From 77432087c3376b1f31e2af4979b1cb4be4a5570a Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Fri, 19 Jul 2024 09:38:15 +0200 Subject: [PATCH 001/203] Initial project setup --- ldk-server/.github/workflows/build.yml | 31 ++++++++++++++++++++++++++ ldk-server/.gitignore | 1 + ldk-server/Cargo.toml | 11 +++++++++ ldk-server/cli/Cargo.toml | 6 +++++ ldk-server/cli/src/main.rs | 3 +++ ldk-server/client/Cargo.toml | 6 +++++ ldk-server/client/src/lib.rs | 14 ++++++++++++ ldk-server/rustfmt.toml | 12 ++++++++++ ldk-server/server/Cargo.toml | 6 +++++ ldk-server/server/src/main.rs | 3 +++ 10 files changed, 93 insertions(+) create mode 100644 ldk-server/.github/workflows/build.yml create mode 100644 ldk-server/.gitignore create mode 100644 ldk-server/Cargo.toml create mode 100644 ldk-server/cli/Cargo.toml create mode 100644 ldk-server/cli/src/main.rs create mode 100644 ldk-server/client/Cargo.toml create mode 100644 ldk-server/client/src/lib.rs create mode 100644 ldk-server/rustfmt.toml create mode 100644 ldk-server/server/Cargo.toml create mode 100644 ldk-server/server/src/main.rs diff --git a/ldk-server/.github/workflows/build.yml b/ldk-server/.github/workflows/build.yml new file mode 100644 index 000000000..b54fe758d --- /dev/null +++ b/ldk-server/.github/workflows/build.yml @@ -0,0 +1,31 @@ +name: Continuous Integration Checks + +on: [ push, pull_request ] + +jobs: + build: + strategy: + matrix: + toolchain: [ stable ] + include: + - toolchain: stable + check-fmt: true + runs-on: ubuntu-latest + steps: + - name: Checkout source code + uses: actions/checkout@v3 + - name: Install Rust ${{ matrix.toolchain }} toolchain + run: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ matrix.toolchain }} + rustup override set ${{ matrix.toolchain }} + - name: Build on Rust ${{ matrix.toolchain }} + run: cargo build --verbose --color always + - name: Check formatting + if: matrix.check-fmt + run: rustup component add rustfmt && cargo fmt --all -- --check + - name: Test on Rust ${{ matrix.toolchain }} + run: cargo test + - name: Cargo check release on Rust ${{ matrix.toolchain }} + run: cargo check --release + - name: Cargo check doc on Rust ${{ matrix.toolchain }} + run: cargo doc --release diff --git a/ldk-server/.gitignore b/ldk-server/.gitignore new file mode 100644 index 000000000..ea8c4bf7f --- /dev/null +++ b/ldk-server/.gitignore @@ -0,0 +1 @@ +/target diff --git a/ldk-server/Cargo.toml b/ldk-server/Cargo.toml new file mode 100644 index 000000000..9f0592700 --- /dev/null +++ b/ldk-server/Cargo.toml @@ -0,0 +1,11 @@ +[workspace] +resolver = "2" +members = [ "cli", "client", "server"] + +[profile.release] +panic = "abort" +opt-level = 3 +lto = true + +[profile.dev] +panic = "abort" diff --git a/ldk-server/cli/Cargo.toml b/ldk-server/cli/Cargo.toml new file mode 100644 index 000000000..c1fb0b03c --- /dev/null +++ b/ldk-server/cli/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "cli" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/ldk-server/cli/src/main.rs b/ldk-server/cli/src/main.rs new file mode 100644 index 000000000..a30eb952c --- /dev/null +++ b/ldk-server/cli/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/ldk-server/client/Cargo.toml b/ldk-server/client/Cargo.toml new file mode 100644 index 000000000..87c805118 --- /dev/null +++ b/ldk-server/client/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "client" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/ldk-server/client/src/lib.rs b/ldk-server/client/src/lib.rs new file mode 100644 index 000000000..06d268d0c --- /dev/null +++ b/ldk-server/client/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/ldk-server/rustfmt.toml b/ldk-server/rustfmt.toml new file mode 100644 index 000000000..4f88472be --- /dev/null +++ b/ldk-server/rustfmt.toml @@ -0,0 +1,12 @@ +use_small_heuristics = "Max" +fn_params_layout = "Compressed" +hard_tabs = true +use_field_init_shorthand = true +max_width = 100 +match_block_trailing_comma = true +# UNSTABLE: format_code_in_doc_comments = true +# UNSTABLE: overflow_delimited_expr = true +# UNSTABLE: comment_width = 100 +# UNSTABLE: format_macro_matchers = true +# UNSTABLE: format_strings = true +# UNSTABLE: group_imports = "StdExternalCrate" diff --git a/ldk-server/server/Cargo.toml b/ldk-server/server/Cargo.toml new file mode 100644 index 000000000..6ae692962 --- /dev/null +++ b/ldk-server/server/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "ldk-node-server" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/ldk-server/server/src/main.rs b/ldk-server/server/src/main.rs new file mode 100644 index 000000000..a30eb952c --- /dev/null +++ b/ldk-server/server/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From b5bee98ca690a914fd37ffbabf5d542a3a63b30b Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Fri, 19 Jul 2024 10:05:44 +0200 Subject: [PATCH 002/203] Add initial service building blocks --- ldk-server/Cargo.lock | 2040 ++++++++++++++++++++++++++++++ ldk-server/server/Cargo.toml | 8 + ldk-server/server/src/main.rs | 156 ++- ldk-server/server/src/service.rs | 74 ++ 4 files changed, 2277 insertions(+), 1 deletion(-) create mode 100644 ldk-server/Cargo.lock create mode 100644 ldk-server/server/src/service.rs diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock new file mode 100644 index 000000000..680caae2c --- /dev/null +++ b/ldk-server/Cargo.lock @@ -0,0 +1,2040 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[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 = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "bdk" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc1fc1a92e0943bfbcd6eb7d32c1b2a79f2f1357eb1e2eee9d7f36d6d7ca44a" +dependencies = [ + "ahash 0.7.8", + "async-trait", + "bdk-macros", + "bip39", + "bitcoin", + "esplora-client", + "futures", + "getrandom", + "js-sys", + "log", + "miniscript", + "rand", + "rusqlite", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "bdk-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81c1980e50ae23bb6efa9283ae8679d6ea2c6fa6a99fe62533f65f4a25a1a56c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bip21" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9532c632b068e45a478f5e309126b6e2ec1dbf0bbd327b73836f33d9a43ede" +dependencies = [ + "bitcoin", + "percent-encoding-rfc3986", +] + +[[package]] +name = "bip39" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" +dependencies = [ + "bitcoin_hashes 0.11.0", + "serde", + "unicode-normalization", +] + +[[package]] +name = "bitcoin" +version = "0.30.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1945a5048598e4189e239d3f809b19bdad4845c4b2ba400d304d2dcf26d2c462" +dependencies = [ + "base64 0.13.1", + "bech32", + "bitcoin-private", + "bitcoin_hashes 0.12.0", + "hex_lit", + "secp256k1", + "serde", +] + +[[package]] +name = "bitcoin-internals" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f9997f8650dd818369931b5672a18dbef95324d0513aa99aae758de8ce86e5b" + +[[package]] +name = "bitcoin-private" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" + +[[package]] +name = "bitcoin_hashes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" + +[[package]] +name = "bitcoin_hashes" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" +dependencies = [ + "bitcoin-private", + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytes" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" + +[[package]] +name = "cc" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.6", +] + +[[package]] +name = "cli" +version = "0.1.0" + +[[package]] +name = "client" +version = "0.1.0" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "esplora-client" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cb1f7f2489cce83bc3bd92784f9ba5271eeb6e729b975895fc541f78cbfcdca" +dependencies = [ + "bitcoin", + "bitcoin-internals", + "log", + "reqwest", + "serde", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[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.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex-conservative" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" + +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.30", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "hyper-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "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 = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[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.3.0" +source = "git+https://github.com/lightningdevkit/ldk-node.git?branch=main#77a0bbede4f063ee50ca2aa36fb019e79d3f8707" +dependencies = [ + "bdk", + "bip21", + "bip39", + "bitcoin", + "chrono", + "esplora-client", + "libc", + "lightning", + "lightning-background-processor", + "lightning-invoice", + "lightning-liquidity", + "lightning-net-tokio", + "lightning-persister", + "lightning-rapid-gossip-sync", + "lightning-transaction-sync", + "prost 0.11.9", + "rand", + "reqwest", + "rusqlite", + "tokio", + "vss-client", + "winapi", +] + +[[package]] +name = "ldk-node-server" +version = "0.1.0" +dependencies = [ + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "ldk-node", + "prost 0.12.6", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libsqlite3-sys" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "lightning" +version = "0.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd92d4aa159374be430c7590e169b4a6c0fb79018f5bc4ea1bffde536384db3" +dependencies = [ + "bitcoin", + "hex-conservative", +] + +[[package]] +name = "lightning-background-processor" +version = "0.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb1c2c64050e37cee7c3b6b022106523784055ac3ee572d360780a1d6fe8062c" +dependencies = [ + "bitcoin", + "lightning", + "lightning-rapid-gossip-sync", +] + +[[package]] +name = "lightning-invoice" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d07d01cf197bf2184b929b7dc94aa70d935aac6df896c256a3a9475b7e9d40" +dependencies = [ + "bech32", + "bitcoin", + "lightning", + "secp256k1", + "serde", +] + +[[package]] +name = "lightning-liquidity" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fa6284740f64672f42145de7b0a242beea3821dae1f0eac7949a8f48799c828" +dependencies = [ + "bitcoin", + "chrono", + "lightning", + "lightning-invoice", + "serde", + "serde_json", +] + +[[package]] +name = "lightning-net-tokio" +version = "0.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9e6a4d49c50a1344916d080dc8c012ce3a778cdd45de8def75350b2b40fe018" +dependencies = [ + "bitcoin", + "lightning", + "tokio", +] + +[[package]] +name = "lightning-persister" +version = "0.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a8dd33971815fa074b05678e09a6d4b15c78225ea34d66ed4f17c35a53467a9" +dependencies = [ + "bitcoin", + "lightning", + "windows-sys 0.48.0", +] + +[[package]] +name = "lightning-rapid-gossip-sync" +version = "0.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d861b0f0cd5f8fe8c63760023c4fd4fd32c384881b41780b62ced2a8a619f91" +dependencies = [ + "bitcoin", + "lightning", +] + +[[package]] +name = "lightning-transaction-sync" +version = "0.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c1e88eece28f19b5834fb5aefceabc5d143cfda2dfa9a32f73e66f4d0c84ed" +dependencies = [ + "bdk-macros", + "bitcoin", + "esplora-client", + "futures", + "lightning", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniscript" +version = "10.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70545cd04bd4eaf5689918aa8a9b155ecb29d8542d82537968cf9ce9e22460a3" +dependencies = [ + "bitcoin", + "bitcoin-private", + "serde", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "percent-encoding" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive 0.11.9", +] + +[[package]] +name = "prost" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +dependencies = [ + "bytes", + "prost-derive 0.12.6", +] + +[[package]] +name = "prost-build" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +dependencies = [ + "bytes", + "heck", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost 0.11.9", + "prost-types", + "regex", + "syn 1.0.109", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-derive" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.71", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost 0.11.9", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-rustls", + "tokio-socks", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rusqlite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" +dependencies = [ + "bitflags 1.3.2", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "bitcoin_hashes 0.12.0", + "rand", + "secp256k1-sys", + "serde", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + +[[package]] +name = "serde_json" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +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.38.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-socks" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" +dependencies = [ + "either", + "futures-util", + "thiserror", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vss-client" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62cbd331368125aeb93b67dd4a80826a4ee29a810d4c76d2c9d265c1522a3f2" +dependencies = [ + "prost 0.11.9", + "prost-build", + "rand", + "reqwest", + "tokio", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.71", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] diff --git a/ldk-server/server/Cargo.toml b/ldk-server/server/Cargo.toml index 6ae692962..0289f4ec5 100644 --- a/ldk-server/server/Cargo.toml +++ b/ldk-server/server/Cargo.toml @@ -4,3 +4,11 @@ version = "0.1.0" edition = "2021" [dependencies] +ldk-node = { git = "https://github.com/lightningdevkit/ldk-node.git", branch = "main" } +serde = { version = "1.0.203", default-features = false, features = ["derive"] } +serde_json = { version = "1.0.118", default-features = false } +hyper = { version = "1", default-features = false, features = ["server", "http1"] } +http-body-util = { version = "0.1", default-features = false } +hyper-util = { version = "0.1", default-features = false, features = ["server-graceful"] } +tokio = { version = "1.38.0", default-features = false, features = ["time", "signal", "rt-multi-thread"] } +prost = { version = "0.12.3", default-features = false, features = ["derive", "std"] } diff --git a/ldk-server/server/src/main.rs b/ldk-server/server/src/main.rs index a30eb952c..b440903b0 100644 --- a/ldk-server/server/src/main.rs +++ b/ldk-server/server/src/main.rs @@ -1,3 +1,157 @@ +mod service; + +use crate::service::NodeService; + +use ldk_node::bitcoin::Network; +use ldk_node::lightning::ln::msgs::SocketAddress; +use ldk_node::{Builder, Config, Event, LogLevel}; + +use tokio::net::TcpListener; +use tokio::signal::unix::SignalKind; + +use hyper::server::conn::http1; +use hyper_util::rt::TokioIo; + +use std::net::SocketAddr; +use std::str::FromStr; +use std::sync::Arc; + fn main() { - println!("Hello, world!"); + let args: Vec = std::env::args().collect(); + + if args.len() < 6 { + eprintln!( + "Usage: {} storage_path listening_addr rest_svc_addr network esplora_server_url", + args[0] + ); + std::process::exit(-1); + } + + let mut config = Config::default(); + config.storage_dir_path = args[1].clone(); + config.log_level = LogLevel::Trace; + + config.listening_addresses = match SocketAddress::from_str(&args[2]) { + Ok(addr) => Some(vec![addr]), + Err(_) => { + eprintln!("Failed to parse listening_addr: {}", args[2]); + std::process::exit(-1); + }, + }; + + let rest_svc_addr = match SocketAddr::from_str(&args[3]) { + Ok(addr) => addr, + Err(_) => { + eprintln!("Failed to parse rest_svc_addr: {}", args[3]); + std::process::exit(-1); + }, + }; + + config.network = match Network::from_str(&args[4]) { + Ok(network) => network, + Err(_) => { + eprintln!("Unsupported network: {}. Use 'bitcoin', 'testnet', 'regtest', 'signet', 'regtest'.", args[4]); + std::process::exit(-1); + }, + }; + + let mut builder = Builder::from_config(config); + builder.set_esplora_server(args[5].clone()); + + let runtime = match tokio::runtime::Builder::new_multi_thread().enable_all().build() { + Ok(runtime) => Arc::new(runtime), + Err(e) => { + eprintln!("Failed to setup tokio runtime: {}", e); + std::process::exit(-1); + }, + }; + + let node = match builder.build() { + Ok(node) => Arc::new(node), + Err(e) => { + eprintln!("Failed to build LDK Node: {}", e); + std::process::exit(-1); + }, + }; + + println!("Starting up..."); + match node.start_with_runtime(Arc::clone(&runtime)) { + Ok(()) => {}, + Err(e) => { + eprintln!("Failed to start up LDK Node: {}", e); + std::process::exit(-1); + }, + } + + println!( + "CONNECTION_STRING: {}@{}", + node.node_id(), + node.config().listening_addresses.as_ref().unwrap().first().unwrap() + ); + + runtime.block_on(async { + let mut sigterm_stream = match tokio::signal::unix::signal(SignalKind::terminate()) { + Ok(stream) => stream, + Err(e) => { + println!("Failed to register for SIGTERM stream: {}", e); + std::process::exit(-1); + }, + }; + let event_node = Arc::clone(&node); + let rest_svc_listener = + TcpListener::bind(rest_svc_addr).await.expect("Failed to bind listening port"); + loop { + tokio::select! { + event = event_node.next_event_async() => { + match event { + Event::ChannelPending { channel_id, counterparty_node_id, .. } => { + println!( + "CHANNEL_PENDING: {} from counterparty {}", + channel_id, counterparty_node_id + ); + }, + Event::ChannelReady { channel_id, counterparty_node_id, .. } => { + println!( + "CHANNEL_READY: {} from counterparty {:?}", + channel_id, counterparty_node_id + ); + }, + Event::PaymentReceived { payment_id, payment_hash, amount_msat } => { + println!( + "PAYMENT_RECEIVED: with id {:?}, hash {}, amount_msat {}", + payment_id, payment_hash, amount_msat + ); + }, + _ => {}, + } + event_node.event_handled(); + }, + res = rest_svc_listener.accept() => { + match res { + Ok((stream, _)) => { + let io_stream = TokioIo::new(stream); + let node_service = NodeService::new(Arc::clone(&node)); + runtime.spawn(async move { + if let Err(err) = http1::Builder::new().serve_connection(io_stream, node_service).await { + eprintln!("Failed to serve connection: {}", err); + } + }); + }, + Err(e) => eprintln!("Failed to accept connection: {}", e), + } + } + _ = tokio::signal::ctrl_c() => { + println!("Received CTRL-C, shutting down.."); + break; + } + _ = sigterm_stream.recv() => { + println!("Received SIGTERM, shutting down.."); + break; + } + } + } + }); + + node.stop().expect("Shutdown should always succeed."); + println!("Shutdown complete.."); } diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs new file mode 100644 index 000000000..606dfd108 --- /dev/null +++ b/ldk-server/server/src/service.rs @@ -0,0 +1,74 @@ +use ldk_node::Node; + +use http_body_util::{BodyExt, Full}; +use hyper::body::{Bytes, Incoming}; +use hyper::service::Service; +use hyper::{Request, Response, StatusCode}; + +use prost::Message; + +use std::future::Future; +use std::pin::Pin; +use std::sync::Arc; + +#[derive(Clone)] +pub struct NodeService { + node: Arc, +} + +impl NodeService { + pub(crate) fn new(node: Arc) -> Self { + Self { node } + } +} + +impl Service> for NodeService { + type Response = Response>; + type Error = hyper::Error; + type Future = Pin> + Send>>; + + fn call(&self, req: Request) -> Self::Future { + let _node = Arc::clone(&self.node); + match req.uri().path() { + path => { + let error = format!("Unknown request: {}", path).into_bytes(); + Box::pin(async { + Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Full::new(Bytes::from(error))) + // unwrap safety: body only errors when previous chained calls failed. + .unwrap()) + }) + }, + } + } +} + +async fn handle_request< + T: Message + Default, + R: Message, + F: Fn(Arc, T) -> Result, +>( + node: Arc, request: Request, handler: F, +) -> Result<>>::Response, hyper::Error> { + // TODO: we should bound the amount of data we read to avoid allocating too much memory. + let bytes = request.into_body().collect().await?.to_bytes(); + match T::decode(bytes) { + Ok(request) => match handler(node, request) { + Ok(response) => Ok(Response::builder() + .body(Full::new(Bytes::from(response.encode_to_vec()))) + // unwrap safety: body only errors when previous chained calls failed. + .unwrap()), + Err(e) => Ok(Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(Full::new(Bytes::from(e.to_string().into_bytes()))) + // unwrap safety: body only errors when previous chained calls failed. + .unwrap()), + }, + Err(_) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(Full::new(Bytes::from(b"Error parsing request".to_vec()))) + // unwrap safety: body only errors when previous chained calls failed. + .unwrap()), + } +} From f1d853e914081d7689ec5cf176961acb5429b3e2 Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Thu, 22 Aug 2024 08:00:18 +0200 Subject: [PATCH 003/203] Add MSRV 1.63.0 to Github CI --- ldk-server/.github/workflows/build.yml | 25 +++++++-- ldk-server/Cargo.lock | 78 +++++++++----------------- ldk-server/server/Cargo.toml | 2 +- 3 files changed, 49 insertions(+), 56 deletions(-) diff --git a/ldk-server/.github/workflows/build.yml b/ldk-server/.github/workflows/build.yml index b54fe758d..3c39bdb3b 100644 --- a/ldk-server/.github/workflows/build.yml +++ b/ldk-server/.github/workflows/build.yml @@ -6,11 +6,21 @@ jobs: build: strategy: matrix: - toolchain: [ stable ] + platform: [ + ubuntu-latest, + macos-latest, + ] + toolchain: + [ stable, + beta, + 1.63.0, # MSRV + ] include: - toolchain: stable check-fmt: true - runs-on: ubuntu-latest + - toolchain: 1.63.0 + msrv: true + runs-on: ${{ matrix.platform }} steps: - name: Checkout source code uses: actions/checkout@v3 @@ -18,11 +28,18 @@ jobs: run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ matrix.toolchain }} rustup override set ${{ matrix.toolchain }} - - name: Build on Rust ${{ matrix.toolchain }} - run: cargo build --verbose --color always - name: Check formatting if: matrix.check-fmt run: rustup component add rustfmt && cargo fmt --all -- --check + - name: Pin packages to allow for MSRV + if: matrix.msrv + run: | + cargo update -p hashlink --precise "0.8.2" --verbose # hashlink 0.8.3 requires hashbrown 0.14, requiring 1.64.0 + cargo update -p regex --precise "1.9.6" --verbose # regex 1.10.0 requires rustc 1.65.0 + cargo update -p home --precise "0.5.5" --verbose # home v0.5.9 requires rustc 1.70 or newer + cargo update -p tokio --precise "1.38.1" --verbose # tokio v1.39.0 requires rustc 1.70 or newer + - name: Build on Rust ${{ matrix.toolchain }} + run: cargo build --verbose --color always - name: Test on Rust ${{ matrix.toolchain }} run: cargo test - name: Cargo check release on Rust ${{ matrix.toolchain }} diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 680caae2c..6bd52c403 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -49,12 +49,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "allocator-api2" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" - [[package]] name = "android-tzdata" version = "0.1.1" @@ -508,21 +502,26 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ "ahash 0.8.11", - "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hashlink" -version = "0.8.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "0761a1b9491c4f2e3d66aa0f62d0fba0af9a0e2852e4d48ea506632a4b56e6aa" dependencies = [ - "hashbrown", + "hashbrown 0.13.2", ] [[package]] @@ -551,11 +550,11 @@ checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" [[package]] name = "home" -version = "0.5.9" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.48.0", ] [[package]] @@ -738,7 +737,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.5", ] [[package]] @@ -797,7 +796,7 @@ dependencies = [ "lightning-persister", "lightning-rapid-gossip-sync", "lightning-transaction-sync", - "prost 0.11.9", + "prost", "rand", "reqwest", "rusqlite", @@ -814,7 +813,7 @@ dependencies = [ "hyper 1.4.1", "hyper-util", "ldk-node", - "prost 0.12.6", + "prost", "serde", "serde_json", "tokio", @@ -1097,17 +1096,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", - "prost-derive 0.11.9", -] - -[[package]] -name = "prost" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" -dependencies = [ - "bytes", - "prost-derive 0.12.6", + "prost-derive", ] [[package]] @@ -1124,7 +1113,7 @@ dependencies = [ "multimap", "petgraph", "prettyplease", - "prost 0.11.9", + "prost", "prost-types", "regex", "syn 1.0.109", @@ -1145,26 +1134,13 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "prost-derive" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 2.0.71", -] - [[package]] name = "prost-types" version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" dependencies = [ - "prost 0.11.9", + "prost", ] [[package]] @@ -1208,9 +1184,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" dependencies = [ "aho-corasick", "memchr", @@ -1220,9 +1196,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" dependencies = [ "aho-corasick", "memchr", @@ -1231,9 +1207,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "reqwest" @@ -1723,7 +1699,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a62cbd331368125aeb93b67dd4a80826a4ee29a810d4c76d2c9d265c1522a3f2" dependencies = [ - "prost 0.11.9", + "prost", "prost-build", "rand", "reqwest", diff --git a/ldk-server/server/Cargo.toml b/ldk-server/server/Cargo.toml index 0289f4ec5..2a9d7e9e5 100644 --- a/ldk-server/server/Cargo.toml +++ b/ldk-server/server/Cargo.toml @@ -11,4 +11,4 @@ hyper = { version = "1", default-features = false, features = ["server", "http1" http-body-util = { version = "0.1", default-features = false } hyper-util = { version = "0.1", default-features = false, features = ["server-graceful"] } tokio = { version = "1.38.0", default-features = false, features = ["time", "signal", "rt-multi-thread"] } -prost = { version = "0.12.3", default-features = false, features = ["derive", "std"] } +prost = { version = "0.11.6", default-features = false, features = ["std"] } From 469f41bf67714dd19d5f7d1cc427977d9b233479 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 20 Aug 2024 17:07:15 -0700 Subject: [PATCH 004/203] Add proto object generation setup --- ldk-server/Cargo.lock | 9 +++++++++ ldk-server/Cargo.toml | 2 +- ldk-server/protos/Cargo.toml | 12 +++++++++++ ldk-server/protos/build.rs | 20 +++++++++++++++++++ ldk-server/protos/src/lib.rs | 3 +++ .../protos/src/proto/ldk_node_server.proto | 6 ++++++ ldk-server/server/Cargo.toml | 1 + 7 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 ldk-server/protos/Cargo.toml create mode 100644 ldk-server/protos/build.rs create mode 100644 ldk-server/protos/src/lib.rs create mode 100644 ldk-server/protos/src/proto/ldk_node_server.proto diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 6bd52c403..847f68a79 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -814,6 +814,7 @@ dependencies = [ "hyper-util", "ldk-node", "prost", + "protos", "serde", "serde_json", "tokio", @@ -1143,6 +1144,14 @@ dependencies = [ "prost", ] +[[package]] +name = "protos" +version = "0.1.0" +dependencies = [ + "prost", + "prost-build", +] + [[package]] name = "quote" version = "1.0.36" diff --git a/ldk-server/Cargo.toml b/ldk-server/Cargo.toml index 9f0592700..61b420c9b 100644 --- a/ldk-server/Cargo.toml +++ b/ldk-server/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = [ "cli", "client", "server"] +members = [ "cli", "client", "protos", "server"] [profile.release] panic = "abort" diff --git a/ldk-server/protos/Cargo.toml b/ldk-server/protos/Cargo.toml new file mode 100644 index 000000000..7a69b66a6 --- /dev/null +++ b/ldk-server/protos/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "protos" +version = "0.1.0" +edition = "2021" + +build = "build.rs" + +[dependencies] +prost = { version = "0.11.6", default-features = false, features = ["std", "prost-derive"] } + +[target.'cfg(genproto)'.build-dependencies] +prost-build = { version = "0.11.6" , default-features = false} diff --git a/ldk-server/protos/build.rs b/ldk-server/protos/build.rs new file mode 100644 index 000000000..b65f50d87 --- /dev/null +++ b/ldk-server/protos/build.rs @@ -0,0 +1,20 @@ +#[cfg(genproto)] +extern crate prost_build; + +#[cfg(genproto)] +use std::{env, fs, path::Path}; + +/// To generate updated proto objects, run `RUSTFLAGS="--cfg genproto" cargo build` +fn main() { + #[cfg(genproto)] + generate_protos(); +} + +#[cfg(genproto)] +fn generate_protos() { + prost_build::compile_protos(&["src/proto/ldk_node_server.proto"], &["src/"]) + .expect("protobuf compilation failed"); + println!("sss {}", &env::var("OUT_DIR").unwrap()); + let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("ldk_node_server.rs"); + fs::copy(from_path, "src/lib.rs").unwrap(); +} diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/protos/src/lib.rs new file mode 100644 index 000000000..c8391a984 --- /dev/null +++ b/ldk-server/protos/src/lib.rs @@ -0,0 +1,3 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DummyRequest {} diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto new file mode 100644 index 000000000..db2c0db02 --- /dev/null +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -0,0 +1,6 @@ +syntax = "proto3"; +package ldk_node_server; + +message DummyRequest { + +} diff --git a/ldk-server/server/Cargo.toml b/ldk-server/server/Cargo.toml index 2a9d7e9e5..82fd98011 100644 --- a/ldk-server/server/Cargo.toml +++ b/ldk-server/server/Cargo.toml @@ -12,3 +12,4 @@ http-body-util = { version = "0.1", default-features = false } hyper-util = { version = "0.1", default-features = false, features = ["server-graceful"] } tokio = { version = "1.38.0", default-features = false, features = ["time", "signal", "rt-multi-thread"] } prost = { version = "0.11.6", default-features = false, features = ["std"] } +protos = { path = "../protos" } From 66eee39a9c943818e04bc3f84ae9663f61dcae7e Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 20 Aug 2024 20:31:39 -0700 Subject: [PATCH 005/203] Add proto for OnchainReceive --- ldk-server/protos/src/proto/ldk_node_server.proto | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index db2c0db02..041ff1e6b 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -1,6 +1,13 @@ syntax = "proto3"; package ldk_node_server; -message DummyRequest { +// Retrieve a new on-chain funding address. +// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.new_address +message OnchainReceiveRequest { +} + +message OnchainReceiveResponse { + // A Bitcoin on-chain address. + string address = 1; } From 0cd5b37bf89a772a4f7a7f903411653ace56d6a7 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 20 Aug 2024 20:40:38 -0700 Subject: [PATCH 006/203] Add proto for OnchainSend --- .../protos/src/proto/ldk_node_server.proto | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index 041ff1e6b..08a22e507 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -11,3 +11,31 @@ message OnchainReceiveResponse { // A Bitcoin on-chain address. string address = 1; } + +// Send an on-chain payment to the given address. +message OnchainSendRequest { + + // The address to send coins to. + string address = 1; + + // The amount in satoshis to send. + // While sending the specified amount, we will respect any on-chain reserve we need to keep, + // i.e., won't allow to cut into `total_anchor_channels_reserve_sats`. + // See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.send_to_address + optional uint64 amount_sats = 2; + + // If set, the amount_sats field should be unset. + // It indicates that node will send full balance to the specified address. + // + // Please note that when send_all is used this operation will **not** retain any on-chain reserves, + // which might be potentially dangerous if you have open Anchor channels for which you can't trust + // the counterparty to spend the Anchor output after channel closure. + // See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.send_all_to_address + optional bool send_all = 3; +} + +message OnchainSendResponse { + + // The transaction ID of the broadcasted transaction. + string txid = 1; +} From e17e97e3786a4a995e7d1bfc8462c156fa203055 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 20 Aug 2024 20:54:15 -0700 Subject: [PATCH 007/203] Add proto for Bolt11ReceiveRequest --- .../protos/src/proto/ldk_node_server.proto | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index 08a22e507..16b323d0a 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -39,3 +39,31 @@ message OnchainSendResponse { // The transaction ID of the broadcasted transaction. string txid = 1; } + +// Return a BOLT11 payable invoice that can be used to request and receive a payment +// for the given amount, if specified. +// The inbound payment will be automatically claimed upon arrival. +// See more: +// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.receive +// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.receive_variable_amount +message Bolt11ReceiveRequest { + + // The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount invoice is returned. + optional uint64 amount_msat = 1; + + // An optional description to attach along with the invoice. + // Will be set in the description field of the encoded payment request. + string description = 2; + + // Invoice expiry time in seconds. + uint32 expiry_secs = 3; +} + + +message Bolt11ReceiveResponse { + + // An invoice for a payment within the Lightning Network. + // With the details of the invoice, the sender has all the data necessary to send a payment + // to the recipient. + string invoice = 1; +} From 1ade1d421f4594c84ff717832f8b0c406e80f2a1 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 20 Aug 2024 22:50:36 -0700 Subject: [PATCH 008/203] Add proto for Bolt11Send Api --- .../protos/src/proto/ldk_node_server.proto | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index 16b323d0a..174845b7e 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -67,3 +67,29 @@ message Bolt11ReceiveResponse { // to the recipient. string invoice = 1; } + +// Send a payment for a BOLT11 invoice. +// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.send +message Bolt11SendRequest { + + // An invoice for a payment within the Lightning Network. + string invoice = 1; + + // Set this field when paying a so-called "zero-amount" invoice, i.e., an invoice that leaves the + // amount paid to be determined by the user. + // This operation will fail if the amount specified is less than the value required by the given invoice. + optional uint64 amount_msat = 2; + +} + +message Bolt11SendResponse { + + // An identifier used to uniquely identify a payment. + PaymentId payment_id = 1; +} + +// An identifier used to uniquely identify a payment. +message PaymentId { + + bytes data = 1; +} From 06493cda8cf030f1152d1974b59feec9b342e356 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 20 Aug 2024 22:55:44 -0700 Subject: [PATCH 009/203] Add proto for Bolt12Receive --- .../protos/src/proto/ldk_node_server.proto | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index 174845b7e..fafe8652a 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -93,3 +93,26 @@ message PaymentId { bytes data = 1; } + +// Returns a BOLT12 offer for the given amount, if specified. +// +// See more: +// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.receive +// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.receive_variable_amount +message Bolt12ReceiveRequest { + + // An optional description to attach along with the offer. + // Will be set in the description field of the encoded offer. + string description = 1; + + // The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount offer is returned. + optional uint64 amount_msat = 2; +} + +message Bolt12ReceiveResponse { + + // An offer for a payment within the Lightning Network. + // With the details of the offer, the sender has all the data necessary to send a payment + // to the recipient. + string offer = 1; +} From aa99ca858005389c52c8a39cdea8de03796ef2f9 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 20 Aug 2024 23:02:17 -0700 Subject: [PATCH 010/203] Add proto for Bolt12Send --- .../protos/src/proto/ldk_node_server.proto | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index fafe8652a..210522d3c 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -116,3 +116,30 @@ message Bolt12ReceiveResponse { // to the recipient. string offer = 1; } + +// Send a payment for a BOLT12 offer. +// See more: +// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.send +// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.send_using_amount +message Bolt12SendRequest { + + // An offer for a payment within the Lightning Network. + string offer = 1; + + // Set this field when paying a so-called "zero-amount" offer, i.e., an offer that leaves the + // amount paid to be determined by the user. + // This operation will fail if the amount specified is less than the value required by the given offer. + optional uint64 amount_msat = 2; + + // If set, it represents the number of items requested. + optional uint64 quantity = 3; + + // If set, it will be seen by the recipient and reflected back in the invoice. + optional string payer_note = 4; +} + +message Bolt12SendResponse { + + // An identifier used to uniquely identify a payment. + PaymentId payment_id = 1; +} From 0df5ffe033834b6cb47a796665d19f70814d1a06 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:56:34 -0700 Subject: [PATCH 011/203] Add proto for OpenChannel --- .../protos/src/proto/ldk_node_server.proto | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index 210522d3c..f59698cd1 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -143,3 +143,30 @@ message Bolt12SendResponse { // An identifier used to uniquely identify a payment. PaymentId payment_id = 1; } + +// Creates a new outbound channel to the given remote node. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.connect_open_channel +message OpenChannelRequest { + + // The hex-encoded public key of the node to open a channel with. + string node_pubkey = 1; + + // 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 + string address = 2; + + // The amount of satoshis the caller is willing to commit to the channel. + uint64 channel_amount_sats = 3; + + // The amount of satoshis to push to the remote side as part of the initial commitment state. + optional uint64 push_to_counterparty_msat = 4; + + // Whether the channel should be public. + bool announce_channel = 5; +} + +message OpenChannelResponse { + + // The channel id of the created channel that user can use to refer to channel. + bytes user_channel_id = 1; +} From 004589f4d28de85e69d32220191c6449063fb98f Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 21 Aug 2024 15:57:14 -0700 Subject: [PATCH 012/203] Allow setting ChannelConfig in OpenChannel --- .../protos/src/proto/ldk_node_server.proto | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index f59698cd1..ce4768125 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -161,8 +161,11 @@ message OpenChannelRequest { // The amount of satoshis to push to the remote side as part of the initial commitment state. optional uint64 push_to_counterparty_msat = 4; + // The channel configuration to be used for opening this channel. If unset, default ChannelConfig is used. + optional ChannelConfig channel_config = 5; + // Whether the channel should be public. - bool announce_channel = 5; + bool announce_channel = 6; } message OpenChannelResponse { @@ -170,3 +173,48 @@ message OpenChannelResponse { // The channel id of the created channel that user can use to refer to channel. bytes user_channel_id = 1; } + +// ChannelConfig represents the configuration settings for a channel in a Lightning Network node. +// See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html +message ChannelConfig { + // Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound + // over the channel. + // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.forwarding_fee_proportional_millionths + uint32 forwarding_fee_proportional_millionths = 1; + + // Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, + // in excess of forwarding_fee_proportional_millionths. + // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.forwarding_fee_base_msat + uint32 forwarding_fee_base_msat = 2; + + // The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded + // over the channel this config applies to. + // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.cltv_expiry_delta + uint32 cltv_expiry_delta = 3; + + // The maximum additional fee we’re willing to pay to avoid waiting for the counterparty’s + // to_self_delay to reclaim funds. + // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.force_close_avoidance_max_fee_satoshis + uint64 force_close_avoidance_max_fee_satoshis = 4; + + // If set, allows this channel’s counterparty to skim an additional fee off this node’s + // inbound HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users. + // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.accept_underpaying_htlcs + bool accept_underpaying_htlcs = 5; + + // Limit our total exposure to potential loss to on-chain fees on close, including + // in-flight HTLCs which are burned to fees as they are too small to claim on-chain + // and fees on commitment transaction(s) broadcasted by our counterparty in excess of + // our own fee estimate. + // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.max_dust_htlc_exposure + oneof max_dust_htlc_exposure { + + // This sets a fixed limit on the total dust exposure in millisatoshis. + // See more: https://docs.rs/lightning/latest/lightning/util/config/enum.MaxDustHTLCExposure.html#variant.FixedLimitMsat + uint64 fixed_limit_msat = 6; + + // This sets a multiplier on the ConfirmationTarget::OnChainSweep feerate (in sats/KW) to determine the maximum allowed dust exposure. + // See more: https://docs.rs/lightning/latest/lightning/util/config/enum.MaxDustHTLCExposure.html#variant.FeeRateMultiplier + uint64 fee_rate_multiplier = 7; + } +} From f5d797883b04b790e3c97e83918932e28917da86 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 21 Aug 2024 16:13:10 -0700 Subject: [PATCH 013/203] Add proto for CloseChannel --- .../protos/src/proto/ldk_node_server.proto | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index ce4768125..ea5501eb9 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -218,3 +218,23 @@ message ChannelConfig { uint64 fee_rate_multiplier = 7; } } + +// Closes the channel specified by given request. +// See more: +// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.close_channel +// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.force_close_channel +message CloseChannelRequest { + + // The channel id of the created channel that user can use to refer to channel. + bytes user_channel_id = 1; + + // The hex-encoded public key of the node to close a channel with. + string counterparty_node_id = 2; + + // Whether to force close the specified channel. + optional bool force_close = 3; +} + +message CloseChannelResponse { + +} From 49672556cfa475603e50d8352d523d1db7f7e4b3 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:05:56 -0700 Subject: [PATCH 014/203] Add proto for ListChannels --- .../protos/src/proto/ldk_node_server.proto | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index ea5501eb9..07409d85d 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -238,3 +238,150 @@ message CloseChannelRequest { message CloseChannelResponse { } + +// Returns a list of known channels. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_channels +message ListChannelsRequest {} + +message ListChannelsResponse { + + // List of channels. + repeated Channel channels = 1; +} + +message Channel { + // The channel ID (prior to funding transaction generation, this is a random 32-byte + // identifier, afterwards this is the transaction ID of the funding transaction XOR the + // funding transaction output). + // + // Note that this means this value is *not* persistent - it can change once during the + // lifetime of the channel. + string channel_id = 1; + + // The node ID of our the channel's remote counterparty. + string counterparty_node_id = 2; + + // The channel's funding transaction output, if we've negotiated the funding transaction with + // our counterparty already. + optional OutPoint funding_txo = 3; + + // The local `user_channel_id` of this channel. + bytes user_channel_id = 4; + + // The value, in satoshis, that must always be held as a reserve in the channel for us. This + // value ensures that if we broadcast a revoked state, our counterparty can punish us by + // claiming at least this value on chain. + // + // This value is not included in [`outbound_capacity_msat`] as it can never be spent. + // + // This value will be `None` for outbound channels until the counterparty accepts the channel. + optional uint64 unspendable_punishment_reserve = 5; + + // The value, in satoshis, of this channel as it appears in the funding output. + uint64 channel_value_sats = 6; + + // The currently negotiated fee rate denominated in satoshi per 1000 weight units, + // which is applied to commitment and HTLC transactions. + uint32 feerate_sat_per_1000_weight = 7; + + // The available outbound capacity for sending HTLCs to the remote peer. + // + // The amount does not include any pending HTLCs which are not yet resolved (and, thus, whose + // balance is not available for inclusion in new outbound HTLCs). This further does not include + // any pending outgoing HTLCs which are awaiting some other resolution to be sent. + uint64 outbound_capacity_msat = 8; + + // The available outbound capacity for sending HTLCs to the remote peer. + // + // The amount does not include any pending HTLCs which are not yet resolved + // (and, thus, whose balance is not available for inclusion in new inbound HTLCs). This further + // does not include any pending outgoing HTLCs which are awaiting some other resolution to be + // sent. + uint64 inbound_capacity_msat = 9; + + // The number of required confirmations on the funding transactions before the funding is + // considered "locked". The amount is selected by the channel fundee. + // + // The value will be `None` for outbound channels until the counterparty accepts the channel. + optional uint32 confirmations_required = 10; + + // The current number of confirmations on the funding transaction. + optional uint32 confirmations = 11; + + // Is `true` if the channel was initiated (and therefore funded) by us. + bool is_outbound = 12; + + // Is `true` if both parties have exchanged `channel_ready` messages, and the channel is + // not currently being shut down. Both parties exchange `channel_ready` messages upon + // independently verifying that the required confirmations count provided by + // `confirmations_required` has been reached. + bool is_channel_ready = 13; + + // Is `true` if the channel (a) `channel_ready` messages have been exchanged, (b) the + // peer is connected, and (c) the channel is not currently negotiating shutdown. + // + // This is a strict superset of `is_channel_ready`. + bool is_usable = 14; + + // Is `true` if this channel is (or will be) publicly-announced + bool is_public = 15; + + // Set of configurable parameters set by self that affect channel operation. + ChannelConfig channel_config = 16; + + // The available outbound capacity for sending a single HTLC to the remote peer. This is + // similar to `outbound_capacity_msat` but it may be further restricted by + // the current state and per-HTLC limit(s). This is intended for use when routing, allowing us + // to use a limit as close as possible to the HTLC limit we can currently send. + uint64 next_outbound_htlc_limit_msat = 17; + + // The minimum value for sending a single HTLC to the remote peer. This is the equivalent of + // `next_outbound_htlc_limit_msat` but represents a lower-bound, rather than + // an upper-bound. This is intended for use when routing, allowing us to ensure we pick a + // route which is valid. + uint64 next_outbound_htlc_minimum_msat = 18; + + // The number of blocks (after our commitment transaction confirms) that we will need to wait + // until we can claim our funds after we force-close the channel. During this time our + // counterparty is allowed to punish us if we broadcasted a stale state. If our counterparty + // force-closes the channel and broadcasts a commitment transaction we do not have to wait any + // time to claim our non-HTLC-encumbered funds. + // + // This value will be `None` for outbound channels until the counterparty accepts the channel. + optional uint32 force_close_spend_delay = 19; + + // The smallest value HTLC (in msat) the remote peer will accept, for this channel. + // + // This field is only `None` before we have received either the `OpenChannel` or + // `AcceptChannel` message from the remote peer. + optional uint64 counterparty_outbound_htlc_minimum_msat = 20; + + // The largest value HTLC (in msat) the remote peer currently will accept, for this channel. + optional uint64 counterparty_outbound_htlc_maximum_msat = 21; + + // The value, in satoshis, that must always be held in the channel for our counterparty. This + // value ensures that if our counterparty broadcasts a revoked state, we can punish them by + // claiming at least this value on chain. + // + // This value is not included in `inbound_capacity_msat` as it can never be spent. + optional uint64 counterparty_unspendable_punishment_reserve = 22; + + // Base routing fee in millisatoshis. + optional uint32 counterparty_forwarding_info_fee_base_msat = 23; + + // Proportional fee, in millionths of a satoshi the channel will charge per transferred satoshi. + optional uint32 counterparty_forwarding_info_fee_proportional_millionths = 24; + + // The minimum difference in CLTV expiry between an ingoing HTLC and its outgoing counterpart, + // such that the outgoing HTLC is forwardable to this counterparty. + optional uint32 counterparty_forwarding_info_cltv_expiry_delta = 25; +} + +// Represent a transaction outpoint. +message OutPoint { + // The referenced transaction's txid. + string txid = 1; + + // The index of the referenced output in its transaction's vout. + uint32 vout = 2; +} \ No newline at end of file From 8170b97e1a545a12df50288579a9825c3b120007 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:17:28 -0700 Subject: [PATCH 015/203] Update generated protos --- ldk-server/protos/src/lib.rs | 415 ++++++++++++++++++++++++++++++++++- 1 file changed, 414 insertions(+), 1 deletion(-) diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/protos/src/lib.rs index c8391a984..689db8c96 100644 --- a/ldk-server/protos/src/lib.rs +++ b/ldk-server/protos/src/lib.rs @@ -1,3 +1,416 @@ +/// Retrieve a new on-chain funding address. +/// See more: #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct DummyRequest {} +pub struct OnchainReceiveRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OnchainReceiveResponse { + /// A Bitcoin on-chain address. + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, +} +/// Send an on-chain payment to the given address. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OnchainSendRequest { + /// The address to send coins to. + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, + /// The amount in satoshis to send. + /// While sending the specified amount, we will respect any on-chain reserve we need to keep, + /// i.e., won't allow to cut into `total_anchor_channels_reserve_sats`. + /// See more: + #[prost(uint64, optional, tag = "2")] + pub amount_sats: ::core::option::Option, + /// If set, the amount_sats field should be unset. + /// It indicates that node will send full balance to the specified address. + /// + /// Please note that when send_all is used this operation will **not** retain any on-chain reserves, + /// which might be potentially dangerous if you have open Anchor channels for which you can't trust + /// the counterparty to spend the Anchor output after channel closure. + /// See more: + #[prost(bool, optional, tag = "3")] + pub send_all: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OnchainSendResponse { + /// The transaction ID of the broadcasted transaction. + #[prost(string, tag = "1")] + pub txid: ::prost::alloc::string::String, +} +/// Return a BOLT11 payable invoice that can be used to request and receive a payment +/// for the given amount, if specified. +/// The inbound payment will be automatically claimed upon arrival. +/// See more: +/// - +/// - +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11ReceiveRequest { + /// The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount invoice is returned. + #[prost(uint64, optional, tag = "1")] + pub amount_msat: ::core::option::Option, + /// An optional description to attach along with the invoice. + /// Will be set in the description field of the encoded payment request. + #[prost(string, tag = "2")] + pub description: ::prost::alloc::string::String, + /// Invoice expiry time in seconds. + #[prost(uint32, tag = "3")] + pub expiry_secs: u32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11ReceiveResponse { + /// An invoice for a payment within the Lightning Network. + /// With the details of the invoice, the sender has all the data necessary to send a payment + /// to the recipient. + #[prost(string, tag = "1")] + pub invoice: ::prost::alloc::string::String, +} +/// Send a payment for a BOLT11 invoice. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11SendRequest { + /// An invoice for a payment within the Lightning Network. + #[prost(string, tag = "1")] + pub invoice: ::prost::alloc::string::String, + /// Set this field when paying a so-called "zero-amount" invoice, i.e., an invoice that leaves the + /// amount paid to be determined by the user. + /// This operation will fail if the amount specified is less than the value required by the given invoice. + #[prost(uint64, optional, tag = "2")] + pub amount_msat: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11SendResponse { + /// An identifier used to uniquely identify a payment. + #[prost(message, optional, tag = "1")] + pub payment_id: ::core::option::Option, +} +/// An identifier used to uniquely identify a payment. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PaymentId { + #[prost(bytes = "vec", tag = "1")] + pub data: ::prost::alloc::vec::Vec, +} +/// Returns a BOLT12 offer for the given amount, if specified. +/// +/// See more: +/// - +/// - +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12ReceiveRequest { + /// An optional description to attach along with the offer. + /// Will be set in the description field of the encoded offer. + #[prost(string, tag = "1")] + pub description: ::prost::alloc::string::String, + /// The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount offer is returned. + #[prost(uint64, optional, tag = "2")] + pub amount_msat: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12ReceiveResponse { + /// An offer for a payment within the Lightning Network. + /// With the details of the offer, the sender has all the data necessary to send a payment + /// to the recipient. + #[prost(string, tag = "1")] + pub offer: ::prost::alloc::string::String, +} +/// Send a payment for a BOLT12 offer. +/// See more: +/// - +/// - +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12SendRequest { + /// An offer for a payment within the Lightning Network. + #[prost(string, tag = "1")] + pub offer: ::prost::alloc::string::String, + /// Set this field when paying a so-called "zero-amount" offer, i.e., an offer that leaves the + /// amount paid to be determined by the user. + /// This operation will fail if the amount specified is less than the value required by the given offer. + #[prost(uint64, optional, tag = "2")] + pub amount_msat: ::core::option::Option, + /// If set, it represents the number of items requested. + #[prost(uint64, optional, tag = "3")] + pub quantity: ::core::option::Option, + /// If set, it will be seen by the recipient and reflected back in the invoice. + #[prost(string, optional, tag = "4")] + pub payer_note: ::core::option::Option<::prost::alloc::string::String>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12SendResponse { + /// An identifier used to uniquely identify a payment. + #[prost(message, optional, tag = "1")] + pub payment_id: ::core::option::Option, +} +/// Creates a new outbound channel to the given remote node. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OpenChannelRequest { + /// The hex-encoded public key of the node to open a channel with. + #[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, + /// The amount of satoshis the caller is willing to commit to the channel. + #[prost(uint64, tag = "3")] + pub channel_amount_sats: u64, + /// The amount of satoshis to push to the remote side as part of the initial commitment state. + #[prost(uint64, optional, tag = "4")] + pub push_to_counterparty_msat: ::core::option::Option, + /// The channel configuration to be used for opening this channel. If unset, default ChannelConfig is used. + #[prost(message, optional, tag = "5")] + pub channel_config: ::core::option::Option, + /// Whether the channel should be public. + #[prost(bool, tag = "6")] + pub announce_channel: bool, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OpenChannelResponse { + /// The channel id of the created channel that user can use to refer to channel. + #[prost(bytes = "vec", tag = "1")] + pub user_channel_id: ::prost::alloc::vec::Vec, +} +/// ChannelConfig represents the configuration settings for a channel in a Lightning Network node. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ChannelConfig { + /// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound + /// over the channel. + /// See more: + #[prost(uint32, tag = "1")] + pub forwarding_fee_proportional_millionths: u32, + /// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, + /// in excess of forwarding_fee_proportional_millionths. + /// See more: + #[prost(uint32, tag = "2")] + pub forwarding_fee_base_msat: u32, + /// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded + /// over the channel this config applies to. + /// See more: + #[prost(uint32, tag = "3")] + pub cltv_expiry_delta: u32, + /// The maximum additional fee we’re willing to pay to avoid waiting for the counterparty’s + /// to_self_delay to reclaim funds. + /// See more: + #[prost(uint64, tag = "4")] + pub force_close_avoidance_max_fee_satoshis: u64, + /// If set, allows this channel’s counterparty to skim an additional fee off this node’s + /// inbound HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users. + /// See more: + #[prost(bool, tag = "5")] + pub accept_underpaying_htlcs: bool, + /// Limit our total exposure to potential loss to on-chain fees on close, including + /// in-flight HTLCs which are burned to fees as they are too small to claim on-chain + /// and fees on commitment transaction(s) broadcasted by our counterparty in excess of + /// our own fee estimate. + /// See more: + #[prost(oneof = "channel_config::MaxDustHtlcExposure", tags = "6, 7")] + pub max_dust_htlc_exposure: ::core::option::Option, +} +/// Nested message and enum types in `ChannelConfig`. +pub mod channel_config { + /// Limit our total exposure to potential loss to on-chain fees on close, including + /// in-flight HTLCs which are burned to fees as they are too small to claim on-chain + /// and fees on commitment transaction(s) broadcasted by our counterparty in excess of + /// our own fee estimate. + /// See more: + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum MaxDustHtlcExposure { + /// This sets a fixed limit on the total dust exposure in millisatoshis. + /// See more: + #[prost(uint64, tag = "6")] + FixedLimitMsat(u64), + /// This sets a multiplier on the ConfirmationTarget::OnChainSweep feerate (in sats/KW) to determine the maximum allowed dust exposure. + /// See more: + #[prost(uint64, tag = "7")] + FeeRateMultiplier(u64), + } +} +/// Closes the channel specified by given request. +/// See more: +/// - +/// - +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CloseChannelRequest { + /// The channel id of the created channel that user can use to refer to channel. + #[prost(bytes = "vec", tag = "1")] + pub user_channel_id: ::prost::alloc::vec::Vec, + /// The hex-encoded public key of the node to close a channel with. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// Whether to force close the specified channel. + #[prost(bool, tag = "3")] + pub force_close: bool, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CloseChannelResponse {} +/// Returns a list of known channels. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListChannelsRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListChannelsResponse { + /// List of channels. + #[prost(message, repeated, tag = "1")] + pub channels: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Channel { + /// The channel ID (prior to funding transaction generation, this is a random 32-byte + /// identifier, afterwards this is the transaction ID of the funding transaction XOR the + /// funding transaction output). + /// + /// Note that this means this value is *not* persistent - it can change once during the + /// lifetime of the channel. + #[prost(string, tag = "1")] + pub channel_id: ::prost::alloc::string::String, + /// The node ID of our the channel's remote counterparty. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// The channel's funding transaction output, if we've negotiated the funding transaction with + /// our counterparty already. + #[prost(message, optional, tag = "3")] + pub funding_txo: ::core::option::Option, + /// The local `user_channel_id` of this channel. + #[prost(bytes = "vec", tag = "4")] + pub user_channel_id: ::prost::alloc::vec::Vec, + /// The value, in satoshis, that must always be held as a reserve in the channel for us. This + /// value ensures that if we broadcast a revoked state, our counterparty can punish us by + /// claiming at least this value on chain. + /// + /// This value is not included in \[`outbound_capacity_msat`\] as it can never be spent. + /// + /// This value will be `None` for outbound channels until the counterparty accepts the channel. + #[prost(uint64, optional, tag = "5")] + pub unspendable_punishment_reserve: ::core::option::Option, + /// The value, in satoshis, of this channel as it appears in the funding output. + #[prost(uint64, tag = "6")] + pub channel_value_sats: u64, + /// The currently negotiated fee rate denominated in satoshi per 1000 weight units, + /// which is applied to commitment and HTLC transactions. + #[prost(uint32, tag = "7")] + pub feerate_sat_per_1000_weight: u32, + /// The available outbound capacity for sending HTLCs to the remote peer. + /// + /// The amount does not include any pending HTLCs which are not yet resolved (and, thus, whose + /// balance is not available for inclusion in new outbound HTLCs). This further does not include + /// any pending outgoing HTLCs which are awaiting some other resolution to be sent. + #[prost(uint64, tag = "8")] + pub outbound_capacity_msat: u64, + /// The available outbound capacity for sending HTLCs to the remote peer. + /// + /// The amount does not include any pending HTLCs which are not yet resolved + /// (and, thus, whose balance is not available for inclusion in new inbound HTLCs). This further + /// does not include any pending outgoing HTLCs which are awaiting some other resolution to be + /// sent. + #[prost(uint64, tag = "9")] + pub inbound_capacity_msat: u64, + /// The number of required confirmations on the funding transactions before the funding is + /// considered "locked". The amount is selected by the channel fundee. + /// + /// The value will be `None` for outbound channels until the counterparty accepts the channel. + #[prost(uint32, optional, tag = "10")] + pub confirmations_required: ::core::option::Option, + /// The current number of confirmations on the funding transaction. + #[prost(uint32, optional, tag = "11")] + pub confirmations: ::core::option::Option, + /// Is `true` if the channel was initiated (and therefore funded) by us. + #[prost(bool, tag = "12")] + pub is_outbound: bool, + /// Is `true` if both parties have exchanged `channel_ready` messages, and the channel is + /// not currently being shut down. Both parties exchange `channel_ready` messages upon + /// independently verifying that the required confirmations count provided by + /// `confirmations_required` has been reached. + #[prost(bool, tag = "13")] + pub is_channel_ready: bool, + /// Is `true` if the channel (a) `channel_ready` messages have been exchanged, (b) the + /// peer is connected, and (c) the channel is not currently negotiating shutdown. + /// + /// This is a strict superset of `is_channel_ready`. + #[prost(bool, tag = "14")] + pub is_usable: bool, + /// Is `true` if this channel is (or will be) publicly-announced + #[prost(bool, tag = "15")] + pub is_public: bool, + /// Set of configurable parameters set by self that affect channel operation. + #[prost(message, optional, tag = "16")] + pub channel_config: ::core::option::Option, + /// The available outbound capacity for sending a single HTLC to the remote peer. This is + /// similar to `outbound_capacity_msat` but it may be further restricted by + /// the current state and per-HTLC limit(s). This is intended for use when routing, allowing us + /// to use a limit as close as possible to the HTLC limit we can currently send. + #[prost(uint64, tag = "17")] + pub next_outbound_htlc_limit_msat: u64, + /// The minimum value for sending a single HTLC to the remote peer. This is the equivalent of + /// `next_outbound_htlc_limit_msat` but represents a lower-bound, rather than + /// an upper-bound. This is intended for use when routing, allowing us to ensure we pick a + /// route which is valid. + #[prost(uint64, tag = "18")] + pub next_outbound_htlc_minimum_msat: u64, + /// The number of blocks (after our commitment transaction confirms) that we will need to wait + /// until we can claim our funds after we force-close the channel. During this time our + /// counterparty is allowed to punish us if we broadcasted a stale state. If our counterparty + /// force-closes the channel and broadcasts a commitment transaction we do not have to wait any + /// time to claim our non-HTLC-encumbered funds. + /// + /// This value will be `None` for outbound channels until the counterparty accepts the channel. + #[prost(uint32, optional, tag = "19")] + pub force_close_spend_delay: ::core::option::Option, + /// The smallest value HTLC (in msat) the remote peer will accept, for this channel. + /// + /// This field is only `None` before we have received either the `OpenChannel` or + /// `AcceptChannel` message from the remote peer. + #[prost(uint64, optional, tag = "20")] + pub counterparty_outbound_htlc_minimum_msat: ::core::option::Option, + /// The largest value HTLC (in msat) the remote peer currently will accept, for this channel. + #[prost(uint64, optional, tag = "21")] + pub counterparty_outbound_htlc_maximum_msat: ::core::option::Option, + /// The value, in satoshis, that must always be held in the channel for our counterparty. This + /// value ensures that if our counterparty broadcasts a revoked state, we can punish them by + /// claiming at least this value on chain. + /// + /// This value is not included in `inbound_capacity_msat` as it can never be spent. + #[prost(uint64, optional, tag = "22")] + pub counterparty_unspendable_punishment_reserve: ::core::option::Option, + /// Base routing fee in millisatoshis. + #[prost(uint32, optional, tag = "23")] + pub counterparty_forwarding_info_fee_base_msat: ::core::option::Option, + /// Proportional fee, in millionths of a satoshi the channel will charge per transferred satoshi. + #[prost(uint32, optional, tag = "24")] + pub counterparty_forwarding_info_fee_proportional_millionths: ::core::option::Option, + /// The minimum difference in CLTV expiry between an ingoing HTLC and its outgoing counterpart, + /// such that the outgoing HTLC is forwardable to this counterparty. + #[prost(uint32, optional, tag = "25")] + pub counterparty_forwarding_info_cltv_expiry_delta: ::core::option::Option, +} +/// Represent a transaction outpoint. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Outpoint { + /// The referenced transaction's txid. + #[prost(string, tag = "1")] + pub txid: ::prost::alloc::string::String, + /// The index of the referenced output in its transaction's vout. + #[prost(uint32, tag = "2")] + pub vout: u32, +} From 9398dd1e9cf92eaf4474fe8c81de9c3fdb43013c Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:21:46 -0700 Subject: [PATCH 016/203] Update generated protos. --- ldk-server/protos/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/protos/src/lib.rs index 689db8c96..2fcb85ac6 100644 --- a/ldk-server/protos/src/lib.rs +++ b/ldk-server/protos/src/lib.rs @@ -255,8 +255,8 @@ pub struct CloseChannelRequest { #[prost(string, tag = "2")] pub counterparty_node_id: ::prost::alloc::string::String, /// Whether to force close the specified channel. - #[prost(bool, tag = "3")] - pub force_close: bool, + #[prost(bool, optional, tag = "3")] + pub force_close: ::core::option::Option, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -290,7 +290,7 @@ pub struct Channel { /// The channel's funding transaction output, if we've negotiated the funding transaction with /// our counterparty already. #[prost(message, optional, tag = "3")] - pub funding_txo: ::core::option::Option, + pub funding_txo: ::core::option::Option, /// The local `user_channel_id` of this channel. #[prost(bytes = "vec", tag = "4")] pub user_channel_id: ::prost::alloc::vec::Vec, @@ -406,7 +406,7 @@ pub struct Channel { /// Represent a transaction outpoint. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Outpoint { +pub struct OutPoint { /// The referenced transaction's txid. #[prost(string, tag = "1")] pub txid: ::prost::alloc::string::String, From bbe0523b35ef226b9c247e9ae46627df6329edbb Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:22:50 -0700 Subject: [PATCH 017/203] Use Bytes instead of Vec in generated protos. Using ref-counted Bytes objects might help us in avoiding some clones while creating proto objects containing bytes. This could also be useful if we are using the same byte blob at multiple places or as part of multiple requests. --- ldk-server/protos/build.rs | 4 +++- ldk-server/protos/src/lib.rs | 16 ++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/ldk-server/protos/build.rs b/ldk-server/protos/build.rs index b65f50d87..f8b686292 100644 --- a/ldk-server/protos/build.rs +++ b/ldk-server/protos/build.rs @@ -12,7 +12,9 @@ fn main() { #[cfg(genproto)] fn generate_protos() { - prost_build::compile_protos(&["src/proto/ldk_node_server.proto"], &["src/"]) + prost_build::Config::new() + .bytes(&["."]) + .compile_protos(&["src/proto/ldk_node_server.proto"], &["src/"]) .expect("protobuf compilation failed"); println!("sss {}", &env::var("OUT_DIR").unwrap()); let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("ldk_node_server.rs"); diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/protos/src/lib.rs index 2fcb85ac6..5c5fddc58 100644 --- a/ldk-server/protos/src/lib.rs +++ b/ldk-server/protos/src/lib.rs @@ -94,8 +94,8 @@ pub struct Bolt11SendResponse { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct PaymentId { - #[prost(bytes = "vec", tag = "1")] - pub data: ::prost::alloc::vec::Vec, + #[prost(bytes = "bytes", tag = "1")] + pub data: ::prost::bytes::Bytes, } /// Returns a BOLT12 offer for the given amount, if specified. /// @@ -180,8 +180,8 @@ pub struct OpenChannelRequest { #[derive(Clone, PartialEq, ::prost::Message)] pub struct OpenChannelResponse { /// The channel id of the created channel that user can use to refer to channel. - #[prost(bytes = "vec", tag = "1")] - pub user_channel_id: ::prost::alloc::vec::Vec, + #[prost(bytes = "bytes", tag = "1")] + pub user_channel_id: ::prost::bytes::Bytes, } /// ChannelConfig represents the configuration settings for a channel in a Lightning Network node. /// See more: @@ -249,8 +249,8 @@ pub mod channel_config { #[derive(Clone, PartialEq, ::prost::Message)] pub struct CloseChannelRequest { /// The channel id of the created channel that user can use to refer to channel. - #[prost(bytes = "vec", tag = "1")] - pub user_channel_id: ::prost::alloc::vec::Vec, + #[prost(bytes = "bytes", tag = "1")] + pub user_channel_id: ::prost::bytes::Bytes, /// The hex-encoded public key of the node to close a channel with. #[prost(string, tag = "2")] pub counterparty_node_id: ::prost::alloc::string::String, @@ -292,8 +292,8 @@ pub struct Channel { #[prost(message, optional, tag = "3")] pub funding_txo: ::core::option::Option, /// The local `user_channel_id` of this channel. - #[prost(bytes = "vec", tag = "4")] - pub user_channel_id: ::prost::alloc::vec::Vec, + #[prost(bytes = "bytes", tag = "4")] + pub user_channel_id: ::prost::bytes::Bytes, /// The value, in satoshis, that must always be held as a reserve in the channel for us. This /// value ensures that if we broadcast a revoked state, our counterparty can punish us by /// claiming at least this value on chain. From b3939506bc8a885ece5d3842b969074b0b2f538b Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:25:42 -0700 Subject: [PATCH 018/203] Fix typo in log in build.rs --- ldk-server/protos/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/protos/build.rs b/ldk-server/protos/build.rs index f8b686292..5a1a185c8 100644 --- a/ldk-server/protos/build.rs +++ b/ldk-server/protos/build.rs @@ -16,7 +16,7 @@ fn generate_protos() { .bytes(&["."]) .compile_protos(&["src/proto/ldk_node_server.proto"], &["src/"]) .expect("protobuf compilation failed"); - println!("sss {}", &env::var("OUT_DIR").unwrap()); + println!("OUT_DIR: {}", &env::var("OUT_DIR").unwrap()); let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("ldk_node_server.rs"); fs::copy(from_path, "src/lib.rs").unwrap(); } From fe986fc3cd665e373773d2d631d1bf8ea7fa3c29 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:08:24 -0700 Subject: [PATCH 019/203] Add base rest client setup. --- ldk-server/client/Cargo.toml | 4 +++ ldk-server/client/src/client.rs | 49 +++++++++++++++++++++++++++++++++ ldk-server/client/src/error.rs | 20 ++++++++++++++ ldk-server/client/src/lib.rs | 28 +++++++++---------- 4 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 ldk-server/client/src/client.rs create mode 100644 ldk-server/client/src/error.rs diff --git a/ldk-server/client/Cargo.toml b/ldk-server/client/Cargo.toml index 87c805118..dd823fc90 100644 --- a/ldk-server/client/Cargo.toml +++ b/ldk-server/client/Cargo.toml @@ -4,3 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +protos = { path = "../protos" } +reqwest = { version = "0.11.13", default-features = false, features = ["rustls-tls"] } +tokio = { version = "1.38.0", default-features = false } +prost = { version = "0.11.6", default-features = false, features = ["std", "prost-derive"] } diff --git a/ldk-server/client/src/client.rs b/ldk-server/client/src/client.rs new file mode 100644 index 000000000..314c28800 --- /dev/null +++ b/ldk-server/client/src/client.rs @@ -0,0 +1,49 @@ +use prost::Message; + +use crate::error::LdkNodeServerError; +use reqwest::header::CONTENT_TYPE; +use reqwest::Client; + +const APPLICATION_OCTET_STREAM: &str = "application/octet-stream"; + +/// Client to access a hosted instance of LDK Node Server. +#[derive(Clone)] +pub struct LdkNodeServerClient { + base_url: String, + client: Client, +} + +impl LdkNodeServerClient { + /// Constructs a [`LdkNodeServerClient`] using `base_url` as the server endpoint. + pub fn new(base_url: String) -> Self { + Self { base_url, client: Client::new() } + } + + async fn post_request( + &self, request: &Rq, url: &str, + ) -> Result { + let request_body = request.encode_to_vec(); + let response_raw = match self + .client + .post(url) + .header(CONTENT_TYPE, APPLICATION_OCTET_STREAM) + .body(request_body) + .send() + .await + { + Ok(response) => response, + Err(e) => { + return Err(LdkNodeServerError::InternalError(e.to_string())); + }, + }; + let status = response_raw.status(); + let payload = response_raw.bytes().await?; + + if status.is_success() { + Ok(Rs::decode(&payload[..])?) + } else { + //TODO: Error handling and error response parsing. + Err(LdkNodeServerError::InternalError("Unknown Error".to_string())) + } + } +} diff --git a/ldk-server/client/src/error.rs b/ldk-server/client/src/error.rs new file mode 100644 index 000000000..c15726de6 --- /dev/null +++ b/ldk-server/client/src/error.rs @@ -0,0 +1,20 @@ +use prost::DecodeError; + +/// When there is an error in request to LDK Node Server, the response contains a relevant error code. +#[derive(Debug)] +pub enum LdkNodeServerError { + /// There is an unknown error. (Placeholder until error handling is done.) + InternalError(String), +} + +impl From for LdkNodeServerError { + fn from(err: DecodeError) -> Self { + LdkNodeServerError::InternalError(err.to_string()) + } +} + +impl From for LdkNodeServerError { + fn from(err: reqwest::Error) -> Self { + LdkNodeServerError::InternalError(err.to_string()) + } +} diff --git a/ldk-server/client/src/lib.rs b/ldk-server/client/src/lib.rs index 06d268d0c..36e9f52a9 100644 --- a/ldk-server/client/src/lib.rs +++ b/ldk-server/client/src/lib.rs @@ -1,14 +1,14 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} +//! Client-side library to interact with LDK Node Server. + +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] +#![deny(missing_docs)] + +/// Implements a client ([`client::LdkNodeServerClient`]) to access a hosted instance of LDK Node Server. +pub mod client; + +/// Implements the error type ([`error::LdkNodeServerError`]) returned on interacting with [`client::LdkNodeServerClient`] +pub mod error; + +/// Request/Response structs required for interacting with the client. +pub use protos; From 99392153dd37d47f0723e980ca26f267d7b9417a Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:44:17 -0700 Subject: [PATCH 020/203] Add initial set of api methods to rest-client. --- ldk-server/client/src/client.rs | 98 +++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/ldk-server/client/src/client.rs b/ldk-server/client/src/client.rs index 314c28800..ea97b7a88 100644 --- a/ldk-server/client/src/client.rs +++ b/ldk-server/client/src/client.rs @@ -1,11 +1,28 @@ use prost::Message; use crate::error::LdkNodeServerError; +use protos::{ + Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse, + Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, + CloseChannelRequest, CloseChannelResponse, ListChannelsRequest, ListChannelsResponse, + OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, + OpenChannelRequest, OpenChannelResponse, +}; use reqwest::header::CONTENT_TYPE; use reqwest::Client; const APPLICATION_OCTET_STREAM: &str = "application/octet-stream"; +const ONCHAIN_RECEIVE_PATH: &str = "OnchainReceive"; +const ONCHAIN_SEND_PATH: &str = "OnchainSend"; +const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; +const BOLT11_SEND_PATH: &str = "Bolt11Send"; +const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive"; +const BOLT12_SEND_PATH: &str = "Bolt12Send"; +const OPEN_CHANNEL_PATH: &str = "OpenChannel"; +const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; +const LIST_CHANNELS_PATH: &str = "ListChannels"; + /// Client to access a hosted instance of LDK Node Server. #[derive(Clone)] pub struct LdkNodeServerClient { @@ -19,6 +36,87 @@ impl LdkNodeServerClient { Self { base_url, client: Client::new() } } + /// Retrieve a new on-chain funding address. + /// For API contract/usage, refer to docs for [`OnchainReceiveRequest`] and [`OnchainReceiveResponse`]. + pub async fn onchain_receive( + &self, request: OnchainReceiveRequest, + ) -> Result { + let url = format!("http://{}/{ONCHAIN_RECEIVE_PATH}", self.base_url); + self.post_request(&request, &url).await + } + + /// Send an on-chain payment to the given address. + /// For API contract/usage, refer to docs for [`OnchainSendRequest`] and [`OnchainSendResponse`]. + pub async fn onchain_send( + &self, request: OnchainSendRequest, + ) -> Result { + let url = format!("http://{}/{ONCHAIN_SEND_PATH}", self.base_url); + self.post_request(&request, &url).await + } + + /// Retrieve a new BOLT11 payable invoice. + /// For API contract/usage, refer to docs for [`Bolt11ReceiveRequest`] and [`Bolt11ReceiveResponse`]. + pub async fn bolt11_receive( + &self, request: Bolt11ReceiveRequest, + ) -> Result { + let url = format!("http://{}/{BOLT11_RECEIVE_PATH}", self.base_url); + self.post_request(&request, &url).await + } + + /// Send a payment for a BOLT11 invoice. + /// For API contract/usage, refer to docs for [`Bolt11SendRequest`] and [`Bolt11SendResponse`]. + pub async fn bolt11_send( + &self, request: Bolt11SendRequest, + ) -> Result { + let url = format!("http://{}/{BOLT11_SEND_PATH}", self.base_url); + self.post_request(&request, &url).await + } + + /// Retrieve a new BOLT11 payable offer. + /// For API contract/usage, refer to docs for [`Bolt12ReceiveRequest`] and [`Bolt12ReceiveResponse`]. + pub async fn bolt12_receive( + &self, request: Bolt12ReceiveRequest, + ) -> Result { + let url = format!("http://{}/{BOLT12_RECEIVE_PATH}", self.base_url); + self.post_request(&request, &url).await + } + + /// Send a payment for a BOLT12 offer. + /// For API contract/usage, refer to docs for [`Bolt12SendRequest`] and [`Bolt12SendResponse`]. + pub async fn bolt12_send( + &self, request: Bolt12SendRequest, + ) -> Result { + let url = format!("http://{}/{BOLT12_SEND_PATH}", self.base_url); + self.post_request(&request, &url).await + } + + /// Creates a new outbound channel. + /// For API contract/usage, refer to docs for [`OpenChannelRequest`] and [`OpenChannelResponse`]. + pub async fn open_channel( + &self, request: OpenChannelRequest, + ) -> Result { + let url = format!("http://{}/{OPEN_CHANNEL_PATH}", self.base_url); + self.post_request(&request, &url).await + } + + /// Closes the channel specified by given request. + /// For API contract/usage, refer to docs for [`CloseChannelRequest`] and [`CloseChannelResponse`]. + pub async fn close_channel( + &self, request: CloseChannelRequest, + ) -> Result { + let url = format!("http://{}/{CLOSE_CHANNEL_PATH}", self.base_url); + self.post_request(&request, &url).await + } + + /// Retrieves list of known channels. + /// For API contract/usage, refer to docs for [`ListChannelsRequest`] and [`ListChannelsResponse`]. + pub async fn list_channels( + &self, request: ListChannelsRequest, + ) -> Result { + let url = format!("http://{}/{LIST_CHANNELS_PATH}", self.base_url); + self.post_request(&request, &url).await + } + async fn post_request( &self, request: &Rq, url: &str, ) -> Result { From 5fa52639fc67469fec13380be8c04e4395cbca56 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 6 Sep 2024 13:08:47 -0700 Subject: [PATCH 021/203] Add base cli setup. --- ldk-server/Cargo.lock | 75 ++++++++++++++++++++++++++++++++++++++ ldk-server/cli/Cargo.toml | 3 ++ ldk-server/cli/src/main.rs | 38 ++++++++++++++++++- 3 files changed, 114 insertions(+), 2 deletions(-) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 847f68a79..928080918 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -268,13 +268,58 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "clap" +version = "4.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5e0d0fdd7dc774d433c78c9de5695ca04724beaec6a7d4d13ac6014608f3eaf" +dependencies = [ + "bitflags 1.3.2", + "clap_derive", + "clap_lex", + "once_cell", +] + +[[package]] +name = "clap_derive" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca689d7434ce44517a12a89456b2be4d1ea1cafcd8f581978c03d45f5a5c12a7" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "cli" version = "0.1.0" +dependencies = [ + "clap", + "client", + "tokio", +] [[package]] name = "client" version = "0.1.0" +dependencies = [ + "prost", + "protos", + "reqwest", + "tokio", +] [[package]] name = "core-foundation" @@ -1025,6 +1070,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1081,6 +1132,30 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.86" diff --git a/ldk-server/cli/Cargo.toml b/ldk-server/cli/Cargo.toml index c1fb0b03c..b9a7ff480 100644 --- a/ldk-server/cli/Cargo.toml +++ b/ldk-server/cli/Cargo.toml @@ -4,3 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] +client = { path = "../client" } +clap = { version = "4.0.5", default-features = false, features = ["derive", "std"] } +tokio = { version = "1.38.0", default-features = false, features = ["rt-multi-thread", "macros"] } diff --git a/ldk-server/cli/src/main.rs b/ldk-server/cli/src/main.rs index a30eb952c..0011edf9f 100644 --- a/ldk-server/cli/src/main.rs +++ b/ldk-server/cli/src/main.rs @@ -1,3 +1,37 @@ -fn main() { - println!("Hello, world!"); +use clap::{Parser, Subcommand}; +use client::client::LdkNodeServerClient; +use client::protos::OnchainReceiveRequest; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Cli { + #[arg(short, long, default_value = "localhost:3000")] + base_url: String, + + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand, Debug)] +enum Commands { + OnchainReceive, +} + +#[tokio::main] +async fn main() { + let cli = Cli::parse(); + let client = LdkNodeServerClient::new(cli.base_url); + + match cli.command { + Commands::OnchainReceive => { + match client.onchain_receive(OnchainReceiveRequest {}).await { + Ok(response) => { + println!("New Bitcoin Address: {:?}", response); + }, + Err(e) => { + eprintln!("Error in OnchainReceive: {:?}", e); + }, + }; + }, + } } From 1466244bcf09f604c7fbe7c93520129920db56cd Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 10 Sep 2024 15:36:25 -0700 Subject: [PATCH 022/203] Add Cli command for OnchainSend --- ldk-server/Cargo.lock | 1 + ldk-server/cli/Cargo.toml | 1 + ldk-server/cli/src/main.rs | 36 +++++++++++++++++++++++++++--------- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 928080918..6f413f955 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -308,6 +308,7 @@ version = "0.1.0" dependencies = [ "clap", "client", + "prost", "tokio", ] diff --git a/ldk-server/cli/Cargo.toml b/ldk-server/cli/Cargo.toml index b9a7ff480..080c3c593 100644 --- a/ldk-server/cli/Cargo.toml +++ b/ldk-server/cli/Cargo.toml @@ -7,3 +7,4 @@ edition = "2021" client = { path = "../client" } clap = { version = "4.0.5", default-features = false, features = ["derive", "std"] } tokio = { version = "1.38.0", default-features = false, features = ["rt-multi-thread", "macros"] } +prost = { version = "0.11.6", default-features = false} diff --git a/ldk-server/cli/src/main.rs b/ldk-server/cli/src/main.rs index 0011edf9f..f654c29e3 100644 --- a/ldk-server/cli/src/main.rs +++ b/ldk-server/cli/src/main.rs @@ -1,6 +1,7 @@ use clap::{Parser, Subcommand}; use client::client::LdkNodeServerClient; -use client::protos::OnchainReceiveRequest; +use client::error::LdkNodeServerError; +use client::protos::{OnchainReceiveRequest, OnchainSendRequest}; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -15,6 +16,14 @@ struct Cli { #[derive(Subcommand, Debug)] enum Commands { OnchainReceive, + OnchainSend { + #[arg(short, long)] + address: String, + #[arg(long)] + amount_sats: Option, + #[arg(long)] + send_all: Option, + }, } #[tokio::main] @@ -24,14 +33,23 @@ async fn main() { match cli.command { Commands::OnchainReceive => { - match client.onchain_receive(OnchainReceiveRequest {}).await { - Ok(response) => { - println!("New Bitcoin Address: {:?}", response); - }, - Err(e) => { - eprintln!("Error in OnchainReceive: {:?}", e); - }, - }; + handle_response(client.onchain_receive(OnchainReceiveRequest {}).await); + }, + Commands::OnchainSend { address, amount_sats, send_all } => { + handle_response( + client.onchain_send(OnchainSendRequest { address, amount_sats, send_all }).await, + ); }, } } + +fn handle_response(response: Result) { + match response { + Ok(response) => { + println!("{:?}", response); + }, + Err(e) => { + eprintln!("Error executing command: {:?}", e); + }, + }; +} From 630455bb77e38a552e3bf1080fcb9d2fc6205683 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:20:38 -0700 Subject: [PATCH 023/203] Add Cli command for Bolt11Receive --- ldk-server/cli/src/main.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/ldk-server/cli/src/main.rs b/ldk-server/cli/src/main.rs index f654c29e3..247a16a97 100644 --- a/ldk-server/cli/src/main.rs +++ b/ldk-server/cli/src/main.rs @@ -1,7 +1,7 @@ use clap::{Parser, Subcommand}; use client::client::LdkNodeServerClient; use client::error::LdkNodeServerError; -use client::protos::{OnchainReceiveRequest, OnchainSendRequest}; +use client::protos::{Bolt11ReceiveRequest, OnchainReceiveRequest, OnchainSendRequest}; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -24,6 +24,14 @@ enum Commands { #[arg(long)] send_all: Option, }, + Bolt11Receive { + #[arg(short, long)] + description: String, + #[arg(short, long)] + expiry_secs: u32, + #[arg(long)] + amount_msat: Option, + }, } #[tokio::main] @@ -40,6 +48,13 @@ async fn main() { client.onchain_send(OnchainSendRequest { address, amount_sats, send_all }).await, ); }, + Commands::Bolt11Receive { description, expiry_secs, amount_msat } => { + handle_response( + client + .bolt11_receive(Bolt11ReceiveRequest { description, expiry_secs, amount_msat }) + .await, + ); + }, } } From 902545883dd20bc00757e1baa9c795b42625a71b Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:22:35 -0700 Subject: [PATCH 024/203] Add Cli command for Bolt11Send --- ldk-server/cli/src/main.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ldk-server/cli/src/main.rs b/ldk-server/cli/src/main.rs index 247a16a97..d0ab8ebca 100644 --- a/ldk-server/cli/src/main.rs +++ b/ldk-server/cli/src/main.rs @@ -1,7 +1,9 @@ use clap::{Parser, Subcommand}; use client::client::LdkNodeServerClient; use client::error::LdkNodeServerError; -use client::protos::{Bolt11ReceiveRequest, OnchainReceiveRequest, OnchainSendRequest}; +use client::protos::{ + Bolt11ReceiveRequest, Bolt11SendRequest, OnchainReceiveRequest, OnchainSendRequest, +}; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -32,6 +34,12 @@ enum Commands { #[arg(long)] amount_msat: Option, }, + Bolt11Send { + #[arg(short, long)] + invoice: String, + #[arg(long)] + amount_msat: Option, + }, } #[tokio::main] @@ -55,6 +63,9 @@ async fn main() { .await, ); }, + Commands::Bolt11Send { invoice, amount_msat } => { + handle_response(client.bolt11_send(Bolt11SendRequest { invoice, amount_msat }).await); + }, } } From 8517037a8989d9ce09bb56bffa38b2d364d98482 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:25:32 -0700 Subject: [PATCH 025/203] Add Cli command for Bolt12Receive --- ldk-server/cli/src/main.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ldk-server/cli/src/main.rs b/ldk-server/cli/src/main.rs index d0ab8ebca..e1030b471 100644 --- a/ldk-server/cli/src/main.rs +++ b/ldk-server/cli/src/main.rs @@ -2,7 +2,8 @@ use clap::{Parser, Subcommand}; use client::client::LdkNodeServerClient; use client::error::LdkNodeServerError; use client::protos::{ - Bolt11ReceiveRequest, Bolt11SendRequest, OnchainReceiveRequest, OnchainSendRequest, + Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, OnchainReceiveRequest, + OnchainSendRequest, }; #[derive(Parser, Debug)] @@ -40,6 +41,12 @@ enum Commands { #[arg(long)] amount_msat: Option, }, + Bolt12Receive { + #[arg(short, long)] + description: String, + #[arg(long)] + amount_msat: Option, + }, } #[tokio::main] @@ -66,6 +73,11 @@ async fn main() { Commands::Bolt11Send { invoice, amount_msat } => { handle_response(client.bolt11_send(Bolt11SendRequest { invoice, amount_msat }).await); }, + Commands::Bolt12Receive { description, amount_msat } => { + handle_response( + client.bolt12_receive(Bolt12ReceiveRequest { description, amount_msat }).await, + ); + }, } } From 10d40298558f319829289b35f2cb52394dd33701 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:29:35 -0700 Subject: [PATCH 026/203] Add Cli command for Bolt12Send --- ldk-server/cli/src/main.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/ldk-server/cli/src/main.rs b/ldk-server/cli/src/main.rs index e1030b471..c442cec1e 100644 --- a/ldk-server/cli/src/main.rs +++ b/ldk-server/cli/src/main.rs @@ -2,8 +2,8 @@ use clap::{Parser, Subcommand}; use client::client::LdkNodeServerClient; use client::error::LdkNodeServerError; use client::protos::{ - Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, OnchainReceiveRequest, - OnchainSendRequest, + Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, Bolt12SendRequest, + OnchainReceiveRequest, OnchainSendRequest, }; #[derive(Parser, Debug)] @@ -47,6 +47,16 @@ enum Commands { #[arg(long)] amount_msat: Option, }, + Bolt12Send { + #[arg(short, long)] + offer: String, + #[arg(long)] + amount_msat: Option, + #[arg(short, long)] + quantity: Option, + #[arg(short, long)] + payer_note: Option, + }, } #[tokio::main] @@ -78,6 +88,13 @@ async fn main() { client.bolt12_receive(Bolt12ReceiveRequest { description, amount_msat }).await, ); }, + Commands::Bolt12Send { offer, amount_msat, quantity, payer_note } => { + handle_response( + client + .bolt12_send(Bolt12SendRequest { offer, amount_msat, quantity, payer_note }) + .await, + ); + }, } } From 033457ca346afbcaead9d98a25d8a619b48eb6e7 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:37:26 -0700 Subject: [PATCH 027/203] Add Cli command for OpenChannel --- ldk-server/cli/src/main.rs | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/ldk-server/cli/src/main.rs b/ldk-server/cli/src/main.rs index c442cec1e..61cf04471 100644 --- a/ldk-server/cli/src/main.rs +++ b/ldk-server/cli/src/main.rs @@ -3,7 +3,7 @@ use client::client::LdkNodeServerClient; use client::error::LdkNodeServerError; use client::protos::{ Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, Bolt12SendRequest, - OnchainReceiveRequest, OnchainSendRequest, + OnchainReceiveRequest, OnchainSendRequest, OpenChannelRequest, }; #[derive(Parser, Debug)] @@ -57,6 +57,18 @@ enum Commands { #[arg(short, long)] payer_note: Option, }, + OpenChannel { + #[arg(short, long)] + node_pubkey: String, + #[arg(short, long)] + address: String, + #[arg(long)] + channel_amount_sats: u64, + #[arg(long)] + push_to_counterparty_msat: Option, + #[arg(long)] + announce_channel: bool, + }, } #[tokio::main] @@ -95,6 +107,26 @@ async fn main() { .await, ); }, + Commands::OpenChannel { + node_pubkey, + address, + channel_amount_sats, + push_to_counterparty_msat, + announce_channel, + } => { + handle_response( + client + .open_channel(OpenChannelRequest { + node_pubkey, + address, + channel_amount_sats, + push_to_counterparty_msat, + channel_config: None, + announce_channel, + }) + .await, + ); + }, } } From adb0605a74b43273f2e20f10ca332678a8c978e8 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 11 Sep 2024 14:30:28 -0700 Subject: [PATCH 028/203] Exit with status code 1 on error. --- ldk-server/cli/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ldk-server/cli/src/main.rs b/ldk-server/cli/src/main.rs index 61cf04471..cf97a7764 100644 --- a/ldk-server/cli/src/main.rs +++ b/ldk-server/cli/src/main.rs @@ -137,6 +137,7 @@ fn handle_response(response: Result { eprintln!("Error executing command: {:?}", e); + std::process::exit(1); // Exit with status code 1 on error. }, }; } From c6d9d971beddc582ccb670233883316ea1d55287 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 25 Sep 2024 13:30:52 +0900 Subject: [PATCH 029/203] Remove PaymentId as separate type from api. --- ldk-server/protos/src/lib.rs | 13 +++---------- ldk-server/protos/src/proto/ldk_node_server.proto | 10 ++-------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/protos/src/lib.rs index 5c5fddc58..3d62d28f9 100644 --- a/ldk-server/protos/src/lib.rs +++ b/ldk-server/protos/src/lib.rs @@ -87,15 +87,8 @@ pub struct Bolt11SendRequest { #[derive(Clone, PartialEq, ::prost::Message)] pub struct Bolt11SendResponse { /// An identifier used to uniquely identify a payment. - #[prost(message, optional, tag = "1")] - pub payment_id: ::core::option::Option, -} -/// An identifier used to uniquely identify a payment. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PaymentId { #[prost(bytes = "bytes", tag = "1")] - pub data: ::prost::bytes::Bytes, + pub payment_id: ::prost::bytes::Bytes, } /// Returns a BOLT12 offer for the given amount, if specified. /// @@ -148,8 +141,8 @@ pub struct Bolt12SendRequest { #[derive(Clone, PartialEq, ::prost::Message)] pub struct Bolt12SendResponse { /// An identifier used to uniquely identify a payment. - #[prost(message, optional, tag = "1")] - pub payment_id: ::core::option::Option, + #[prost(bytes = "bytes", tag = "1")] + pub payment_id: ::prost::bytes::Bytes, } /// Creates a new outbound channel to the given remote node. /// See more: diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index 07409d85d..e415ba127 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -85,13 +85,7 @@ message Bolt11SendRequest { message Bolt11SendResponse { // An identifier used to uniquely identify a payment. - PaymentId payment_id = 1; -} - -// An identifier used to uniquely identify a payment. -message PaymentId { - - bytes data = 1; + bytes payment_id = 1; } // Returns a BOLT12 offer for the given amount, if specified. @@ -141,7 +135,7 @@ message Bolt12SendRequest { message Bolt12SendResponse { // An identifier used to uniquely identify a payment. - PaymentId payment_id = 1; + bytes payment_id = 1; } // Creates a new outbound channel to the given remote node. From 8723504ca060e5792f247f18306d501db2e368eb Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:23:21 -0700 Subject: [PATCH 030/203] Add Impl for OnchainReceive Api --- ldk-server/server/src/api/mod.rs | 1 + ldk-server/server/src/api/onchain_receive.rs | 12 ++++++++++++ ldk-server/server/src/main.rs | 1 + ldk-server/server/src/service.rs | 8 +++++++- 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 ldk-server/server/src/api/mod.rs create mode 100644 ldk-server/server/src/api/onchain_receive.rs diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs new file mode 100644 index 000000000..ad02e7d49 --- /dev/null +++ b/ldk-server/server/src/api/mod.rs @@ -0,0 +1 @@ +pub(crate) mod onchain_receive; diff --git a/ldk-server/server/src/api/onchain_receive.rs b/ldk-server/server/src/api/onchain_receive.rs new file mode 100644 index 000000000..565bfd930 --- /dev/null +++ b/ldk-server/server/src/api/onchain_receive.rs @@ -0,0 +1,12 @@ +use ldk_node::Node; +use protos::{OnchainReceiveRequest, OnchainReceiveResponse}; +use std::sync::Arc; + +pub(crate) const ONCHAIN_RECEIVE_PATH: &str = "OnchainReceive"; +pub(crate) fn handle_onchain_receive_request( + node: Arc, _request: OnchainReceiveRequest, +) -> Result { + let response = + OnchainReceiveResponse { address: node.onchain_payment().new_address()?.to_string() }; + Ok(response) +} diff --git a/ldk-server/server/src/main.rs b/ldk-server/server/src/main.rs index b440903b0..9c9fd6528 100644 --- a/ldk-server/server/src/main.rs +++ b/ldk-server/server/src/main.rs @@ -1,3 +1,4 @@ +mod api; mod service; use crate::service::NodeService; diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index 606dfd108..8820e46ac 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -11,6 +11,9 @@ use std::future::Future; use std::pin::Pin; use std::sync::Arc; +use crate::api::onchain_receive::handle_onchain_receive_request; +use crate::api::onchain_receive::ONCHAIN_RECEIVE_PATH; + #[derive(Clone)] pub struct NodeService { node: Arc, @@ -28,8 +31,11 @@ impl Service> for NodeService { type Future = Pin> + Send>>; fn call(&self, req: Request) -> Self::Future { - let _node = Arc::clone(&self.node); + let node = Arc::clone(&self.node); match req.uri().path() { + ONCHAIN_RECEIVE_PATH => { + Box::pin(handle_request(node, req, handle_onchain_receive_request)) + }, path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async { From 79c4a21f5af61b661d9685b06a9a497a29b97112 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:23:37 -0700 Subject: [PATCH 031/203] Add Impl for OnchainSend Api --- ldk-server/server/src/api/mod.rs | 1 + ldk-server/server/src/api/onchain_send.rs | 25 +++++++++++++++++++++++ ldk-server/server/src/service.rs | 3 +++ 3 files changed, 29 insertions(+) create mode 100644 ldk-server/server/src/api/onchain_send.rs diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs index ad02e7d49..fe9d9a86f 100644 --- a/ldk-server/server/src/api/mod.rs +++ b/ldk-server/server/src/api/mod.rs @@ -1 +1,2 @@ pub(crate) mod onchain_receive; +pub(crate) mod onchain_send; diff --git a/ldk-server/server/src/api/onchain_send.rs b/ldk-server/server/src/api/onchain_send.rs new file mode 100644 index 000000000..0e40d6310 --- /dev/null +++ b/ldk-server/server/src/api/onchain_send.rs @@ -0,0 +1,25 @@ +use ldk_node::bitcoin::Address; +use ldk_node::Node; +use protos::{OnchainSendRequest, OnchainSendResponse}; +use std::str::FromStr; +use std::sync::Arc; + +pub(crate) const ONCHAIN_SEND_PATH: &str = "OnchainSend"; + +pub(crate) fn handle_onchain_send_request( + node: Arc, request: OnchainSendRequest, +) -> Result { + let address = Address::from_str(&request.address) + .map_err(|_| ldk_node::NodeError::InvalidAddress)? + .require_network(node.config().network) + .map_err(|_| ldk_node::NodeError::InvalidAddress)?; + let txid = match (request.amount_sats, request.send_all) { + (Some(amount_sats), None) => { + node.onchain_payment().send_to_address(&address, amount_sats)? + }, + (None, Some(true)) => node.onchain_payment().send_all_to_address(&address)?, + _ => return Err(ldk_node::NodeError::InvalidAmount), + }; + let response = OnchainSendResponse { txid: txid.to_string() }; + Ok(response) +} diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index 8820e46ac..4f9d7644e 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -13,6 +13,8 @@ use std::sync::Arc; use crate::api::onchain_receive::handle_onchain_receive_request; use crate::api::onchain_receive::ONCHAIN_RECEIVE_PATH; +use crate::api::onchain_send::handle_onchain_send_request; +use crate::api::onchain_send::ONCHAIN_SEND_PATH; #[derive(Clone)] pub struct NodeService { @@ -36,6 +38,7 @@ impl Service> for NodeService { ONCHAIN_RECEIVE_PATH => { Box::pin(handle_request(node, req, handle_onchain_receive_request)) }, + ONCHAIN_SEND_PATH => Box::pin(handle_request(node, req, handle_onchain_send_request)), path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async { From 8f5eb8a032431ee08b45d73c1b2c915dbd2e9ef3 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:24:07 -0700 Subject: [PATCH 032/203] Add Impl for BOLT11Receive Api --- ldk-server/server/src/api/bolt11_receive.rs | 21 +++++++++++++++++++++ ldk-server/server/src/api/mod.rs | 1 + ldk-server/server/src/service.rs | 5 +++++ 3 files changed, 27 insertions(+) create mode 100644 ldk-server/server/src/api/bolt11_receive.rs diff --git a/ldk-server/server/src/api/bolt11_receive.rs b/ldk-server/server/src/api/bolt11_receive.rs new file mode 100644 index 000000000..8778c6761 --- /dev/null +++ b/ldk-server/server/src/api/bolt11_receive.rs @@ -0,0 +1,21 @@ +use ldk_node::Node; +use protos::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; +use std::sync::Arc; + +pub(crate) const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; + +pub(crate) fn handle_bolt11_receive_request( + node: Arc, request: Bolt11ReceiveRequest, +) -> Result { + let invoice = match request.amount_msat { + Some(amount_msat) => { + node.bolt11_payment().receive(amount_msat, &request.description, request.expiry_secs)? + }, + None => node + .bolt11_payment() + .receive_variable_amount(&request.description, request.expiry_secs)?, + }; + + let response = Bolt11ReceiveResponse { invoice: invoice.to_string() }; + Ok(response) +} diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs index fe9d9a86f..9d958a63c 100644 --- a/ldk-server/server/src/api/mod.rs +++ b/ldk-server/server/src/api/mod.rs @@ -1,2 +1,3 @@ +pub(crate) mod bolt11_receive; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index 4f9d7644e..7d447125f 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -15,6 +15,8 @@ use crate::api::onchain_receive::handle_onchain_receive_request; use crate::api::onchain_receive::ONCHAIN_RECEIVE_PATH; use crate::api::onchain_send::handle_onchain_send_request; use crate::api::onchain_send::ONCHAIN_SEND_PATH; +use crate::api::bolt11_receive::handle_bolt11_receive_request; +use crate::api::bolt11_receive::BOLT11_RECEIVE_PATH; #[derive(Clone)] pub struct NodeService { @@ -39,6 +41,9 @@ impl Service> for NodeService { Box::pin(handle_request(node, req, handle_onchain_receive_request)) }, ONCHAIN_SEND_PATH => Box::pin(handle_request(node, req, handle_onchain_send_request)), + BOLT11_RECEIVE_PATH => { + Box::pin(handle_request(node, req, handle_bolt11_receive_request)) + }, path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async { From e04e767edcfda60ddcdfacf02beb0a9034035e14 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:24:24 -0700 Subject: [PATCH 033/203] Add Impl for OpenChannel Api --- ldk-server/Cargo.lock | 1 + ldk-server/server/Cargo.toml | 1 + ldk-server/server/src/api/mod.rs | 1 + ldk-server/server/src/api/open_channel.rs | 31 +++++++++++++++++++++++ ldk-server/server/src/service.rs | 3 +++ 5 files changed, 37 insertions(+) create mode 100644 ldk-server/server/src/api/open_channel.rs diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 847f68a79..7d1f24229 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -809,6 +809,7 @@ dependencies = [ name = "ldk-node-server" version = "0.1.0" dependencies = [ + "bytes", "http-body-util", "hyper 1.4.1", "hyper-util", diff --git a/ldk-server/server/Cargo.toml b/ldk-server/server/Cargo.toml index 82fd98011..285cbe2f5 100644 --- a/ldk-server/server/Cargo.toml +++ b/ldk-server/server/Cargo.toml @@ -13,3 +13,4 @@ hyper-util = { version = "0.1", default-features = false, features = ["server-gr tokio = { version = "1.38.0", default-features = false, features = ["time", "signal", "rt-multi-thread"] } prost = { version = "0.11.6", default-features = false, features = ["std"] } protos = { path = "../protos" } +bytes = "1.4.0" diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs index 9d958a63c..307ce7906 100644 --- a/ldk-server/server/src/api/mod.rs +++ b/ldk-server/server/src/api/mod.rs @@ -1,3 +1,4 @@ pub(crate) mod bolt11_receive; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; +pub(crate) mod open_channel; diff --git a/ldk-server/server/src/api/open_channel.rs b/ldk-server/server/src/api/open_channel.rs new file mode 100644 index 000000000..5bcb6daae --- /dev/null +++ b/ldk-server/server/src/api/open_channel.rs @@ -0,0 +1,31 @@ +use bytes::Bytes; +use ldk_node::bitcoin::secp256k1::PublicKey; +use ldk_node::lightning::ln::msgs::SocketAddress; +use ldk_node::Node; +use protos::{OpenChannelRequest, OpenChannelResponse}; +use std::str::FromStr; +use std::sync::Arc; + +pub(crate) const OPEN_CHANNEL_PATH: &str = "OpenChannel"; + +pub(crate) fn handle_open_channel( + node: Arc, request: OpenChannelRequest, +) -> 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 user_channel_id = node.connect_open_channel( + node_id, + address, + request.channel_amount_sats, + request.push_to_counterparty_msat, + // TODO: Allow setting ChannelConfig in open-channel. + None, + request.announce_channel, + )?; + let response = OpenChannelResponse { + user_channel_id: Bytes::from(user_channel_id.0.to_be_bytes().to_vec()), + }; + Ok(response) +} diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index 7d447125f..e7d10e0d9 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -17,6 +17,8 @@ use crate::api::onchain_send::handle_onchain_send_request; use crate::api::onchain_send::ONCHAIN_SEND_PATH; use crate::api::bolt11_receive::handle_bolt11_receive_request; use crate::api::bolt11_receive::BOLT11_RECEIVE_PATH; +use crate::api::open_channel::handle_open_channel; +use crate::api::open_channel::OPEN_CHANNEL_PATH; #[derive(Clone)] pub struct NodeService { @@ -44,6 +46,7 @@ impl Service> for NodeService { BOLT11_RECEIVE_PATH => { Box::pin(handle_request(node, req, handle_bolt11_receive_request)) }, + OPEN_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_open_channel)), path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async { From fa2be30d1a51a6f5bd7df281c1e99f072d1cc4e0 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:49:50 -0700 Subject: [PATCH 034/203] Add Impl for Bolt11Send Api --- ldk-server/server/src/api/bolt11_send.rs | 23 +++++++++++++++++++++++ ldk-server/server/src/api/mod.rs | 1 + ldk-server/server/src/service.rs | 3 +++ 3 files changed, 27 insertions(+) create mode 100644 ldk-server/server/src/api/bolt11_send.rs diff --git a/ldk-server/server/src/api/bolt11_send.rs b/ldk-server/server/src/api/bolt11_send.rs new file mode 100644 index 000000000..a5d41e824 --- /dev/null +++ b/ldk-server/server/src/api/bolt11_send.rs @@ -0,0 +1,23 @@ +use bytes::Bytes; +use ldk_node::lightning_invoice::Bolt11Invoice; +use ldk_node::Node; +use protos::{Bolt11SendRequest, Bolt11SendResponse}; +use std::str::FromStr; +use std::sync::Arc; + +pub(crate) const BOLT11_SEND_PATH: &str = "Bolt11Send"; + +pub(crate) fn handle_bolt11_send_request( + node: Arc, request: Bolt11SendRequest, +) -> Result { + let invoice = Bolt11Invoice::from_str(&request.invoice.as_str()) + .map_err(|_| ldk_node::NodeError::InvalidInvoice)?; + + let payment_id = match request.amount_msat { + None => node.bolt11_payment().send(&invoice), + Some(amount_msat) => node.bolt11_payment().send_using_amount(&invoice, amount_msat), + }?; + + let response = Bolt11SendResponse { payment_id: Bytes::from(payment_id.0.to_vec()) }; + Ok(response) +} diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs index 307ce7906..1f6b05009 100644 --- a/ldk-server/server/src/api/mod.rs +++ b/ldk-server/server/src/api/mod.rs @@ -1,4 +1,5 @@ pub(crate) mod bolt11_receive; +pub(crate) mod bolt11_send; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; pub(crate) mod open_channel; diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index e7d10e0d9..69f250278 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -19,6 +19,8 @@ use crate::api::bolt11_receive::handle_bolt11_receive_request; use crate::api::bolt11_receive::BOLT11_RECEIVE_PATH; use crate::api::open_channel::handle_open_channel; use crate::api::open_channel::OPEN_CHANNEL_PATH; +use crate::api::bolt11_send::handle_bolt11_send_request; +use crate::api::bolt11_send::BOLT11_SEND_PATH; #[derive(Clone)] pub struct NodeService { @@ -46,6 +48,7 @@ impl Service> for NodeService { BOLT11_RECEIVE_PATH => { Box::pin(handle_request(node, req, handle_bolt11_receive_request)) }, + BOLT11_SEND_PATH => Box::pin(handle_request(node, req, handle_bolt11_send_request)), OPEN_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_open_channel)), path => { let error = format!("Unknown request: {}", path).into_bytes(); From de57ea174cfb7bc79efe7eea74751729a1503b25 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 4 Sep 2024 17:24:44 -0700 Subject: [PATCH 035/203] Add Impl for Bolt12Receive Api --- ldk-server/server/src/api/bolt12_receive.rs | 17 +++++++++++++++++ ldk-server/server/src/api/mod.rs | 1 + ldk-server/server/src/service.rs | 5 +++++ 3 files changed, 23 insertions(+) create mode 100644 ldk-server/server/src/api/bolt12_receive.rs diff --git a/ldk-server/server/src/api/bolt12_receive.rs b/ldk-server/server/src/api/bolt12_receive.rs new file mode 100644 index 000000000..9a5ae79bd --- /dev/null +++ b/ldk-server/server/src/api/bolt12_receive.rs @@ -0,0 +1,17 @@ +use ldk_node::Node; +use protos::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; +use std::sync::Arc; + +pub(crate) const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive"; + +pub(crate) fn handle_bolt12_receive_request( + node: Arc, request: Bolt12ReceiveRequest, +) -> Result { + let offer = match request.amount_msat { + Some(amount_msat) => node.bolt12_payment().receive(amount_msat, &request.description)?, + None => node.bolt12_payment().receive_variable_amount(&request.description)?, + }; + + let response = Bolt12ReceiveResponse { offer: offer.to_string() }; + Ok(response) +} diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs index 1f6b05009..9b7d580e6 100644 --- a/ldk-server/server/src/api/mod.rs +++ b/ldk-server/server/src/api/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod bolt11_receive; pub(crate) mod bolt11_send; +pub(crate) mod bolt12_receive; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; pub(crate) mod open_channel; diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index 69f250278..74d98b353 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -21,6 +21,8 @@ use crate::api::open_channel::handle_open_channel; use crate::api::open_channel::OPEN_CHANNEL_PATH; use crate::api::bolt11_send::handle_bolt11_send_request; use crate::api::bolt11_send::BOLT11_SEND_PATH; +use crate::api::bolt12_receive::handle_bolt12_receive_request; +use crate::api::bolt12_receive::BOLT12_RECEIVE_PATH; #[derive(Clone)] pub struct NodeService { @@ -49,6 +51,9 @@ impl Service> for NodeService { Box::pin(handle_request(node, req, handle_bolt11_receive_request)) }, BOLT11_SEND_PATH => Box::pin(handle_request(node, req, handle_bolt11_send_request)), + BOLT12_RECEIVE_PATH => { + Box::pin(handle_request(node, req, handle_bolt12_receive_request)) + }, OPEN_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_open_channel)), path => { let error = format!("Unknown request: {}", path).into_bytes(); From 47fef7570796e8e8e15c8c8c25daaa702c81fee8 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 4 Sep 2024 17:25:26 -0700 Subject: [PATCH 036/203] Add Impl for Bolt12Send Api --- ldk-server/server/src/api/bolt12_send.rs | 25 ++++++++++++++++++++++++ ldk-server/server/src/api/mod.rs | 1 + ldk-server/server/src/service.rs | 3 +++ 3 files changed, 29 insertions(+) create mode 100644 ldk-server/server/src/api/bolt12_send.rs diff --git a/ldk-server/server/src/api/bolt12_send.rs b/ldk-server/server/src/api/bolt12_send.rs new file mode 100644 index 000000000..8718e0ab0 --- /dev/null +++ b/ldk-server/server/src/api/bolt12_send.rs @@ -0,0 +1,25 @@ +use bytes::Bytes; +use ldk_node::lightning::offers::offer::Offer; +use ldk_node::Node; +use protos::{Bolt12SendRequest, Bolt12SendResponse}; +use std::str::FromStr; +use std::sync::Arc; + +pub(crate) const BOLT12_SEND_PATH: &str = "Bolt12Send"; + +pub(crate) fn handle_bolt12_send_request( + node: Arc, request: Bolt12SendRequest, +) -> Result { + let offer = + Offer::from_str(&request.offer.as_str()).map_err(|_| ldk_node::NodeError::InvalidOffer)?; + + let payment_id = match request.amount_msat { + None => node.bolt12_payment().send(&offer, request.payer_note), + Some(amount_msat) => { + node.bolt12_payment().send_using_amount(&offer, request.payer_note, amount_msat) + }, + }?; + + let response = Bolt12SendResponse { payment_id: Bytes::from(payment_id.0.to_vec()) }; + Ok(response) +} diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs index 9b7d580e6..39a952817 100644 --- a/ldk-server/server/src/api/mod.rs +++ b/ldk-server/server/src/api/mod.rs @@ -1,6 +1,7 @@ pub(crate) mod bolt11_receive; pub(crate) mod bolt11_send; pub(crate) mod bolt12_receive; +pub(crate) mod bolt12_send; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; pub(crate) mod open_channel; diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index 74d98b353..9e8656bc7 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -23,6 +23,8 @@ use crate::api::bolt11_send::handle_bolt11_send_request; use crate::api::bolt11_send::BOLT11_SEND_PATH; use crate::api::bolt12_receive::handle_bolt12_receive_request; use crate::api::bolt12_receive::BOLT12_RECEIVE_PATH; +use crate::api::bolt12_send::handle_bolt12_send_request; +use crate::api::bolt12_send::BOLT12_SEND_PATH; #[derive(Clone)] pub struct NodeService { @@ -54,6 +56,7 @@ impl Service> for NodeService { BOLT12_RECEIVE_PATH => { Box::pin(handle_request(node, req, handle_bolt12_receive_request)) }, + BOLT12_SEND_PATH => Box::pin(handle_request(node, req, handle_bolt12_send_request)), OPEN_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_open_channel)), path => { let error = format!("Unknown request: {}", path).into_bytes(); From 8a9764ca7cd56fb38ecff6ea3921eb27ba76eedb Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:32:31 -0700 Subject: [PATCH 037/203] Add Impl for CloseChannel Api --- ldk-server/server/src/api/close_channel.rs | 26 ++++++++++++++++++++++ ldk-server/server/src/api/mod.rs | 1 + ldk-server/server/src/service.rs | 15 ++++++++----- 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 ldk-server/server/src/api/close_channel.rs diff --git a/ldk-server/server/src/api/close_channel.rs b/ldk-server/server/src/api/close_channel.rs new file mode 100644 index 000000000..73e0d5caf --- /dev/null +++ b/ldk-server/server/src/api/close_channel.rs @@ -0,0 +1,26 @@ +use ldk_node::bitcoin::secp256k1::PublicKey; +use ldk_node::{Node, UserChannelId}; +use protos::{CloseChannelRequest, CloseChannelResponse}; +use std::str::FromStr; +use std::sync::Arc; + +pub(crate) const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; + +pub(crate) fn handle_close_channel_request( + node: Arc, request: CloseChannelRequest, +) -> Result { + //TODO: Should this be string? + let mut user_channel_id_bytes = [0u8; 16]; + user_channel_id_bytes.copy_from_slice(&request.user_channel_id); + let user_channel_id = UserChannelId(u128::from_be_bytes(user_channel_id_bytes)); + let counterparty_node_id = PublicKey::from_str(&request.counterparty_node_id) + .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; + + match request.force_close { + Some(true) => node.force_close_channel(&user_channel_id, counterparty_node_id)?, + _ => node.close_channel(&user_channel_id, counterparty_node_id)?, + }; + + let response = CloseChannelResponse {}; + Ok(response) +} diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs index 39a952817..42aa26203 100644 --- a/ldk-server/server/src/api/mod.rs +++ b/ldk-server/server/src/api/mod.rs @@ -2,6 +2,7 @@ pub(crate) mod bolt11_receive; pub(crate) mod bolt11_send; pub(crate) mod bolt12_receive; pub(crate) mod bolt12_send; +pub(crate) mod close_channel; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; pub(crate) mod open_channel; diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index 9e8656bc7..ef4aa251b 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -11,20 +11,22 @@ use std::future::Future; use std::pin::Pin; use std::sync::Arc; -use crate::api::onchain_receive::handle_onchain_receive_request; -use crate::api::onchain_receive::ONCHAIN_RECEIVE_PATH; -use crate::api::onchain_send::handle_onchain_send_request; -use crate::api::onchain_send::ONCHAIN_SEND_PATH; use crate::api::bolt11_receive::handle_bolt11_receive_request; use crate::api::bolt11_receive::BOLT11_RECEIVE_PATH; -use crate::api::open_channel::handle_open_channel; -use crate::api::open_channel::OPEN_CHANNEL_PATH; use crate::api::bolt11_send::handle_bolt11_send_request; use crate::api::bolt11_send::BOLT11_SEND_PATH; use crate::api::bolt12_receive::handle_bolt12_receive_request; use crate::api::bolt12_receive::BOLT12_RECEIVE_PATH; use crate::api::bolt12_send::handle_bolt12_send_request; use crate::api::bolt12_send::BOLT12_SEND_PATH; +use crate::api::close_channel::handle_close_channel_request; +use crate::api::close_channel::CLOSE_CHANNEL_PATH; +use crate::api::onchain_receive::handle_onchain_receive_request; +use crate::api::onchain_receive::ONCHAIN_RECEIVE_PATH; +use crate::api::onchain_send::handle_onchain_send_request; +use crate::api::onchain_send::ONCHAIN_SEND_PATH; +use crate::api::open_channel::handle_open_channel; +use crate::api::open_channel::OPEN_CHANNEL_PATH; #[derive(Clone)] pub struct NodeService { @@ -58,6 +60,7 @@ impl Service> for NodeService { }, BOLT12_SEND_PATH => Box::pin(handle_request(node, req, handle_bolt12_send_request)), OPEN_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_open_channel)), + CLOSE_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_close_channel_request)), path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async { From 3167f2cdfd9acd01ecbba4327b82a1a6ba5fa05d Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:09:53 +0900 Subject: [PATCH 038/203] Add suggestions/error-context clap features. It is helpful in case of wrong input by user. --- ldk-server/cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/cli/Cargo.toml b/ldk-server/cli/Cargo.toml index 080c3c593..a8f9df755 100644 --- a/ldk-server/cli/Cargo.toml +++ b/ldk-server/cli/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" [dependencies] client = { path = "../client" } -clap = { version = "4.0.5", default-features = false, features = ["derive", "std"] } +clap = { version = "4.0.5", default-features = false, features = ["derive", "std", "error-context", "suggestions", "help"] } tokio = { version = "1.38.0", default-features = false, features = ["rt-multi-thread", "macros"] } prost = { version = "0.11.6", default-features = false} From c89ae4e29a0d30fdd411b1eff735a765abfe5e9f Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:14:03 +0900 Subject: [PATCH 039/203] Exclude '/' from path pattern matching. --- ldk-server/server/src/service.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index ef4aa251b..5f1f8f7b8 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -46,7 +46,8 @@ impl Service> for NodeService { fn call(&self, req: Request) -> Self::Future { let node = Arc::clone(&self.node); - match req.uri().path() { + // Exclude '/' from path pattern matching. + match &req.uri().path()[1..] { ONCHAIN_RECEIVE_PATH => { Box::pin(handle_request(node, req, handle_onchain_receive_request)) }, From d2ef390f25ae36a8bfac74d93b09366b5dfed1ca Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Sun, 13 Oct 2024 14:32:50 -0700 Subject: [PATCH 040/203] Group similar imports. --- ldk-server/server/src/service.rs | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index 5f1f8f7b8..7141e0bc1 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -11,22 +11,14 @@ use std::future::Future; use std::pin::Pin; use std::sync::Arc; -use crate::api::bolt11_receive::handle_bolt11_receive_request; -use crate::api::bolt11_receive::BOLT11_RECEIVE_PATH; -use crate::api::bolt11_send::handle_bolt11_send_request; -use crate::api::bolt11_send::BOLT11_SEND_PATH; -use crate::api::bolt12_receive::handle_bolt12_receive_request; -use crate::api::bolt12_receive::BOLT12_RECEIVE_PATH; -use crate::api::bolt12_send::handle_bolt12_send_request; -use crate::api::bolt12_send::BOLT12_SEND_PATH; -use crate::api::close_channel::handle_close_channel_request; -use crate::api::close_channel::CLOSE_CHANNEL_PATH; -use crate::api::onchain_receive::handle_onchain_receive_request; -use crate::api::onchain_receive::ONCHAIN_RECEIVE_PATH; -use crate::api::onchain_send::handle_onchain_send_request; -use crate::api::onchain_send::ONCHAIN_SEND_PATH; -use crate::api::open_channel::handle_open_channel; -use crate::api::open_channel::OPEN_CHANNEL_PATH; +use crate::api::bolt11_receive::{handle_bolt11_receive_request, BOLT11_RECEIVE_PATH}; +use crate::api::bolt11_send::{handle_bolt11_send_request, BOLT11_SEND_PATH}; +use crate::api::bolt12_receive::{handle_bolt12_receive_request, BOLT12_RECEIVE_PATH}; +use crate::api::bolt12_send::{handle_bolt12_send_request, BOLT12_SEND_PATH}; +use crate::api::close_channel::{handle_close_channel_request, CLOSE_CHANNEL_PATH}; +use crate::api::onchain_receive::{handle_onchain_receive_request, ONCHAIN_RECEIVE_PATH}; +use crate::api::onchain_send::{handle_onchain_send_request, ONCHAIN_SEND_PATH}; +use crate::api::open_channel::{handle_open_channel, OPEN_CHANNEL_PATH}; #[derive(Clone)] pub struct NodeService { From 24ffd37d2a4d26164ead79817c3fb8682ddb5d74 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Sun, 13 Oct 2024 15:12:51 -0700 Subject: [PATCH 041/203] Minor proto changes for ListChannels Impl. --- ldk-server/protos/src/lib.rs | 30 +++++++++---------- .../protos/src/proto/ldk_node_server.proto | 16 +++++----- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/protos/src/lib.rs index 3d62d28f9..e5b3df1a5 100644 --- a/ldk-server/protos/src/lib.rs +++ b/ldk-server/protos/src/lib.rs @@ -184,28 +184,28 @@ pub struct ChannelConfig { /// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound /// over the channel. /// See more: - #[prost(uint32, tag = "1")] - pub forwarding_fee_proportional_millionths: u32, + #[prost(uint32, optional, tag = "1")] + pub forwarding_fee_proportional_millionths: ::core::option::Option, /// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, /// in excess of forwarding_fee_proportional_millionths. /// See more: - #[prost(uint32, tag = "2")] - pub forwarding_fee_base_msat: u32, + #[prost(uint32, optional, tag = "2")] + pub forwarding_fee_base_msat: ::core::option::Option, /// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded /// over the channel this config applies to. /// See more: - #[prost(uint32, tag = "3")] - pub cltv_expiry_delta: u32, + #[prost(uint32, optional, tag = "3")] + pub cltv_expiry_delta: ::core::option::Option, /// The maximum additional fee we’re willing to pay to avoid waiting for the counterparty’s /// to_self_delay to reclaim funds. /// See more: - #[prost(uint64, tag = "4")] - pub force_close_avoidance_max_fee_satoshis: u64, + #[prost(uint64, optional, tag = "4")] + pub force_close_avoidance_max_fee_satoshis: ::core::option::Option, /// If set, allows this channel’s counterparty to skim an additional fee off this node’s /// inbound HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users. /// See more: - #[prost(bool, tag = "5")] - pub accept_underpaying_htlcs: bool, + #[prost(bool, optional, tag = "5")] + pub accept_underpaying_htlcs: ::core::option::Option, /// Limit our total exposure to potential loss to on-chain fees on close, including /// in-flight HTLCs which are burned to fees as they are too small to claim on-chain /// and fees on commitment transaction(s) broadcasted by our counterparty in excess of @@ -284,9 +284,9 @@ pub struct Channel { /// our counterparty already. #[prost(message, optional, tag = "3")] pub funding_txo: ::core::option::Option, - /// The local `user_channel_id` of this channel. - #[prost(bytes = "bytes", tag = "4")] - pub user_channel_id: ::prost::bytes::Bytes, + /// The hex-encoded local `user_channel_id` of this channel. + #[prost(string, tag = "4")] + pub user_channel_id: ::prost::alloc::string::String, /// The value, in satoshis, that must always be held as a reserve in the channel for us. This /// value ensures that if we broadcast a revoked state, our counterparty can punish us by /// claiming at least this value on chain. @@ -383,8 +383,8 @@ pub struct Channel { /// claiming at least this value on chain. /// /// This value is not included in `inbound_capacity_msat` as it can never be spent. - #[prost(uint64, optional, tag = "22")] - pub counterparty_unspendable_punishment_reserve: ::core::option::Option, + #[prost(uint64, tag = "22")] + pub counterparty_unspendable_punishment_reserve: u64, /// Base routing fee in millisatoshis. #[prost(uint32, optional, tag = "23")] pub counterparty_forwarding_info_fee_base_msat: ::core::option::Option, diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index e415ba127..8ae9e8065 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -174,27 +174,27 @@ message ChannelConfig { // Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound // over the channel. // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.forwarding_fee_proportional_millionths - uint32 forwarding_fee_proportional_millionths = 1; + optional uint32 forwarding_fee_proportional_millionths = 1; // Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, // in excess of forwarding_fee_proportional_millionths. // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.forwarding_fee_base_msat - uint32 forwarding_fee_base_msat = 2; + optional uint32 forwarding_fee_base_msat = 2; // The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded // over the channel this config applies to. // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.cltv_expiry_delta - uint32 cltv_expiry_delta = 3; + optional uint32 cltv_expiry_delta = 3; // The maximum additional fee we’re willing to pay to avoid waiting for the counterparty’s // to_self_delay to reclaim funds. // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.force_close_avoidance_max_fee_satoshis - uint64 force_close_avoidance_max_fee_satoshis = 4; + optional uint64 force_close_avoidance_max_fee_satoshis = 4; // If set, allows this channel’s counterparty to skim an additional fee off this node’s // inbound HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users. // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.accept_underpaying_htlcs - bool accept_underpaying_htlcs = 5; + optional bool accept_underpaying_htlcs = 5; // Limit our total exposure to potential loss to on-chain fees on close, including // in-flight HTLCs which are burned to fees as they are too small to claim on-chain @@ -259,8 +259,8 @@ message Channel { // our counterparty already. optional OutPoint funding_txo = 3; - // The local `user_channel_id` of this channel. - bytes user_channel_id = 4; + // The hex-encoded local `user_channel_id` of this channel. + string user_channel_id = 4; // The value, in satoshis, that must always be held as a reserve in the channel for us. This // value ensures that if we broadcast a revoked state, our counterparty can punish us by @@ -358,7 +358,7 @@ message Channel { // claiming at least this value on chain. // // This value is not included in `inbound_capacity_msat` as it can never be spent. - optional uint64 counterparty_unspendable_punishment_reserve = 22; + uint64 counterparty_unspendable_punishment_reserve = 22; // Base routing fee in millisatoshis. optional uint32 counterparty_forwarding_info_fee_base_msat = 23; From e24425bab0d1bebcbfb851816d4083921efcb155 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Sun, 13 Oct 2024 15:15:36 -0700 Subject: [PATCH 042/203] Add impl for ListChannels Api. --- ldk-server/server/Cargo.toml | 1 + ldk-server/server/src/api/list_channels.rs | 15 ++++++ ldk-server/server/src/api/mod.rs | 1 + ldk-server/server/src/main.rs | 1 + ldk-server/server/src/service.rs | 2 + ldk-server/server/src/util/mod.rs | 1 + ldk-server/server/src/util/proto_adapter.rs | 55 +++++++++++++++++++++ 7 files changed, 76 insertions(+) create mode 100644 ldk-server/server/src/api/list_channels.rs create mode 100644 ldk-server/server/src/util/mod.rs create mode 100644 ldk-server/server/src/util/proto_adapter.rs diff --git a/ldk-server/server/Cargo.toml b/ldk-server/server/Cargo.toml index 285cbe2f5..ba2100381 100644 --- a/ldk-server/server/Cargo.toml +++ b/ldk-server/server/Cargo.toml @@ -14,3 +14,4 @@ tokio = { version = "1.38.0", default-features = false, features = ["time", "sig prost = { version = "0.11.6", default-features = false, features = ["std"] } protos = { path = "../protos" } bytes = "1.4.0" +hex = { package = "hex-conservative", version = "0.2.1", default-features = false } diff --git a/ldk-server/server/src/api/list_channels.rs b/ldk-server/server/src/api/list_channels.rs new file mode 100644 index 000000000..32688d6bc --- /dev/null +++ b/ldk-server/server/src/api/list_channels.rs @@ -0,0 +1,15 @@ +use crate::util::proto_adapter::channel_to_proto; +use ldk_node::Node; +use protos::{ListChannelsRequest, ListChannelsResponse}; +use std::sync::Arc; + +pub(crate) const LIST_CHANNELS_PATH: &str = "ListChannels"; + +pub(crate) fn handle_list_channels_request( + node: Arc, _request: ListChannelsRequest, +) -> Result { + let channels = node.list_channels().into_iter().map(|c| channel_to_proto(c)).collect(); + + let response = ListChannelsResponse { channels }; + Ok(response) +} diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs index 42aa26203..22a2185f7 100644 --- a/ldk-server/server/src/api/mod.rs +++ b/ldk-server/server/src/api/mod.rs @@ -3,6 +3,7 @@ pub(crate) mod bolt11_send; pub(crate) mod bolt12_receive; pub(crate) mod bolt12_send; pub(crate) mod close_channel; +pub(crate) mod list_channels; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; pub(crate) mod open_channel; diff --git a/ldk-server/server/src/main.rs b/ldk-server/server/src/main.rs index 9c9fd6528..0bebbdc4d 100644 --- a/ldk-server/server/src/main.rs +++ b/ldk-server/server/src/main.rs @@ -1,5 +1,6 @@ mod api; mod service; +mod util; use crate::service::NodeService; diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index 7141e0bc1..df185383d 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -16,6 +16,7 @@ use crate::api::bolt11_send::{handle_bolt11_send_request, BOLT11_SEND_PATH}; use crate::api::bolt12_receive::{handle_bolt12_receive_request, BOLT12_RECEIVE_PATH}; use crate::api::bolt12_send::{handle_bolt12_send_request, BOLT12_SEND_PATH}; use crate::api::close_channel::{handle_close_channel_request, CLOSE_CHANNEL_PATH}; +use crate::api::list_channels::{handle_list_channels_request, LIST_CHANNELS_PATH}; use crate::api::onchain_receive::{handle_onchain_receive_request, ONCHAIN_RECEIVE_PATH}; use crate::api::onchain_send::{handle_onchain_send_request, ONCHAIN_SEND_PATH}; use crate::api::open_channel::{handle_open_channel, OPEN_CHANNEL_PATH}; @@ -54,6 +55,7 @@ impl Service> for NodeService { BOLT12_SEND_PATH => Box::pin(handle_request(node, req, handle_bolt12_send_request)), OPEN_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_open_channel)), CLOSE_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_close_channel_request)), + LIST_CHANNELS_PATH => Box::pin(handle_request(node, req, handle_list_channels_request)), path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async { diff --git a/ldk-server/server/src/util/mod.rs b/ldk-server/server/src/util/mod.rs new file mode 100644 index 000000000..8f7d1a3d9 --- /dev/null +++ b/ldk-server/server/src/util/mod.rs @@ -0,0 +1 @@ +pub(crate) mod proto_adapter; diff --git a/ldk-server/server/src/util/proto_adapter.rs b/ldk-server/server/src/util/proto_adapter.rs new file mode 100644 index 000000000..09d5fc944 --- /dev/null +++ b/ldk-server/server/src/util/proto_adapter.rs @@ -0,0 +1,55 @@ +use hex::prelude::*; +use ldk_node::{ChannelConfig, ChannelDetails}; +use protos::{Channel, OutPoint}; +pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { + Channel { + channel_id: channel.channel_id.0.to_lower_hex_string(), + counterparty_node_id: channel.counterparty_node_id.to_string(), + funding_txo: channel + .funding_txo + .map(|o| OutPoint { txid: o.txid.to_string(), vout: o.vout }), + user_channel_id: channel.user_channel_id.0.to_string(), + unspendable_punishment_reserve: channel.unspendable_punishment_reserve, + channel_value_sats: channel.channel_value_sats, + feerate_sat_per_1000_weight: channel.feerate_sat_per_1000_weight, + outbound_capacity_msat: channel.outbound_capacity_msat, + inbound_capacity_msat: channel.inbound_capacity_msat, + confirmations_required: channel.confirmations_required, + confirmations: channel.confirmations, + is_outbound: channel.is_outbound, + is_channel_ready: channel.is_channel_ready, + is_usable: channel.is_usable, + is_public: channel.is_public, + channel_config: Some(channel_config_to_proto(channel.config.as_ref())), + next_outbound_htlc_limit_msat: channel.next_outbound_htlc_limit_msat, + next_outbound_htlc_minimum_msat: channel.next_outbound_htlc_minimum_msat, + force_close_spend_delay: channel.force_close_spend_delay.map(|x| x as u32), + counterparty_outbound_htlc_minimum_msat: channel.counterparty_outbound_htlc_minimum_msat, + counterparty_outbound_htlc_maximum_msat: channel.counterparty_outbound_htlc_maximum_msat, + counterparty_unspendable_punishment_reserve: channel + .counterparty_unspendable_punishment_reserve, + counterparty_forwarding_info_fee_base_msat: channel + .counterparty_forwarding_info_fee_base_msat, + counterparty_forwarding_info_fee_proportional_millionths: channel + .counterparty_forwarding_info_fee_proportional_millionths, + counterparty_forwarding_info_cltv_expiry_delta: channel + .counterparty_forwarding_info_cltv_expiry_delta + .map(|x| x as u32), + } +} + +pub(crate) fn channel_config_to_proto(channel_config: &ChannelConfig) -> protos::ChannelConfig { + protos::ChannelConfig { + forwarding_fee_proportional_millionths: Some( + channel_config.forwarding_fee_proportional_millionths(), + ), + forwarding_fee_base_msat: Some(channel_config.forwarding_fee_base_msat()), + cltv_expiry_delta: Some(channel_config.cltv_expiry_delta() as u32), + force_close_avoidance_max_fee_satoshis: Some( + channel_config.force_close_avoidance_max_fee_satoshis(), + ), + accept_underpaying_htlcs: Some(channel_config.accept_underpaying_htlcs()), + // FIXME: Pending ldk-node upgrade. + max_dust_htlc_exposure: None, + } +} From 89d930806c0cc1b1d47f6faf2dc91a7e0029e514 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Sun, 13 Oct 2024 15:28:32 -0700 Subject: [PATCH 043/203] Add proto for GetNodeInfo. --- ldk-server/protos/src/lib.rs | 57 ++++++++++++++++++ .../protos/src/proto/ldk_node_server.proto | 58 ++++++++++++++++++- 2 files changed, 114 insertions(+), 1 deletion(-) diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/protos/src/lib.rs index e5b3df1a5..f20bb9ec3 100644 --- a/ldk-server/protos/src/lib.rs +++ b/ldk-server/protos/src/lib.rs @@ -1,3 +1,50 @@ +/// Retrieve the latest node info like `node_id`, `current_best_block` etc. +/// See more: +/// - +/// - +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetNodeInfoRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetNodeInfoResponse { + /// The hex-encoded `node-id` or public key for our own lightning node. + #[prost(string, tag = "1")] + pub node_id: ::prost::alloc::string::String, + /// The best block to which our Lightning wallet is currently synced. + /// + /// Should be always set, will never be `None`. + #[prost(message, optional, tag = "3")] + pub current_best_block: ::core::option::Option, + /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our Lightning wallet + /// to the chain tip. + /// + /// Will be `None` if the wallet hasn’t been synced since the node was initialized. + #[prost(uint64, optional, tag = "4")] + pub latest_wallet_sync_timestamp: ::core::option::Option, + /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our on-chain + /// wallet to the chain tip. + /// + /// Will be `None` if the wallet hasn’t been synced since the node was initialized. + #[prost(uint64, optional, tag = "5")] + pub latest_onchain_wallet_sync_timestamp: ::core::option::Option, + /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully update our fee rate cache. + /// + /// Will be `None` if the cache hasn’t been updated since the node was initialized. + #[prost(uint64, optional, tag = "6")] + pub latest_fee_rate_cache_update_timestamp: ::core::option::Option, + /// The timestamp, in seconds since start of the UNIX epoch, when the last rapid gossip sync (RGS) snapshot we + /// successfully applied was generated. + /// + /// Will be `None` if RGS isn’t configured or the snapshot hasn’t been updated since the node was initialized. + #[prost(uint64, optional, tag = "7")] + pub latest_rgs_snapshot_timestamp: ::core::option::Option, + /// The timestamp, in seconds since start of the UNIX epoch, when we last broadcasted a node announcement. + /// + /// Will be `None` if we have no public channels or we haven’t broadcasted since the node was initialized. + #[prost(uint64, optional, tag = "8")] + pub latest_node_announcement_broadcast_timestamp: ::core::option::Option, +} /// Retrieve a new on-chain funding address. /// See more: #[allow(clippy::derive_partial_eq_without_eq)] @@ -407,3 +454,13 @@ pub struct OutPoint { #[prost(uint32, tag = "2")] pub vout: u32, } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BestBlock { + /// The block’s hash + #[prost(string, tag = "1")] + pub block_hash: ::prost::alloc::string::String, + /// The height at which the block was confirmed. + #[prost(uint32, tag = "2")] + pub height: u32, +} diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index 8ae9e8065..588a5bf86 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -1,6 +1,52 @@ syntax = "proto3"; package ldk_node_server; +// Retrieve the latest node info like `node_id`, `current_best_block` etc. +// See more: +// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.node_id +// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.status +message GetNodeInfoRequest { +} + +message GetNodeInfoResponse { + + // The hex-encoded `node-id` or public key for our own lightning node. + string node_id = 1; + + // The best block to which our Lightning wallet is currently synced. + // + // Should be always set, will never be `None`. + BestBlock current_best_block = 3; + + // The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our Lightning wallet + // to the chain tip. + // + // Will be `None` if the wallet hasn’t been synced since the node was initialized. + optional uint64 latest_wallet_sync_timestamp = 4; + + // The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our on-chain + // wallet to the chain tip. + // + // Will be `None` if the wallet hasn’t been synced since the node was initialized. + optional uint64 latest_onchain_wallet_sync_timestamp = 5; + + // The timestamp, in seconds since start of the UNIX epoch, when we last successfully update our fee rate cache. + // + // Will be `None` if the cache hasn’t been updated since the node was initialized. + optional uint64 latest_fee_rate_cache_update_timestamp = 6; + + // The timestamp, in seconds since start of the UNIX epoch, when the last rapid gossip sync (RGS) snapshot we + // successfully applied was generated. + // + // Will be `None` if RGS isn’t configured or the snapshot hasn’t been updated since the node was initialized. + optional uint64 latest_rgs_snapshot_timestamp = 7; + + // The timestamp, in seconds since start of the UNIX epoch, when we last broadcasted a node announcement. + // + // Will be `None` if we have no public channels or we haven’t broadcasted since the node was initialized. + optional uint64 latest_node_announcement_broadcast_timestamp = 8; +} + // Retrieve a new on-chain funding address. // See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.new_address message OnchainReceiveRequest { @@ -378,4 +424,14 @@ message OutPoint { // The index of the referenced output in its transaction's vout. uint32 vout = 2; -} \ No newline at end of file +} + +message BestBlock { + + // The block’s hash + string block_hash = 1; + + // The height at which the block was confirmed. + uint32 height = 2; + +} From 729e672244c7198a22fa2d8fdf733df56d9657d9 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Sun, 13 Oct 2024 15:41:12 -0700 Subject: [PATCH 044/203] Add impl for GetNodeInfo Api. --- ldk-server/server/src/api/get_node_info.rs | 28 ++++++++++++++++++++++ ldk-server/server/src/api/mod.rs | 1 + ldk-server/server/src/service.rs | 2 ++ 3 files changed, 31 insertions(+) create mode 100644 ldk-server/server/src/api/get_node_info.rs diff --git a/ldk-server/server/src/api/get_node_info.rs b/ldk-server/server/src/api/get_node_info.rs new file mode 100644 index 000000000..d98c8f1bb --- /dev/null +++ b/ldk-server/server/src/api/get_node_info.rs @@ -0,0 +1,28 @@ +use ldk_node::Node; +use protos::{BestBlock, GetNodeInfoRequest, GetNodeInfoResponse}; +use std::sync::Arc; + +pub(crate) const GET_NODE_INFO: &str = "GetNodeInfo"; + +pub(crate) fn handle_get_node_info_request( + node: Arc, _request: GetNodeInfoRequest, +) -> Result { + let node_status = node.status(); + + let best_block = BestBlock { + block_hash: node_status.current_best_block.block_hash.to_string(), + height: node_status.current_best_block.height, + }; + + let response = GetNodeInfoResponse { + node_id: node.node_id().to_string(), + current_best_block: Some(best_block), + latest_wallet_sync_timestamp: node_status.latest_wallet_sync_timestamp, + latest_onchain_wallet_sync_timestamp: node_status.latest_onchain_wallet_sync_timestamp, + latest_fee_rate_cache_update_timestamp: node_status.latest_fee_rate_cache_update_timestamp, + latest_rgs_snapshot_timestamp: node_status.latest_rgs_snapshot_timestamp, + latest_node_announcement_broadcast_timestamp: node_status + .latest_node_announcement_broadcast_timestamp, + }; + Ok(response) +} diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs index 22a2185f7..6355e9de8 100644 --- a/ldk-server/server/src/api/mod.rs +++ b/ldk-server/server/src/api/mod.rs @@ -3,6 +3,7 @@ pub(crate) mod bolt11_send; pub(crate) mod bolt12_receive; pub(crate) mod bolt12_send; pub(crate) mod close_channel; +pub(crate) mod get_node_info; pub(crate) mod list_channels; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index df185383d..15eaa7931 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -16,6 +16,7 @@ use crate::api::bolt11_send::{handle_bolt11_send_request, BOLT11_SEND_PATH}; use crate::api::bolt12_receive::{handle_bolt12_receive_request, BOLT12_RECEIVE_PATH}; use crate::api::bolt12_send::{handle_bolt12_send_request, BOLT12_SEND_PATH}; use crate::api::close_channel::{handle_close_channel_request, CLOSE_CHANNEL_PATH}; +use crate::api::get_node_info::{handle_get_node_info_request, GET_NODE_INFO}; use crate::api::list_channels::{handle_list_channels_request, LIST_CHANNELS_PATH}; use crate::api::onchain_receive::{handle_onchain_receive_request, ONCHAIN_RECEIVE_PATH}; use crate::api::onchain_send::{handle_onchain_send_request, ONCHAIN_SEND_PATH}; @@ -41,6 +42,7 @@ impl Service> for NodeService { let node = Arc::clone(&self.node); // Exclude '/' from path pattern matching. match &req.uri().path()[1..] { + GET_NODE_INFO => Box::pin(handle_request(node, req, handle_get_node_info_request)), ONCHAIN_RECEIVE_PATH => { Box::pin(handle_request(node, req, handle_onchain_receive_request)) }, From 8c63b4589c6e09e48b07d8c5ce7fe3b24461ae89 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:21:41 -0700 Subject: [PATCH 045/203] Upgrade Ldk-node to v0.4.0 / Ldk to v0.0.125 --- ldk-server/Cargo.lock | 312 +++++++++++++++++++++++++---------- ldk-server/server/Cargo.toml | 2 +- 2 files changed, 229 insertions(+), 85 deletions(-) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 54dd631dc..3e07926ef 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -19,14 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.8" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] +checksum = "0453232ace82dee0dd0b4c87a59bd90f7b53b314f3e0f61fe2ee7c8a16482289" [[package]] name = "ahash" @@ -70,6 +65,12 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "async-trait" version = "0.1.81" @@ -103,10 +104,14 @@ dependencies = [ ] [[package]] -name = "base64" -version = "0.13.1" +name = "base58ck" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" +dependencies = [ + "bitcoin-internals", + "bitcoin_hashes 0.14.0", +] [[package]] name = "base64" @@ -115,28 +120,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] -name = "bdk" -version = "0.29.0" +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc1fc1a92e0943bfbcd6eb7d32c1b2a79f2f1357eb1e2eee9d7f36d6d7ca44a" -dependencies = [ - "ahash 0.7.8", - "async-trait", - "bdk-macros", - "bip39", - "bitcoin", - "esplora-client", - "futures", - "getrandom", - "js-sys", - "log", - "miniscript", - "rand", - "rusqlite", - "serde", - "serde_json", - "tokio", -] +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bdk-macros" @@ -149,17 +136,73 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "bdk_chain" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e553c45ffed860aa7e0c6998c3a827fcdc039a2df76307563208ecfcae2f750" +dependencies = [ + "bdk_core", + "bitcoin", + "miniscript", + "serde", +] + +[[package]] +name = "bdk_core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0b45300422611971b0bbe84b04d18e38e81a056a66860c9dd3434f6d0f5396" +dependencies = [ + "bitcoin", + "hashbrown 0.9.1", + "serde", +] + +[[package]] +name = "bdk_esplora" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cc9b320b2042e9729739eed66c6fc47b208554c8c6e393785cd56d257045e9f" +dependencies = [ + "async-trait", + "bdk_core", + "esplora-client", + "futures", +] + +[[package]] +name = "bdk_wallet" +version = "1.0.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb48cd8e0a15d0bf7351fc8c30e44c474be01f4f98eb29f20ab59b645bd29c" +dependencies = [ + "bdk_chain", + "bip39", + "bitcoin", + "miniscript", + "rand_core", + "serde", + "serde_json", +] + [[package]] name = "bech32" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +[[package]] +name = "bech32" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" + [[package]] name = "bip21" -version = "0.3.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9532c632b068e45a478f5e309126b6e2ec1dbf0bbd327b73836f33d9a43ede" +checksum = "ebe7a7f5928d264879d5b65eb18a72ea1890c57f22d62ee2eba93f207a6a020b" dependencies = [ "bitcoin", "percent-encoding-rfc3986", @@ -178,14 +221,18 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.30.2" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1945a5048598e4189e239d3f809b19bdad4845c4b2ba400d304d2dcf26d2c462" +checksum = "0032b0e8ead7074cda7fc4f034409607e3f03a6f71d66ade8a307f79b4d99e73" dependencies = [ - "base64 0.13.1", - "bech32", - "bitcoin-private", - "bitcoin_hashes 0.12.0", + "base58ck", + "base64 0.21.7", + "bech32 0.11.0", + "bitcoin-internals", + "bitcoin-io", + "bitcoin-units", + "bitcoin_hashes 0.14.0", + "hex-conservative", "hex_lit", "secp256k1", "serde", @@ -193,9 +240,18 @@ dependencies = [ [[package]] name = "bitcoin-internals" -version = "0.1.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f9997f8650dd818369931b5672a18dbef95324d0513aa99aae758de8ce86e5b" +checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" +dependencies = [ + "serde", +] + +[[package]] +name = "bitcoin-io" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" [[package]] name = "bitcoin-private" @@ -203,6 +259,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" +[[package]] +name = "bitcoin-units" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +dependencies = [ + "bitcoin-internals", + "serde", +] + [[package]] name = "bitcoin_hashes" version = "0.11.0" @@ -216,6 +282,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" dependencies = [ "bitcoin-private", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", "serde", ] @@ -268,6 +344,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[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.0.5" @@ -278,6 +360,7 @@ dependencies = [ "clap_derive", "clap_lex", "once_cell", + "strsim", ] [[package]] @@ -371,12 +454,12 @@ dependencies = [ [[package]] name = "esplora-client" -version = "0.6.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cb1f7f2489cce83bc3bd92784f9ba5271eeb6e729b975895fc541f78cbfcdca" +checksum = "9b546e91283ebfc56337de34e0cf814e3ad98083afde593b8e58495ee5355d0e" dependencies = [ "bitcoin", - "bitcoin-internals", + "hex-conservative", "log", "reqwest", "serde", @@ -546,6 +629,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash 0.4.8", + "serde", +] + [[package]] name = "hashbrown" version = "0.13.2" @@ -584,9 +677,12 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex-conservative" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] [[package]] name = "hex_lit" @@ -824,10 +920,14 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "ldk-node" -version = "0.3.0" -source = "git+https://github.com/lightningdevkit/ldk-node.git?branch=main#77a0bbede4f063ee50ca2aa36fb019e79d3f8707" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50eff8ed03ff8847930eba51dc975fc12b10e96619cf9aabd9ab6f50db93ada" dependencies = [ - "bdk", + "base64 0.22.1", + "bdk_chain", + "bdk_esplora", + "bdk_wallet", "bip21", "bip39", "bitcoin", @@ -836,6 +936,7 @@ dependencies = [ "libc", "lightning", "lightning-background-processor", + "lightning-block-sync", "lightning-invoice", "lightning-liquidity", "lightning-net-tokio", @@ -846,6 +947,8 @@ dependencies = [ "rand", "reqwest", "rusqlite", + "serde", + "serde_json", "tokio", "vss-client", "winapi", @@ -856,6 +959,7 @@ name = "ldk-node-server" version = "0.1.0" dependencies = [ "bytes", + "hex-conservative", "http-body-util", "hyper 1.4.1", "hyper-util", @@ -886,19 +990,21 @@ dependencies = [ [[package]] name = "lightning" -version = "0.0.123" +version = "0.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd92d4aa159374be430c7590e169b4a6c0fb79018f5bc4ea1bffde536384db3" +checksum = "767f388e50251da71f95a3737d6db32c9729f9de6427a54fa92bb994d04d793f" dependencies = [ + "bech32 0.9.1", "bitcoin", - "hex-conservative", + "lightning-invoice", + "lightning-types", ] [[package]] name = "lightning-background-processor" -version = "0.0.123" +version = "0.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb1c2c64050e37cee7c3b6b022106523784055ac3ee572d360780a1d6fe8062c" +checksum = "4734caab73611a2c725f15392565150e4f5a531dd1f239365d01311f7de65d2d" dependencies = [ "bitcoin", "lightning", @@ -906,37 +1012,50 @@ dependencies = [ ] [[package]] -name = "lightning-invoice" -version = "0.31.0" +name = "lightning-block-sync" +version = "0.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d07d01cf197bf2184b929b7dc94aa70d935aac6df896c256a3a9475b7e9d40" +checksum = "ea041135bad736b075ad1123ef0a4793e78da8041386aa7887779fc5c540b94b" dependencies = [ - "bech32", "bitcoin", + "chunked_transfer", "lightning", - "secp256k1", + "serde_json", + "tokio", +] + +[[package]] +name = "lightning-invoice" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ab9f6ea77e20e3129235e62a2e6bd64ed932363df104e864ee65ccffb54a8f" +dependencies = [ + "bech32 0.9.1", + "bitcoin", + "lightning-types", "serde", ] [[package]] name = "lightning-liquidity" -version = "0.1.0-alpha.4" +version = "0.1.0-alpha.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fa6284740f64672f42145de7b0a242beea3821dae1f0eac7949a8f48799c828" +checksum = "175cff5d30b8d3f94ae9772b59f9ca576b1927a6ab60dd773e8c4e0593cd4e95" dependencies = [ "bitcoin", "chrono", "lightning", "lightning-invoice", + "lightning-types", "serde", "serde_json", ] [[package]] name = "lightning-net-tokio" -version = "0.0.123" +version = "0.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e6a4d49c50a1344916d080dc8c012ce3a778cdd45de8def75350b2b40fe018" +checksum = "af2847a19f892f32b9ab5075af25c70370b4cc5842b4f5b53c57092e52a49498" dependencies = [ "bitcoin", "lightning", @@ -945,9 +1064,9 @@ dependencies = [ [[package]] name = "lightning-persister" -version = "0.0.123" +version = "0.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a8dd33971815fa074b05678e09a6d4b15c78225ea34d66ed4f17c35a53467a9" +checksum = "8d06283d41eb8e6d4af883cd602d91ab0c5f9e0c9a6be1c944b10e6f47176f20" dependencies = [ "bitcoin", "lightning", @@ -956,9 +1075,9 @@ dependencies = [ [[package]] name = "lightning-rapid-gossip-sync" -version = "0.0.123" +version = "0.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d861b0f0cd5f8fe8c63760023c4fd4fd32c384881b41780b62ced2a8a619f91" +checksum = "92185313db1075495e5efa3dd6a3b5d4dee63e1496059f58cf65074994718f05" dependencies = [ "bitcoin", "lightning", @@ -966,9 +1085,9 @@ dependencies = [ [[package]] name = "lightning-transaction-sync" -version = "0.0.123" +version = "0.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c1e88eece28f19b5834fb5aefceabc5d143cfda2dfa9a32f73e66f4d0c84ed" +checksum = "a8f023cb8dcd9c8b83b9b0c673ed6ca2e9afb57791119d3fa3224db2787b717e" dependencies = [ "bdk-macros", "bitcoin", @@ -977,6 +1096,17 @@ dependencies = [ "lightning", ] +[[package]] +name = "lightning-types" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1083b8d9137000edf3bfcb1ff011c0d25e0cdd2feb98cc21d6765e64a494148f" +dependencies = [ + "bech32 0.9.1", + "bitcoin", + "hex-conservative", +] + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -1003,12 +1133,12 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniscript" -version = "10.1.0" +version = "12.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70545cd04bd4eaf5689918aa8a9b155ecb29d8542d82537968cf9ce9e22460a3" +checksum = "add2d4aee30e4291ce5cffa3a322e441ff4d4bc57b38c8d9bf0e94faa50ab626" dependencies = [ + "bech32 0.11.0", "bitcoin", - "bitcoin-private", "serde", ] @@ -1436,9 +1566,9 @@ dependencies = [ [[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 0.12.0", "rand", @@ -1448,27 +1578,27 @@ dependencies = [ [[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", ] [[package]] name = "serde" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -1477,11 +1607,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "610f75ff4a8e3cb29b85da56eabdd1bff5b06739059a4b8e2967fef32e5d9944" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -1538,6 +1669,12 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" version = "1.0.109" @@ -1781,15 +1918,22 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vss-client" -version = "0.2.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62cbd331368125aeb93b67dd4a80826a4ee29a810d4c76d2c9d265c1522a3f2" +checksum = "d787f7640ceae8caef95434f1b14936402b73e18d34868b052a502a5d5085490" dependencies = [ + "async-trait", + "base64 0.21.7", + "bitcoin", + "bitcoin_hashes 0.14.0", "prost", "prost-build", "rand", "reqwest", + "serde", + "serde_json", "tokio", + "url", ] [[package]] diff --git a/ldk-server/server/Cargo.toml b/ldk-server/server/Cargo.toml index ba2100381..a0b9194f6 100644 --- a/ldk-server/server/Cargo.toml +++ b/ldk-server/server/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -ldk-node = { git = "https://github.com/lightningdevkit/ldk-node.git", branch = "main" } +ldk-node = { version = "0.4.0", default-features = false } serde = { version = "1.0.203", default-features = false, features = ["derive"] } serde_json = { version = "1.0.118", default-features = false } hyper = { version = "1", default-features = false, features = ["server", "http1"] } From 3a9f8799291c32ede6cd1ee63bbf217877fa2c03 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:23:10 -0700 Subject: [PATCH 046/203] Proto changes for upgrading LDK-node to v0.4.0 --- ldk-server/protos/src/lib.rs | 19 ++++++++++++----- .../protos/src/proto/ldk_node_server.proto | 21 ++++++++++++------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/protos/src/lib.rs index f20bb9ec3..bfe1ae4d1 100644 --- a/ldk-server/protos/src/lib.rs +++ b/ldk-server/protos/src/lib.rs @@ -16,12 +16,12 @@ pub struct GetNodeInfoResponse { /// Should be always set, will never be `None`. #[prost(message, optional, tag = "3")] pub current_best_block: ::core::option::Option, - /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our Lightning wallet - /// to the chain tip. + /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our Lightning wallet to + /// the chain tip. /// - /// Will be `None` if the wallet hasn’t been synced since the node was initialized. + /// Will be `None` if the wallet hasn't been synced yet. #[prost(uint64, optional, tag = "4")] - pub latest_wallet_sync_timestamp: ::core::option::Option, + pub latest_lightning_wallet_sync_timestamp: ::core::option::Option, /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our on-chain /// wallet to the chain tip. /// @@ -152,6 +152,12 @@ pub struct Bolt12ReceiveRequest { /// The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount offer is returned. #[prost(uint64, optional, tag = "2")] pub amount_msat: ::core::option::Option, + /// Offer expiry time in seconds. + #[prost(uint32, optional, tag = "3")] + pub expiry_secs: ::core::option::Option, + /// If set, it represents the number of items requested, can only be set for fixed-amount offers. + #[prost(uint64, optional, tag = "4")] + pub quantity: ::core::option::Option, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -297,6 +303,9 @@ pub struct CloseChannelRequest { /// Whether to force close the specified channel. #[prost(bool, optional, tag = "3")] pub force_close: ::core::option::Option, + /// The reason for force-closing, can only be set while force closing a channel. + #[prost(string, optional, tag = "4")] + pub force_close_reason: ::core::option::Option<::prost::alloc::string::String>, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -391,7 +400,7 @@ pub struct Channel { pub is_usable: bool, /// Is `true` if this channel is (or will be) publicly-announced #[prost(bool, tag = "15")] - pub is_public: bool, + pub is_announced: bool, /// Set of configurable parameters set by self that affect channel operation. #[prost(message, optional, tag = "16")] pub channel_config: ::core::option::Option, diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index 588a5bf86..4d303936d 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -18,11 +18,11 @@ message GetNodeInfoResponse { // Should be always set, will never be `None`. BestBlock current_best_block = 3; - // The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our Lightning wallet - // to the chain tip. + // The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our Lightning wallet to + // the chain tip. // - // Will be `None` if the wallet hasn’t been synced since the node was initialized. - optional uint64 latest_wallet_sync_timestamp = 4; + // Will be `None` if the wallet hasn't been synced yet. + optional uint64 latest_lightning_wallet_sync_timestamp = 4; // The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our on-chain // wallet to the chain tip. @@ -147,6 +147,12 @@ message Bolt12ReceiveRequest { // The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount offer is returned. optional uint64 amount_msat = 2; + + // Offer expiry time in seconds. + optional uint32 expiry_secs = 3; + + // If set, it represents the number of items requested, can only be set for fixed-amount offers. + optional uint64 quantity = 4; } message Bolt12ReceiveResponse { @@ -273,6 +279,9 @@ message CloseChannelRequest { // Whether to force close the specified channel. optional bool force_close = 3; + + // The reason for force-closing, can only be set while force closing a channel. + optional string force_close_reason = 4; } message CloseChannelResponse { @@ -364,7 +373,7 @@ message Channel { bool is_usable = 14; // Is `true` if this channel is (or will be) publicly-announced - bool is_public = 15; + bool is_announced = 15; // Set of configurable parameters set by self that affect channel operation. ChannelConfig channel_config = 16; @@ -427,11 +436,9 @@ message OutPoint { } message BestBlock { - // The block’s hash string block_hash = 1; // The height at which the block was confirmed. uint32 height = 2; - } From 4521fd2860011c7fb22a16b9154c61fbe3f10703 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:23:58 -0700 Subject: [PATCH 047/203] Adjust for node interface change in ldk-node upgrade. --- ldk-server/server/src/main.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ldk-server/server/src/main.rs b/ldk-server/server/src/main.rs index 0bebbdc4d..4615b02f2 100644 --- a/ldk-server/server/src/main.rs +++ b/ldk-server/server/src/main.rs @@ -6,7 +6,7 @@ use crate::service::NodeService; use ldk_node::bitcoin::Network; use ldk_node::lightning::ln::msgs::SocketAddress; -use ldk_node::{Builder, Config, Event, LogLevel}; +use ldk_node::{Builder, Event, LogLevel}; use tokio::net::TcpListener; use tokio::signal::unix::SignalKind; @@ -14,6 +14,7 @@ use tokio::signal::unix::SignalKind; use hyper::server::conn::http1; use hyper_util::rt::TokioIo; +use ldk_node::config::Config; use std::net::SocketAddr; use std::str::FromStr; use std::sync::Arc; @@ -58,7 +59,7 @@ fn main() { }; let mut builder = Builder::from_config(config); - builder.set_esplora_server(args[5].clone()); + builder.set_chain_source_esplora(args[5].clone(), None); let runtime = match tokio::runtime::Builder::new_multi_thread().enable_all().build() { Ok(runtime) => Arc::new(runtime), From b86615e559945901d8ac7a1b1b84eeeaa4d36a6b Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:25:10 -0700 Subject: [PATCH 048/203] Adjust for ChannelConfig interface change in ldk-node upgrade. --- ldk-server/server/src/util/proto_adapter.rs | 30 +++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/ldk-server/server/src/util/proto_adapter.rs b/ldk-server/server/src/util/proto_adapter.rs index 09d5fc944..55d64370c 100644 --- a/ldk-server/server/src/util/proto_adapter.rs +++ b/ldk-server/server/src/util/proto_adapter.rs @@ -1,6 +1,8 @@ use hex::prelude::*; -use ldk_node::{ChannelConfig, ChannelDetails}; +use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; +use ldk_node::ChannelDetails; use protos::{Channel, OutPoint}; + pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { Channel { channel_id: channel.channel_id.0.to_lower_hex_string(), @@ -19,8 +21,8 @@ pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { is_outbound: channel.is_outbound, is_channel_ready: channel.is_channel_ready, is_usable: channel.is_usable, - is_public: channel.is_public, - channel_config: Some(channel_config_to_proto(channel.config.as_ref())), + is_announced: channel.is_announced, + channel_config: Some(channel_config_to_proto(channel.config)), next_outbound_htlc_limit_msat: channel.next_outbound_htlc_limit_msat, next_outbound_htlc_minimum_msat: channel.next_outbound_htlc_minimum_msat, force_close_spend_delay: channel.force_close_spend_delay.map(|x| x as u32), @@ -38,18 +40,24 @@ pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { } } -pub(crate) fn channel_config_to_proto(channel_config: &ChannelConfig) -> protos::ChannelConfig { +pub(crate) fn channel_config_to_proto(channel_config: ChannelConfig) -> protos::ChannelConfig { protos::ChannelConfig { forwarding_fee_proportional_millionths: Some( - channel_config.forwarding_fee_proportional_millionths(), + channel_config.forwarding_fee_proportional_millionths, ), - forwarding_fee_base_msat: Some(channel_config.forwarding_fee_base_msat()), - cltv_expiry_delta: Some(channel_config.cltv_expiry_delta() as u32), + forwarding_fee_base_msat: Some(channel_config.forwarding_fee_base_msat), + cltv_expiry_delta: Some(channel_config.cltv_expiry_delta as u32), force_close_avoidance_max_fee_satoshis: Some( - channel_config.force_close_avoidance_max_fee_satoshis(), + channel_config.force_close_avoidance_max_fee_satoshis, ), - accept_underpaying_htlcs: Some(channel_config.accept_underpaying_htlcs()), - // FIXME: Pending ldk-node upgrade. - max_dust_htlc_exposure: None, + accept_underpaying_htlcs: Some(channel_config.accept_underpaying_htlcs), + max_dust_htlc_exposure: match channel_config.max_dust_htlc_exposure { + MaxDustHTLCExposure::FixedLimit { limit_msat } => { + Some(protos::channel_config::MaxDustHtlcExposure::FixedLimitMsat(limit_msat)) + }, + MaxDustHTLCExposure::FeeRateMultiplier { multiplier } => { + Some(protos::channel_config::MaxDustHtlcExposure::FeeRateMultiplier(multiplier)) + }, + }, } } From e1ce66955f73e962bc0037e70d9040512c17439e Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:26:03 -0700 Subject: [PATCH 049/203] Adjust OpenChannel for interface change in ldk-node upgrade. --- ldk-server/server/src/api/open_channel.rs | 29 ++++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/ldk-server/server/src/api/open_channel.rs b/ldk-server/server/src/api/open_channel.rs index 5bcb6daae..0f744594f 100644 --- a/ldk-server/server/src/api/open_channel.rs +++ b/ldk-server/server/src/api/open_channel.rs @@ -15,15 +15,26 @@ pub(crate) fn handle_open_channel( .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; let address = SocketAddress::from_str(&request.address) .map_err(|_| ldk_node::NodeError::InvalidSocketAddress)?; - let user_channel_id = node.connect_open_channel( - node_id, - address, - request.channel_amount_sats, - request.push_to_counterparty_msat, - // TODO: Allow setting ChannelConfig in open-channel. - None, - request.announce_channel, - )?; + + let user_channel_id = if request.announce_channel { + node.open_announced_channel( + node_id, + address, + request.channel_amount_sats, + request.push_to_counterparty_msat, + // TODO: Allow setting ChannelConfig in open-channel. + None, + )? + } else { + node.open_channel( + node_id, + address, + request.channel_amount_sats, + request.push_to_counterparty_msat, + None, + )? + }; + let response = OpenChannelResponse { user_channel_id: Bytes::from(user_channel_id.0.to_be_bytes().to_vec()), }; From 50aa7c240d38608d4d06d052da17ba0f350adfb8 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:26:39 -0700 Subject: [PATCH 050/203] Adjust GetNodeInfo for interface change in ldk-node upgrade. --- ldk-server/server/src/api/get_node_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/server/src/api/get_node_info.rs b/ldk-server/server/src/api/get_node_info.rs index d98c8f1bb..c221c9ddb 100644 --- a/ldk-server/server/src/api/get_node_info.rs +++ b/ldk-server/server/src/api/get_node_info.rs @@ -17,7 +17,7 @@ pub(crate) fn handle_get_node_info_request( let response = GetNodeInfoResponse { node_id: node.node_id().to_string(), current_best_block: Some(best_block), - latest_wallet_sync_timestamp: node_status.latest_wallet_sync_timestamp, + latest_lightning_wallet_sync_timestamp: node_status.latest_lightning_wallet_sync_timestamp, latest_onchain_wallet_sync_timestamp: node_status.latest_onchain_wallet_sync_timestamp, latest_fee_rate_cache_update_timestamp: node_status.latest_fee_rate_cache_update_timestamp, latest_rgs_snapshot_timestamp: node_status.latest_rgs_snapshot_timestamp, From 0ce52e621e10731ee39adf2e51ca3a6fd5248606 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:27:03 -0700 Subject: [PATCH 051/203] Adjust CloseChannel for interface change in ldk-node upgrade. --- ldk-server/server/src/api/close_channel.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ldk-server/server/src/api/close_channel.rs b/ldk-server/server/src/api/close_channel.rs index 73e0d5caf..2d58bc1c8 100644 --- a/ldk-server/server/src/api/close_channel.rs +++ b/ldk-server/server/src/api/close_channel.rs @@ -17,7 +17,11 @@ pub(crate) fn handle_close_channel_request( .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; match request.force_close { - Some(true) => node.force_close_channel(&user_channel_id, counterparty_node_id)?, + Some(true) => node.force_close_channel( + &user_channel_id, + counterparty_node_id, + request.force_close_reason, + )?, _ => node.close_channel(&user_channel_id, counterparty_node_id)?, }; From 5be1fadd3190cc865c694c5834b0324ec09c7c26 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:27:37 -0700 Subject: [PATCH 052/203] Adjust Bolt11Send for interface change in ldk-node upgrade. --- ldk-server/server/src/api/bolt11_send.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ldk-server/server/src/api/bolt11_send.rs b/ldk-server/server/src/api/bolt11_send.rs index a5d41e824..fc3e09bf0 100644 --- a/ldk-server/server/src/api/bolt11_send.rs +++ b/ldk-server/server/src/api/bolt11_send.rs @@ -14,8 +14,8 @@ pub(crate) fn handle_bolt11_send_request( .map_err(|_| ldk_node::NodeError::InvalidInvoice)?; let payment_id = match request.amount_msat { - None => node.bolt11_payment().send(&invoice), - Some(amount_msat) => node.bolt11_payment().send_using_amount(&invoice, amount_msat), + None => node.bolt11_payment().send(&invoice, None), + Some(amount_msat) => node.bolt11_payment().send_using_amount(&invoice, amount_msat, None), }?; let response = Bolt11SendResponse { payment_id: Bytes::from(payment_id.0.to_vec()) }; From 8f6451203200aa5e1cb76e39b3270a52e7e5ab41 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:27:59 -0700 Subject: [PATCH 053/203] Adjust Bolt11Receive for interface change in ldk-node upgrade. --- ldk-server/server/src/api/bolt12_receive.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ldk-server/server/src/api/bolt12_receive.rs b/ldk-server/server/src/api/bolt12_receive.rs index 9a5ae79bd..203a81fc9 100644 --- a/ldk-server/server/src/api/bolt12_receive.rs +++ b/ldk-server/server/src/api/bolt12_receive.rs @@ -8,8 +8,15 @@ pub(crate) fn handle_bolt12_receive_request( node: Arc, request: Bolt12ReceiveRequest, ) -> Result { let offer = match request.amount_msat { - Some(amount_msat) => node.bolt12_payment().receive(amount_msat, &request.description)?, - None => node.bolt12_payment().receive_variable_amount(&request.description)?, + Some(amount_msat) => node.bolt12_payment().receive( + amount_msat, + &request.description, + request.expiry_secs, + request.quantity, + )?, + None => node + .bolt12_payment() + .receive_variable_amount(&request.description, request.expiry_secs)?, }; let response = Bolt12ReceiveResponse { offer: offer.to_string() }; From cd27125cd967bf43f4db99d14e738406ace2ec04 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:28:44 -0700 Subject: [PATCH 054/203] Adjust Bolt12Send for interface change in ldk-node upgrade. --- ldk-server/server/src/api/bolt12_send.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ldk-server/server/src/api/bolt12_send.rs b/ldk-server/server/src/api/bolt12_send.rs index 8718e0ab0..8a0982338 100644 --- a/ldk-server/server/src/api/bolt12_send.rs +++ b/ldk-server/server/src/api/bolt12_send.rs @@ -14,10 +14,13 @@ pub(crate) fn handle_bolt12_send_request( Offer::from_str(&request.offer.as_str()).map_err(|_| ldk_node::NodeError::InvalidOffer)?; let payment_id = match request.amount_msat { - None => node.bolt12_payment().send(&offer, request.payer_note), - Some(amount_msat) => { - node.bolt12_payment().send_using_amount(&offer, request.payer_note, amount_msat) - }, + None => node.bolt12_payment().send(&offer, request.quantity, request.payer_note), + Some(amount_msat) => node.bolt12_payment().send_using_amount( + &offer, + amount_msat, + request.quantity, + request.payer_note, + ), }?; let response = Bolt12SendResponse { payment_id: Bytes::from(payment_id.0.to_vec()) }; From a666dc9f5dd1b14097344e4585d6cd35cd01f731 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:29:16 -0700 Subject: [PATCH 055/203] Cli interface change for ldk-node upgrade. --- ldk-server/cli/src/main.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ldk-server/cli/src/main.rs b/ldk-server/cli/src/main.rs index cf97a7764..0db105dee 100644 --- a/ldk-server/cli/src/main.rs +++ b/ldk-server/cli/src/main.rs @@ -46,6 +46,10 @@ enum Commands { description: String, #[arg(long)] amount_msat: Option, + #[arg(long)] + expiry_secs: Option, + #[arg(long)] + quantity: Option, }, Bolt12Send { #[arg(short, long)] @@ -95,9 +99,16 @@ async fn main() { Commands::Bolt11Send { invoice, amount_msat } => { handle_response(client.bolt11_send(Bolt11SendRequest { invoice, amount_msat }).await); }, - Commands::Bolt12Receive { description, amount_msat } => { + Commands::Bolt12Receive { description, amount_msat, expiry_secs, quantity } => { handle_response( - client.bolt12_receive(Bolt12ReceiveRequest { description, amount_msat }).await, + client + .bolt12_receive(Bolt12ReceiveRequest { + description, + amount_msat, + expiry_secs, + quantity, + }) + .await, ); }, Commands::Bolt12Send { offer, amount_msat, quantity, payer_note } => { From 7f1e2a3fbf0c7952ed98ebf9d93774885a60e87d Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Sun, 13 Oct 2024 19:47:58 -0700 Subject: [PATCH 056/203] Add proto for GetPaymentDetails api. --- ldk-server/protos/src/lib.rs | 246 ++++++++++++++++++ .../protos/src/proto/ldk_node_server.proto | 173 ++++++++++++ 2 files changed, 419 insertions(+) diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/protos/src/lib.rs index bfe1ae4d1..5dcda4f3f 100644 --- a/ldk-server/protos/src/lib.rs +++ b/ldk-server/protos/src/lib.rs @@ -322,6 +322,190 @@ pub struct ListChannelsResponse { #[prost(message, repeated, tag = "1")] pub channels: ::prost::alloc::vec::Vec, } +/// Returns payment details for a given payment_id. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPaymentDetailsRequest { + /// An identifier used to uniquely identify a payment in hex-encoded form. + #[prost(string, tag = "1")] + pub payment_id: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPaymentDetailsResponse { + /// Represents a payment. + /// Will be `None` if payment doesn't exist. + #[prost(message, optional, tag = "1")] + pub payment: ::core::option::Option, +} +/// Represents a payment. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Payment { + /// An identifier used to uniquely identify a payment in hex-encoded form. + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + /// The kind of the payment. + #[prost(message, optional, tag = "2")] + pub kind: ::core::option::Option, + /// The amount transferred. + #[prost(uint64, optional, tag = "3")] + pub amount_msat: ::core::option::Option, + /// The direction of the payment. + #[prost(enumeration = "PaymentDirection", tag = "4")] + pub direction: i32, + /// The status of the payment. + #[prost(enumeration = "PaymentStatus", tag = "5")] + pub status: i32, + /// The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. + #[prost(uint64, tag = "6")] + pub latest_update_timestamp: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PaymentKind { + #[prost(oneof = "payment_kind::Kind", tags = "1, 2, 3, 4, 5, 6")] + pub kind: ::core::option::Option, +} +/// Nested message and enum types in `PaymentKind`. +pub mod payment_kind { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Kind { + #[prost(message, tag = "1")] + Onchain(super::Onchain), + #[prost(message, tag = "2")] + Bolt11(super::Bolt11), + #[prost(message, tag = "3")] + Bolt11Jit(super::Bolt11Jit), + #[prost(message, tag = "4")] + Bolt12Offer(super::Bolt12Offer), + #[prost(message, tag = "5")] + Bolt12Refund(super::Bolt12Refund), + #[prost(message, tag = "6")] + Spontaneous(super::Spontaneous), + } +} +/// Represents an on-chain payment. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Onchain {} +/// Represents a BOLT 11 payment. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11 { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, tag = "1")] + pub hash: ::prost::alloc::string::String, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, + /// The secret used by the payment. + #[prost(bytes = "bytes", optional, tag = "3")] + pub secret: ::core::option::Option<::prost::bytes::Bytes>, +} +/// Represents a BOLT 11 payment intended to open an LSPS 2 just-in-time channel. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11Jit { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, tag = "1")] + pub hash: ::prost::alloc::string::String, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, + /// The secret used by the payment. + #[prost(bytes = "bytes", optional, tag = "3")] + pub secret: ::core::option::Option<::prost::bytes::Bytes>, + /// Limits applying to how much fee we allow an LSP to deduct from the payment amount. + /// + /// Allowing them to deduct this fee from the first inbound payment will pay for the LSP’s channel opening fees. + /// + /// See \[`LdkChannelConfig::accept_underpaying_htlcs`\]() + /// for more information. + #[prost(message, optional, tag = "4")] + pub lsp_fee_limits: ::core::option::Option, +} +/// Represents a BOLT 12 ‘offer’ payment, i.e., a payment for an Offer. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12Offer { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, optional, tag = "1")] + pub hash: ::core::option::Option<::prost::alloc::string::String>, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, + /// The secret used by the payment. + #[prost(bytes = "bytes", optional, tag = "3")] + pub secret: ::core::option::Option<::prost::bytes::Bytes>, + /// The hex-encoded ID of the offer this payment is for. + #[prost(string, tag = "4")] + pub offer_id: ::prost::alloc::string::String, + /// The payer's note for the payment. + /// Truncated to \[PAYER_NOTE_LIMIT\](). + /// + /// **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, + /// all non-printable characters will be sanitized and replaced with safe characters. + #[prost(string, optional, tag = "5")] + pub payer_note: ::core::option::Option<::prost::alloc::string::String>, + /// The quantity of an item requested in the offer. + #[prost(uint64, optional, tag = "6")] + pub quantity: ::core::option::Option, +} +/// Represents a BOLT 12 ‘refund’ payment, i.e., a payment for a Refund. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12Refund { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, optional, tag = "1")] + pub hash: ::core::option::Option<::prost::alloc::string::String>, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, + /// The secret used by the payment. + #[prost(bytes = "bytes", optional, tag = "3")] + pub secret: ::core::option::Option<::prost::bytes::Bytes>, + /// The payer's note for the payment. + /// Truncated to \[PAYER_NOTE_LIMIT\](). + /// + /// **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, + /// all non-printable characters will be sanitized and replaced with safe characters. + #[prost(string, optional, tag = "5")] + pub payer_note: ::core::option::Option<::prost::alloc::string::String>, + /// The quantity of an item requested in the offer. + #[prost(uint64, optional, tag = "6")] + pub quantity: ::core::option::Option, +} +/// Represents a spontaneous (“keysend”) payment. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Spontaneous { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, tag = "1")] + pub hash: ::prost::alloc::string::String, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, +} +/// Limits applying to how much fee we allow an LSP to deduct from the payment amount. +/// See \[`LdkChannelConfig::accept_underpaying_htlcs`\] for more information. +/// +/// \[`LdkChannelConfig::accept_underpaying_htlcs`\]: lightning::util::config::ChannelConfig::accept_underpaying_htlcs +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LspFeeLimits { + /// The maximal total amount we allow any configured LSP withhold from us when forwarding the + /// payment. + #[prost(uint64, optional, tag = "1")] + pub max_total_opening_fee_msat: ::core::option::Option, + /// The maximal proportional fee, in parts-per-million millisatoshi, we allow any configured + /// LSP withhold from us when forwarding the payment. + #[prost(uint64, optional, tag = "2")] + pub max_proportional_opening_fee_ppm_msat: ::core::option::Option, +} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Channel { @@ -473,3 +657,65 @@ pub struct BestBlock { #[prost(uint32, tag = "2")] pub height: u32, } +/// Represents the direction of a payment. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum PaymentDirection { + /// The payment is inbound. + Inbound = 0, + /// The payment is outbound. + Outbound = 1, +} +impl PaymentDirection { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + PaymentDirection::Inbound => "INBOUND", + PaymentDirection::Outbound => "OUTBOUND", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "INBOUND" => Some(Self::Inbound), + "OUTBOUND" => Some(Self::Outbound), + _ => None, + } + } +} +/// Represents the current status of a payment. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum PaymentStatus { + /// The payment is still pending. + Pending = 0, + /// The payment succeeded. + Succeeded = 1, + /// The payment failed. + Failed = 2, +} +impl PaymentStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + PaymentStatus::Pending => "PENDING", + PaymentStatus::Succeeded => "SUCCEEDED", + PaymentStatus::Failed => "FAILED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "PENDING" => Some(Self::Pending), + "SUCCEEDED" => Some(Self::Succeeded), + "FAILED" => Some(Self::Failed), + _ => None, + } + } +} diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index 4d303936d..411e46b1f 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -298,6 +298,179 @@ message ListChannelsResponse { repeated Channel channels = 1; } +// Returns payment details for a given payment_id. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.payment +message GetPaymentDetailsRequest { + // An identifier used to uniquely identify a payment in hex-encoded form. + string payment_id = 1; +} + +message GetPaymentDetailsResponse { + // Represents a payment. + // Will be `None` if payment doesn't exist. + Payment payment = 1; +} + +// Represents a payment. +// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.PaymentDetails.html +message Payment { + // An identifier used to uniquely identify a payment in hex-encoded form. + string id = 1; + + // The kind of the payment. + PaymentKind kind = 2; + + // The amount transferred. + optional uint64 amount_msat = 3; + + // The direction of the payment. + PaymentDirection direction = 4; + + // The status of the payment. + PaymentStatus status = 5; + + // The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. + uint64 latest_update_timestamp = 6; +} + +message PaymentKind { + oneof kind { + Onchain onchain = 1; + Bolt11 bolt11 = 2; + Bolt11Jit bolt11_jit = 3; + Bolt12Offer bolt12_offer = 4; + Bolt12Refund bolt12_refund = 5; + Spontaneous spontaneous = 6; + } +} + +// Represents an on-chain payment. +message Onchain {} + +// Represents a BOLT 11 payment. +message Bolt11 { + // The payment hash, i.e., the hash of the preimage. + string hash = 1; + + // The pre-image used by the payment. + optional string preimage = 2; + + // The secret used by the payment. + optional bytes secret = 3; +} + +// Represents a BOLT 11 payment intended to open an LSPS 2 just-in-time channel. +message Bolt11Jit { + // The payment hash, i.e., the hash of the preimage. + string hash = 1; + + // The pre-image used by the payment. + optional string preimage = 2; + + // The secret used by the payment. + optional bytes secret = 3; + + // Limits applying to how much fee we allow an LSP to deduct from the payment amount. + // + // Allowing them to deduct this fee from the first inbound payment will pay for the LSP’s channel opening fees. + // + // See [`LdkChannelConfig::accept_underpaying_htlcs`](https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.accept_underpaying_htlcs) + // for more information. + LSPFeeLimits lsp_fee_limits = 4; +} + +// Represents a BOLT 12 ‘offer’ payment, i.e., a payment for an Offer. +message Bolt12Offer { + // The payment hash, i.e., the hash of the preimage. + optional string hash = 1; + + // The pre-image used by the payment. + optional string preimage = 2; + + // The secret used by the payment. + optional bytes secret = 3; + + // The hex-encoded ID of the offer this payment is for. + string offer_id = 4; + + // The payer's note for the payment. + // Truncated to [PAYER_NOTE_LIMIT](https://docs.rs/lightning/latest/lightning/offers/invoice_request/constant.PAYER_NOTE_LIMIT.html). + // + // **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, + // all non-printable characters will be sanitized and replaced with safe characters. + optional string payer_note = 5; + + // The quantity of an item requested in the offer. + optional uint64 quantity = 6; +} + +// Represents a BOLT 12 ‘refund’ payment, i.e., a payment for a Refund. +message Bolt12Refund { + // The payment hash, i.e., the hash of the preimage. + optional string hash = 1; + + // The pre-image used by the payment. + optional string preimage = 2; + + // The secret used by the payment. + optional bytes secret = 3; + + // The payer's note for the payment. + // Truncated to [PAYER_NOTE_LIMIT](https://docs.rs/lightning/latest/lightning/offers/invoice_request/constant.PAYER_NOTE_LIMIT.html). + // + // **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, + // all non-printable characters will be sanitized and replaced with safe characters. + optional string payer_note = 5; + + // The quantity of an item requested in the offer. + optional uint64 quantity = 6; + +} + +// Represents a spontaneous (“keysend”) payment. +message Spontaneous { + // The payment hash, i.e., the hash of the preimage. + string hash = 1; + + // The pre-image used by the payment. + optional string preimage = 2; +} + +// Limits applying to how much fee we allow an LSP to deduct from the payment amount. +// See [`LdkChannelConfig::accept_underpaying_htlcs`] for more information. +// +// [`LdkChannelConfig::accept_underpaying_htlcs`]: lightning::util::config::ChannelConfig::accept_underpaying_htlcs +message LSPFeeLimits { + // The maximal total amount we allow any configured LSP withhold from us when forwarding the + // payment. + optional uint64 max_total_opening_fee_msat = 1; + + // The maximal proportional fee, in parts-per-million millisatoshi, we allow any configured + // LSP withhold from us when forwarding the payment. + optional uint64 max_proportional_opening_fee_ppm_msat = 2; +} + +// Represents the direction of a payment. +enum PaymentDirection { + // The payment is inbound. + INBOUND = 0; + + // The payment is outbound. + OUTBOUND = 1; +} + +// Represents the current status of a payment. +enum PaymentStatus { + // The payment is still pending. + PENDING = 0; + + // The payment succeeded. + SUCCEEDED = 1; + + // The payment failed. + FAILED = 2; +} + message Channel { // The channel ID (prior to funding transaction generation, this is a random 32-byte // identifier, afterwards this is the transaction ID of the funding transaction XOR the From 15a59ce1a7d358012de630e41070289e2f092755 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Sun, 13 Oct 2024 19:50:26 -0700 Subject: [PATCH 057/203] Add proto for ListPayments api. --- ldk-server/protos/src/lib.rs | 12 ++++++++++++ ldk-server/protos/src/proto/ldk_node_server.proto | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/protos/src/lib.rs index 5dcda4f3f..bd29df43b 100644 --- a/ldk-server/protos/src/lib.rs +++ b/ldk-server/protos/src/lib.rs @@ -339,6 +339,18 @@ pub struct GetPaymentDetailsResponse { #[prost(message, optional, tag = "1")] pub payment: ::core::option::Option, } +/// Retrieves list of all payments. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListPaymentsRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListPaymentsResponse { + /// List of payments. + #[prost(message, repeated, tag = "1")] + pub payments: ::prost::alloc::vec::Vec, +} /// Represents a payment. /// See more: #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index 411e46b1f..79d935ac9 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -311,6 +311,15 @@ message GetPaymentDetailsResponse { Payment payment = 1; } +// Retrieves list of all payments. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_payments +message ListPaymentsRequest {} + +message ListPaymentsResponse { + // List of payments. + repeated Payment payments = 1; +} + // Represents a payment. // See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.PaymentDetails.html message Payment { From aafab22a1c521cf37746d09b8600a91ecdcce34d Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Mon, 14 Oct 2024 00:04:00 -0700 Subject: [PATCH 058/203] Add Impl for GetPaymentDetails Api --- .../server/src/api/get_payment_details.rs | 23 ++++++ ldk-server/server/src/api/mod.rs | 1 + ldk-server/server/src/service.rs | 6 ++ ldk-server/server/src/util/proto_adapter.rs | 79 ++++++++++++++++++- 4 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 ldk-server/server/src/api/get_payment_details.rs diff --git a/ldk-server/server/src/api/get_payment_details.rs b/ldk-server/server/src/api/get_payment_details.rs new file mode 100644 index 000000000..52008a3c4 --- /dev/null +++ b/ldk-server/server/src/api/get_payment_details.rs @@ -0,0 +1,23 @@ +use crate::util::proto_adapter::payment_to_proto; +use hex::FromHex; +use ldk_node::lightning::ln::channelmanager::PaymentId; +use ldk_node::Node; +use protos::{GetPaymentDetailsRequest, GetPaymentDetailsResponse}; +use std::sync::Arc; + +pub(crate) const GET_PAYMENT_DETAILS_PATH: &str = "GetPaymentDetails"; + +pub(crate) fn handle_get_payment_details_request( + node: Arc, request: GetPaymentDetailsRequest, +) -> Result { + let payment_id_bytes = <[u8; PaymentId::LENGTH]>::from_hex(&request.payment_id) + .map_err(|_| ldk_node::NodeError::InvalidPaymentId)?; + + let payment_details = node.payment(&PaymentId(payment_id_bytes)); + + let response = GetPaymentDetailsResponse { + payment: payment_details.map(|payment| payment_to_proto(payment)), + }; + + Ok(response) +} diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs index 6355e9de8..0ce3e717b 100644 --- a/ldk-server/server/src/api/mod.rs +++ b/ldk-server/server/src/api/mod.rs @@ -4,6 +4,7 @@ pub(crate) mod bolt12_receive; pub(crate) mod bolt12_send; pub(crate) mod close_channel; pub(crate) mod get_node_info; +pub(crate) mod get_payment_details; pub(crate) mod list_channels; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index 15eaa7931..2c66809fa 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -17,6 +17,9 @@ use crate::api::bolt12_receive::{handle_bolt12_receive_request, BOLT12_RECEIVE_P use crate::api::bolt12_send::{handle_bolt12_send_request, BOLT12_SEND_PATH}; use crate::api::close_channel::{handle_close_channel_request, CLOSE_CHANNEL_PATH}; use crate::api::get_node_info::{handle_get_node_info_request, GET_NODE_INFO}; +use crate::api::get_payment_details::{ + handle_get_payment_details_request, GET_PAYMENT_DETAILS_PATH, +}; use crate::api::list_channels::{handle_list_channels_request, LIST_CHANNELS_PATH}; use crate::api::onchain_receive::{handle_onchain_receive_request, ONCHAIN_RECEIVE_PATH}; use crate::api::onchain_send::{handle_onchain_send_request, ONCHAIN_SEND_PATH}; @@ -58,6 +61,9 @@ impl Service> for NodeService { OPEN_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_open_channel)), CLOSE_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_close_channel_request)), LIST_CHANNELS_PATH => Box::pin(handle_request(node, req, handle_list_channels_request)), + GET_PAYMENT_DETAILS_PATH => { + Box::pin(handle_request(node, req, handle_get_payment_details_request)) + }, path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async { diff --git a/ldk-server/server/src/util/proto_adapter.rs b/ldk-server/server/src/util/proto_adapter.rs index 55d64370c..9f9efe73d 100644 --- a/ldk-server/server/src/util/proto_adapter.rs +++ b/ldk-server/server/src/util/proto_adapter.rs @@ -1,7 +1,12 @@ +use bytes::Bytes; use hex::prelude::*; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; +use ldk_node::payment::{PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus}; use ldk_node::ChannelDetails; -use protos::{Channel, OutPoint}; +use protos::payment_kind::Kind::{ + Bolt11, Bolt11Jit, Bolt12Offer, Bolt12Refund, Onchain, Spontaneous, +}; +use protos::{Channel, LspFeeLimits, OutPoint, Payment}; pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { Channel { @@ -61,3 +66,75 @@ pub(crate) fn channel_config_to_proto(channel_config: ChannelConfig) -> protos:: }, } } + +pub(crate) fn payment_to_proto(payment: PaymentDetails) -> Payment { + Payment { + id: payment.id.0.to_lower_hex_string(), + kind: Some(payment_kind_to_proto(payment.kind)), + amount_msat: payment.amount_msat, + direction: match payment.direction { + PaymentDirection::Inbound => protos::PaymentDirection::Inbound.into(), + PaymentDirection::Outbound => protos::PaymentDirection::Outbound.into(), + }, + status: match payment.status { + PaymentStatus::Pending => protos::PaymentStatus::Pending.into(), + PaymentStatus::Succeeded => protos::PaymentStatus::Succeeded.into(), + PaymentStatus::Failed => protos::PaymentStatus::Failed.into(), + }, + latest_update_timestamp: payment.latest_update_timestamp, + } +} + +pub(crate) fn payment_kind_to_proto(payment_kind: PaymentKind) -> protos::PaymentKind { + match payment_kind { + PaymentKind::Onchain => protos::PaymentKind { kind: Some(Onchain(protos::Onchain {})) }, + PaymentKind::Bolt11 { hash, preimage, secret } => protos::PaymentKind { + kind: Some(Bolt11(protos::Bolt11 { + hash: hash.to_string(), + preimage: preimage.map(|p| p.to_string()), + secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), + })), + }, + PaymentKind::Bolt11Jit { hash, preimage, secret, lsp_fee_limits } => protos::PaymentKind { + kind: Some(Bolt11Jit(protos::Bolt11Jit { + hash: hash.to_string(), + preimage: preimage.map(|p| p.to_string()), + secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), + lsp_fee_limits: Some(LspFeeLimits { + max_total_opening_fee_msat: lsp_fee_limits.max_total_opening_fee_msat, + max_proportional_opening_fee_ppm_msat: lsp_fee_limits + .max_proportional_opening_fee_ppm_msat, + }), + })), + }, + PaymentKind::Bolt12Offer { hash, preimage, secret, offer_id, payer_note, quantity } => { + protos::PaymentKind { + kind: Some(Bolt12Offer(protos::Bolt12Offer { + hash: hash.map(|h| h.to_string()), + preimage: preimage.map(|p| p.to_string()), + secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), + offer_id: offer_id.0.to_lower_hex_string(), + payer_note: payer_note.map(|s| s.to_string()), + quantity, + })), + } + }, + PaymentKind::Bolt12Refund { hash, preimage, secret, payer_note, quantity } => { + protos::PaymentKind { + kind: Some(Bolt12Refund(protos::Bolt12Refund { + hash: hash.map(|h| h.to_string()), + preimage: preimage.map(|p| p.to_string()), + secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), + payer_note: payer_note.map(|s| s.to_string()), + quantity, + })), + } + }, + PaymentKind::Spontaneous { hash, preimage } => protos::PaymentKind { + kind: Some(Spontaneous(protos::Spontaneous { + hash: hash.to_string(), + preimage: preimage.map(|p| p.to_string()), + })), + }, + } +} From 02e9634b928f786b0c5e4b2f26328b2c27ef96be Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Mon, 14 Oct 2024 00:08:29 -0700 Subject: [PATCH 059/203] Add Impl for ListPayments Api --- ldk-server/server/src/api/list_payments.rs | 15 +++++++++++++++ ldk-server/server/src/api/mod.rs | 1 + ldk-server/server/src/service.rs | 2 ++ 3 files changed, 18 insertions(+) create mode 100644 ldk-server/server/src/api/list_payments.rs diff --git a/ldk-server/server/src/api/list_payments.rs b/ldk-server/server/src/api/list_payments.rs new file mode 100644 index 000000000..2667d58f4 --- /dev/null +++ b/ldk-server/server/src/api/list_payments.rs @@ -0,0 +1,15 @@ +use crate::util::proto_adapter::payment_to_proto; +use ldk_node::Node; +use protos::{ListPaymentsRequest, ListPaymentsResponse}; +use std::sync::Arc; + +pub(crate) const LIST_PAYMENTS_PATH: &str = "ListPayments"; + +pub(crate) fn handle_list_payments_request( + node: Arc, _request: ListPaymentsRequest, +) -> Result { + let payments = node.list_payments().into_iter().map(|p| payment_to_proto(p)).collect(); + + let response = ListPaymentsResponse { payments }; + Ok(response) +} diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs index 0ce3e717b..c1079f2f2 100644 --- a/ldk-server/server/src/api/mod.rs +++ b/ldk-server/server/src/api/mod.rs @@ -6,6 +6,7 @@ pub(crate) mod close_channel; pub(crate) mod get_node_info; pub(crate) mod get_payment_details; pub(crate) mod list_channels; +pub(crate) mod list_payments; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; pub(crate) mod open_channel; diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index 2c66809fa..510131d0e 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -21,6 +21,7 @@ use crate::api::get_payment_details::{ handle_get_payment_details_request, GET_PAYMENT_DETAILS_PATH, }; use crate::api::list_channels::{handle_list_channels_request, LIST_CHANNELS_PATH}; +use crate::api::list_payments::{handle_list_payments_request, LIST_PAYMENTS_PATH}; use crate::api::onchain_receive::{handle_onchain_receive_request, ONCHAIN_RECEIVE_PATH}; use crate::api::onchain_send::{handle_onchain_send_request, ONCHAIN_SEND_PATH}; use crate::api::open_channel::{handle_open_channel, OPEN_CHANNEL_PATH}; @@ -64,6 +65,7 @@ impl Service> for NodeService { GET_PAYMENT_DETAILS_PATH => { Box::pin(handle_request(node, req, handle_get_payment_details_request)) }, + LIST_PAYMENTS_PATH => Box::pin(handle_request(node, req, handle_list_payments_request)), path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async { From 34f01e5d5be2d193f0ec3d2ac6be1357efaa8506 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:00:38 -0700 Subject: [PATCH 060/203] Add proto for UpdateChannelConfig api. --- ldk-server/protos/src/lib.rs | 18 ++++++++++++++++++ .../protos/src/proto/ldk_node_server.proto | 17 +++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/protos/src/lib.rs index bd29df43b..87af55e28 100644 --- a/ldk-server/protos/src/lib.rs +++ b/ldk-server/protos/src/lib.rs @@ -229,6 +229,24 @@ pub struct OpenChannelResponse { #[prost(bytes = "bytes", tag = "1")] pub user_channel_id: ::prost::bytes::Bytes, } +/// Update the config for a previously opened channel. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UpdateChannelConfigRequest { + /// The hex-encoded local `user_channel_id` of this channel. + #[prost(string, tag = "1")] + pub user_channel_id: ::prost::alloc::string::String, + /// The hex-encoded public key of the counterparty node to update channel config with. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// The updated channel configuration settings for a channel. + #[prost(message, optional, tag = "3")] + pub channel_config: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UpdateChannelConfigResponse {} /// ChannelConfig represents the configuration settings for a channel in a Lightning Network node. /// See more: #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/ldk_node_server.proto index 79d935ac9..342f704d6 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/ldk_node_server.proto @@ -220,6 +220,23 @@ message OpenChannelResponse { bytes user_channel_id = 1; } +// Update the config for a previously opened channel. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.update_channel_config +message UpdateChannelConfigRequest { + + // The hex-encoded local `user_channel_id` of this channel. + string user_channel_id = 1; + + // The hex-encoded public key of the counterparty node to update channel config with. + string counterparty_node_id = 2; + + // The updated channel configuration settings for a channel. + ChannelConfig channel_config = 3; +} + +message UpdateChannelConfigResponse { +} + // ChannelConfig represents the configuration settings for a channel in a Lightning Network node. // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html message ChannelConfig { From 3ce2d406ee57fc4f1cd062009d7572697a723243 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Mon, 14 Oct 2024 19:04:33 -0700 Subject: [PATCH 061/203] Add impl for UpdateChannelConfig Api. --- ldk-server/server/src/api/mod.rs | 1 + .../server/src/api/update_channel_config.rs | 75 +++++++++++++++++++ ldk-server/server/src/service.rs | 6 ++ 3 files changed, 82 insertions(+) create mode 100644 ldk-server/server/src/api/update_channel_config.rs diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs index c1079f2f2..e7561fd32 100644 --- a/ldk-server/server/src/api/mod.rs +++ b/ldk-server/server/src/api/mod.rs @@ -10,3 +10,4 @@ pub(crate) mod list_payments; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; pub(crate) mod open_channel; +pub(crate) mod update_channel_config; diff --git a/ldk-server/server/src/api/update_channel_config.rs b/ldk-server/server/src/api/update_channel_config.rs new file mode 100644 index 000000000..1f8cec293 --- /dev/null +++ b/ldk-server/server/src/api/update_channel_config.rs @@ -0,0 +1,75 @@ +use ldk_node::bitcoin::secp256k1::PublicKey; +use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; +use ldk_node::{Node, UserChannelId}; +use protos::channel_config::MaxDustHtlcExposure; +use protos::{UpdateChannelConfigRequest, UpdateChannelConfigResponse}; +use std::str::FromStr; +use std::sync::Arc; + +pub(crate) const UPDATE_CHANNEL_CONFIG_PATH: &str = "UpdateChannelConfig"; + +pub(crate) fn handle_update_channel_config_request( + node: Arc, request: UpdateChannelConfigRequest, +) -> Result { + let user_channel_id: u128 = + request.user_channel_id.parse().map_err(|_| ldk_node::NodeError::InvalidChannelId)?; + + //FIXME: Use ldk/ldk-node's partial config update api. + let current_config = node + .list_channels() + .into_iter() + .find(|c| c.user_channel_id.0 == user_channel_id) + .ok_or_else(|| ldk_node::NodeError::InvalidChannelId)? + .config; + + let updated_channel_config = + build_updated_channel_config(current_config, request.channel_config.unwrap()); + + let counterparty_node_id = PublicKey::from_str(&request.counterparty_node_id) + .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; + node.update_channel_config( + &UserChannelId(user_channel_id), + counterparty_node_id, + updated_channel_config, + ) + .map_err(ldk_node::NodeError::from)?; + + Ok(UpdateChannelConfigResponse {}) +} + +fn build_updated_channel_config( + current_config: ChannelConfig, proto_channel_config: protos::ChannelConfig, +) -> ChannelConfig { + let max_dust_htlc_exposure = proto_channel_config + .max_dust_htlc_exposure + .map(|max_dust_htlc_exposure| match max_dust_htlc_exposure { + MaxDustHtlcExposure::FixedLimitMsat(limit_msat) => { + MaxDustHTLCExposure::FixedLimit { limit_msat } + }, + MaxDustHtlcExposure::FeeRateMultiplier(multiplier) => { + MaxDustHTLCExposure::FeeRateMultiplier { multiplier } + }, + }) + .unwrap_or(current_config.max_dust_htlc_exposure); + + let cltv_expiry_delta = proto_channel_config + .cltv_expiry_delta.map(|c| u16::try_from(c).unwrap()) + .unwrap_or(current_config.cltv_expiry_delta); + + ChannelConfig { + forwarding_fee_proportional_millionths: proto_channel_config + .forwarding_fee_proportional_millionths + .unwrap_or(current_config.forwarding_fee_proportional_millionths), + forwarding_fee_base_msat: proto_channel_config + .forwarding_fee_base_msat + .unwrap_or(current_config.forwarding_fee_base_msat), + cltv_expiry_delta, + max_dust_htlc_exposure, + force_close_avoidance_max_fee_satoshis: proto_channel_config + .force_close_avoidance_max_fee_satoshis + .unwrap_or(current_config.force_close_avoidance_max_fee_satoshis), + accept_underpaying_htlcs: proto_channel_config + .accept_underpaying_htlcs + .unwrap_or(current_config.accept_underpaying_htlcs), + } +} diff --git a/ldk-server/server/src/service.rs b/ldk-server/server/src/service.rs index 510131d0e..b8fb52596 100644 --- a/ldk-server/server/src/service.rs +++ b/ldk-server/server/src/service.rs @@ -25,6 +25,9 @@ use crate::api::list_payments::{handle_list_payments_request, LIST_PAYMENTS_PATH use crate::api::onchain_receive::{handle_onchain_receive_request, ONCHAIN_RECEIVE_PATH}; use crate::api::onchain_send::{handle_onchain_send_request, ONCHAIN_SEND_PATH}; use crate::api::open_channel::{handle_open_channel, OPEN_CHANNEL_PATH}; +use crate::api::update_channel_config::{ + handle_update_channel_config_request, UPDATE_CHANNEL_CONFIG_PATH, +}; #[derive(Clone)] pub struct NodeService { @@ -62,6 +65,9 @@ impl Service> for NodeService { OPEN_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_open_channel)), CLOSE_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_close_channel_request)), LIST_CHANNELS_PATH => Box::pin(handle_request(node, req, handle_list_channels_request)), + UPDATE_CHANNEL_CONFIG_PATH => { + Box::pin(handle_request(node, req, handle_update_channel_config_request)) + }, GET_PAYMENT_DETAILS_PATH => { Box::pin(handle_request(node, req, handle_get_payment_details_request)) }, From b917821dbdbb35ffba8f7c40d95e5ba3b5c66da3 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 29 Oct 2024 23:26:24 -0700 Subject: [PATCH 062/203] Move existing protos to api and types mod. --- ldk-server/protos/build.rs | 8 +- ldk-server/protos/src/api.rs | 313 ++++++++ ldk-server/protos/src/lib.rs | 753 +----------------- ldk-server/protos/src/proto/api.proto | 295 +++++++ .../{ldk_node_server.proto => types.proto} | 383 ++------- ldk-server/protos/src/types.rs | 438 ++++++++++ 6 files changed, 1099 insertions(+), 1091 deletions(-) create mode 100644 ldk-server/protos/src/api.rs create mode 100644 ldk-server/protos/src/proto/api.proto rename ldk-server/protos/src/proto/{ldk_node_server.proto => types.proto} (58%) create mode 100644 ldk-server/protos/src/types.rs diff --git a/ldk-server/protos/build.rs b/ldk-server/protos/build.rs index 5a1a185c8..70ddc33e0 100644 --- a/ldk-server/protos/build.rs +++ b/ldk-server/protos/build.rs @@ -14,9 +14,11 @@ fn main() { fn generate_protos() { prost_build::Config::new() .bytes(&["."]) - .compile_protos(&["src/proto/ldk_node_server.proto"], &["src/"]) + .compile_protos(&["src/proto/api.proto", "src/proto/types.proto"], &["src/proto/"]) .expect("protobuf compilation failed"); println!("OUT_DIR: {}", &env::var("OUT_DIR").unwrap()); - let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("ldk_node_server.rs"); - fs::copy(from_path, "src/lib.rs").unwrap(); + let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("api.rs"); + fs::copy(from_path, "src/api.rs").unwrap(); + let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("types.rs"); + fs::copy(from_path, "src/types.rs").unwrap(); } diff --git a/ldk-server/protos/src/api.rs b/ldk-server/protos/src/api.rs new file mode 100644 index 000000000..1c99ba937 --- /dev/null +++ b/ldk-server/protos/src/api.rs @@ -0,0 +1,313 @@ +/// Retrieve the latest node info like `node_id`, `current_best_block` etc. +/// See more: +/// - +/// - +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetNodeInfoRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetNodeInfoResponse { + /// The hex-encoded `node-id` or public key for our own lightning node. + #[prost(string, tag = "1")] + pub node_id: ::prost::alloc::string::String, + /// The best block to which our Lightning wallet is currently synced. + /// + /// Should be always set, will never be `None`. + #[prost(message, optional, tag = "3")] + pub current_best_block: ::core::option::Option, + /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our Lightning wallet to + /// the chain tip. + /// + /// Will be `None` if the wallet hasn't been synced yet. + #[prost(uint64, optional, tag = "4")] + pub latest_lightning_wallet_sync_timestamp: ::core::option::Option, + /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our on-chain + /// wallet to the chain tip. + /// + /// Will be `None` if the wallet hasn’t been synced since the node was initialized. + #[prost(uint64, optional, tag = "5")] + pub latest_onchain_wallet_sync_timestamp: ::core::option::Option, + /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully update our fee rate cache. + /// + /// Will be `None` if the cache hasn’t been updated since the node was initialized. + #[prost(uint64, optional, tag = "6")] + pub latest_fee_rate_cache_update_timestamp: ::core::option::Option, + /// The timestamp, in seconds since start of the UNIX epoch, when the last rapid gossip sync (RGS) snapshot we + /// successfully applied was generated. + /// + /// Will be `None` if RGS isn’t configured or the snapshot hasn’t been updated since the node was initialized. + #[prost(uint64, optional, tag = "7")] + pub latest_rgs_snapshot_timestamp: ::core::option::Option, + /// The timestamp, in seconds since start of the UNIX epoch, when we last broadcasted a node announcement. + /// + /// Will be `None` if we have no public channels or we haven’t broadcasted since the node was initialized. + #[prost(uint64, optional, tag = "8")] + pub latest_node_announcement_broadcast_timestamp: ::core::option::Option, +} +/// Retrieve a new on-chain funding address. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OnchainReceiveRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OnchainReceiveResponse { + /// A Bitcoin on-chain address. + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, +} +/// Send an on-chain payment to the given address. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OnchainSendRequest { + /// The address to send coins to. + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, + /// The amount in satoshis to send. + /// While sending the specified amount, we will respect any on-chain reserve we need to keep, + /// i.e., won't allow to cut into `total_anchor_channels_reserve_sats`. + /// See more: + #[prost(uint64, optional, tag = "2")] + pub amount_sats: ::core::option::Option, + /// If set, the amount_sats field should be unset. + /// It indicates that node will send full balance to the specified address. + /// + /// Please note that when send_all is used this operation will **not** retain any on-chain reserves, + /// which might be potentially dangerous if you have open Anchor channels for which you can't trust + /// the counterparty to spend the Anchor output after channel closure. + /// See more: + #[prost(bool, optional, tag = "3")] + pub send_all: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OnchainSendResponse { + /// The transaction ID of the broadcasted transaction. + #[prost(string, tag = "1")] + pub txid: ::prost::alloc::string::String, +} +/// Return a BOLT11 payable invoice that can be used to request and receive a payment +/// for the given amount, if specified. +/// The inbound payment will be automatically claimed upon arrival. +/// See more: +/// - +/// - +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11ReceiveRequest { + /// The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount invoice is returned. + #[prost(uint64, optional, tag = "1")] + pub amount_msat: ::core::option::Option, + /// An optional description to attach along with the invoice. + /// Will be set in the description field of the encoded payment request. + #[prost(string, tag = "2")] + pub description: ::prost::alloc::string::String, + /// Invoice expiry time in seconds. + #[prost(uint32, tag = "3")] + pub expiry_secs: u32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11ReceiveResponse { + /// An invoice for a payment within the Lightning Network. + /// With the details of the invoice, the sender has all the data necessary to send a payment + /// to the recipient. + #[prost(string, tag = "1")] + pub invoice: ::prost::alloc::string::String, +} +/// Send a payment for a BOLT11 invoice. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11SendRequest { + /// An invoice for a payment within the Lightning Network. + #[prost(string, tag = "1")] + pub invoice: ::prost::alloc::string::String, + /// Set this field when paying a so-called "zero-amount" invoice, i.e., an invoice that leaves the + /// amount paid to be determined by the user. + /// This operation will fail if the amount specified is less than the value required by the given invoice. + #[prost(uint64, optional, tag = "2")] + pub amount_msat: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11SendResponse { + /// An identifier used to uniquely identify a payment. + #[prost(bytes = "bytes", tag = "1")] + pub payment_id: ::prost::bytes::Bytes, +} +/// Returns a BOLT12 offer for the given amount, if specified. +/// +/// See more: +/// - +/// - +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12ReceiveRequest { + /// An optional description to attach along with the offer. + /// Will be set in the description field of the encoded offer. + #[prost(string, tag = "1")] + pub description: ::prost::alloc::string::String, + /// The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount offer is returned. + #[prost(uint64, optional, tag = "2")] + pub amount_msat: ::core::option::Option, + /// Offer expiry time in seconds. + #[prost(uint32, optional, tag = "3")] + pub expiry_secs: ::core::option::Option, + /// If set, it represents the number of items requested, can only be set for fixed-amount offers. + #[prost(uint64, optional, tag = "4")] + pub quantity: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12ReceiveResponse { + /// An offer for a payment within the Lightning Network. + /// With the details of the offer, the sender has all the data necessary to send a payment + /// to the recipient. + #[prost(string, tag = "1")] + pub offer: ::prost::alloc::string::String, +} +/// Send a payment for a BOLT12 offer. +/// See more: +/// - +/// - +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12SendRequest { + /// An offer for a payment within the Lightning Network. + #[prost(string, tag = "1")] + pub offer: ::prost::alloc::string::String, + /// Set this field when paying a so-called "zero-amount" offer, i.e., an offer that leaves the + /// amount paid to be determined by the user. + /// This operation will fail if the amount specified is less than the value required by the given offer. + #[prost(uint64, optional, tag = "2")] + pub amount_msat: ::core::option::Option, + /// If set, it represents the number of items requested. + #[prost(uint64, optional, tag = "3")] + pub quantity: ::core::option::Option, + /// If set, it will be seen by the recipient and reflected back in the invoice. + #[prost(string, optional, tag = "4")] + pub payer_note: ::core::option::Option<::prost::alloc::string::String>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12SendResponse { + /// An identifier used to uniquely identify a payment. + #[prost(bytes = "bytes", tag = "1")] + pub payment_id: ::prost::bytes::Bytes, +} +/// Creates a new outbound channel to the given remote node. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OpenChannelRequest { + /// The hex-encoded public key of the node to open a channel with. + #[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, + /// The amount of satoshis the caller is willing to commit to the channel. + #[prost(uint64, tag = "3")] + pub channel_amount_sats: u64, + /// The amount of satoshis to push to the remote side as part of the initial commitment state. + #[prost(uint64, optional, tag = "4")] + pub push_to_counterparty_msat: ::core::option::Option, + /// The channel configuration to be used for opening this channel. If unset, default ChannelConfig is used. + #[prost(message, optional, tag = "5")] + pub channel_config: ::core::option::Option, + /// Whether the channel should be public. + #[prost(bool, tag = "6")] + pub announce_channel: bool, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OpenChannelResponse { + /// The channel id of the created channel that user can use to refer to channel. + #[prost(bytes = "bytes", tag = "1")] + pub user_channel_id: ::prost::bytes::Bytes, +} +/// Update the config for a previously opened channel. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UpdateChannelConfigRequest { + /// The hex-encoded local `user_channel_id` of this channel. + #[prost(string, tag = "1")] + pub user_channel_id: ::prost::alloc::string::String, + /// The hex-encoded public key of the counterparty node to update channel config with. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// The updated channel configuration settings for a channel. + #[prost(message, optional, tag = "3")] + pub channel_config: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UpdateChannelConfigResponse {} +/// Closes the channel specified by given request. +/// See more: +/// - +/// - +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CloseChannelRequest { + /// The channel id of the created channel that user can use to refer to channel. + #[prost(bytes = "bytes", tag = "1")] + pub user_channel_id: ::prost::bytes::Bytes, + /// The hex-encoded public key of the node to close a channel with. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// Whether to force close the specified channel. + #[prost(bool, optional, tag = "3")] + pub force_close: ::core::option::Option, + /// The reason for force-closing, can only be set while force closing a channel. + #[prost(string, optional, tag = "4")] + pub force_close_reason: ::core::option::Option<::prost::alloc::string::String>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CloseChannelResponse {} +/// Returns a list of known channels. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListChannelsRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListChannelsResponse { + /// List of channels. + #[prost(message, repeated, tag = "1")] + pub channels: ::prost::alloc::vec::Vec, +} +/// Returns payment details for a given payment_id. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPaymentDetailsRequest { + /// An identifier used to uniquely identify a payment in hex-encoded form. + #[prost(string, tag = "1")] + pub payment_id: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPaymentDetailsResponse { + /// Represents a payment. + /// Will be `None` if payment doesn't exist. + #[prost(message, optional, tag = "1")] + pub payment: ::core::option::Option, +} +/// Retrieves list of all payments. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListPaymentsRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListPaymentsResponse { + /// List of payments. + #[prost(message, repeated, tag = "1")] + pub payments: ::prost::alloc::vec::Vec, +} diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/protos/src/lib.rs index 87af55e28..8389f117b 100644 --- a/ldk-server/protos/src/lib.rs +++ b/ldk-server/protos/src/lib.rs @@ -1,751 +1,2 @@ -/// Retrieve the latest node info like `node_id`, `current_best_block` etc. -/// See more: -/// - -/// - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetNodeInfoRequest {} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetNodeInfoResponse { - /// The hex-encoded `node-id` or public key for our own lightning node. - #[prost(string, tag = "1")] - pub node_id: ::prost::alloc::string::String, - /// The best block to which our Lightning wallet is currently synced. - /// - /// Should be always set, will never be `None`. - #[prost(message, optional, tag = "3")] - pub current_best_block: ::core::option::Option, - /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our Lightning wallet to - /// the chain tip. - /// - /// Will be `None` if the wallet hasn't been synced yet. - #[prost(uint64, optional, tag = "4")] - pub latest_lightning_wallet_sync_timestamp: ::core::option::Option, - /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our on-chain - /// wallet to the chain tip. - /// - /// Will be `None` if the wallet hasn’t been synced since the node was initialized. - #[prost(uint64, optional, tag = "5")] - pub latest_onchain_wallet_sync_timestamp: ::core::option::Option, - /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully update our fee rate cache. - /// - /// Will be `None` if the cache hasn’t been updated since the node was initialized. - #[prost(uint64, optional, tag = "6")] - pub latest_fee_rate_cache_update_timestamp: ::core::option::Option, - /// The timestamp, in seconds since start of the UNIX epoch, when the last rapid gossip sync (RGS) snapshot we - /// successfully applied was generated. - /// - /// Will be `None` if RGS isn’t configured or the snapshot hasn’t been updated since the node was initialized. - #[prost(uint64, optional, tag = "7")] - pub latest_rgs_snapshot_timestamp: ::core::option::Option, - /// The timestamp, in seconds since start of the UNIX epoch, when we last broadcasted a node announcement. - /// - /// Will be `None` if we have no public channels or we haven’t broadcasted since the node was initialized. - #[prost(uint64, optional, tag = "8")] - pub latest_node_announcement_broadcast_timestamp: ::core::option::Option, -} -/// Retrieve a new on-chain funding address. -/// See more: -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct OnchainReceiveRequest {} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct OnchainReceiveResponse { - /// A Bitcoin on-chain address. - #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, -} -/// Send an on-chain payment to the given address. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct OnchainSendRequest { - /// The address to send coins to. - #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, - /// The amount in satoshis to send. - /// While sending the specified amount, we will respect any on-chain reserve we need to keep, - /// i.e., won't allow to cut into `total_anchor_channels_reserve_sats`. - /// See more: - #[prost(uint64, optional, tag = "2")] - pub amount_sats: ::core::option::Option, - /// If set, the amount_sats field should be unset. - /// It indicates that node will send full balance to the specified address. - /// - /// Please note that when send_all is used this operation will **not** retain any on-chain reserves, - /// which might be potentially dangerous if you have open Anchor channels for which you can't trust - /// the counterparty to spend the Anchor output after channel closure. - /// See more: - #[prost(bool, optional, tag = "3")] - pub send_all: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct OnchainSendResponse { - /// The transaction ID of the broadcasted transaction. - #[prost(string, tag = "1")] - pub txid: ::prost::alloc::string::String, -} -/// Return a BOLT11 payable invoice that can be used to request and receive a payment -/// for the given amount, if specified. -/// The inbound payment will be automatically claimed upon arrival. -/// See more: -/// - -/// - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt11ReceiveRequest { - /// The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount invoice is returned. - #[prost(uint64, optional, tag = "1")] - pub amount_msat: ::core::option::Option, - /// An optional description to attach along with the invoice. - /// Will be set in the description field of the encoded payment request. - #[prost(string, tag = "2")] - pub description: ::prost::alloc::string::String, - /// Invoice expiry time in seconds. - #[prost(uint32, tag = "3")] - pub expiry_secs: u32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt11ReceiveResponse { - /// An invoice for a payment within the Lightning Network. - /// With the details of the invoice, the sender has all the data necessary to send a payment - /// to the recipient. - #[prost(string, tag = "1")] - pub invoice: ::prost::alloc::string::String, -} -/// Send a payment for a BOLT11 invoice. -/// See more: -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt11SendRequest { - /// An invoice for a payment within the Lightning Network. - #[prost(string, tag = "1")] - pub invoice: ::prost::alloc::string::String, - /// Set this field when paying a so-called "zero-amount" invoice, i.e., an invoice that leaves the - /// amount paid to be determined by the user. - /// This operation will fail if the amount specified is less than the value required by the given invoice. - #[prost(uint64, optional, tag = "2")] - pub amount_msat: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt11SendResponse { - /// An identifier used to uniquely identify a payment. - #[prost(bytes = "bytes", tag = "1")] - pub payment_id: ::prost::bytes::Bytes, -} -/// Returns a BOLT12 offer for the given amount, if specified. -/// -/// See more: -/// - -/// - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt12ReceiveRequest { - /// An optional description to attach along with the offer. - /// Will be set in the description field of the encoded offer. - #[prost(string, tag = "1")] - pub description: ::prost::alloc::string::String, - /// The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount offer is returned. - #[prost(uint64, optional, tag = "2")] - pub amount_msat: ::core::option::Option, - /// Offer expiry time in seconds. - #[prost(uint32, optional, tag = "3")] - pub expiry_secs: ::core::option::Option, - /// If set, it represents the number of items requested, can only be set for fixed-amount offers. - #[prost(uint64, optional, tag = "4")] - pub quantity: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt12ReceiveResponse { - /// An offer for a payment within the Lightning Network. - /// With the details of the offer, the sender has all the data necessary to send a payment - /// to the recipient. - #[prost(string, tag = "1")] - pub offer: ::prost::alloc::string::String, -} -/// Send a payment for a BOLT12 offer. -/// See more: -/// - -/// - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt12SendRequest { - /// An offer for a payment within the Lightning Network. - #[prost(string, tag = "1")] - pub offer: ::prost::alloc::string::String, - /// Set this field when paying a so-called "zero-amount" offer, i.e., an offer that leaves the - /// amount paid to be determined by the user. - /// This operation will fail if the amount specified is less than the value required by the given offer. - #[prost(uint64, optional, tag = "2")] - pub amount_msat: ::core::option::Option, - /// If set, it represents the number of items requested. - #[prost(uint64, optional, tag = "3")] - pub quantity: ::core::option::Option, - /// If set, it will be seen by the recipient and reflected back in the invoice. - #[prost(string, optional, tag = "4")] - pub payer_note: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt12SendResponse { - /// An identifier used to uniquely identify a payment. - #[prost(bytes = "bytes", tag = "1")] - pub payment_id: ::prost::bytes::Bytes, -} -/// Creates a new outbound channel to the given remote node. -/// See more: -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct OpenChannelRequest { - /// The hex-encoded public key of the node to open a channel with. - #[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, - /// The amount of satoshis the caller is willing to commit to the channel. - #[prost(uint64, tag = "3")] - pub channel_amount_sats: u64, - /// The amount of satoshis to push to the remote side as part of the initial commitment state. - #[prost(uint64, optional, tag = "4")] - pub push_to_counterparty_msat: ::core::option::Option, - /// The channel configuration to be used for opening this channel. If unset, default ChannelConfig is used. - #[prost(message, optional, tag = "5")] - pub channel_config: ::core::option::Option, - /// Whether the channel should be public. - #[prost(bool, tag = "6")] - pub announce_channel: bool, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct OpenChannelResponse { - /// The channel id of the created channel that user can use to refer to channel. - #[prost(bytes = "bytes", tag = "1")] - pub user_channel_id: ::prost::bytes::Bytes, -} -/// Update the config for a previously opened channel. -/// See more: -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct UpdateChannelConfigRequest { - /// The hex-encoded local `user_channel_id` of this channel. - #[prost(string, tag = "1")] - pub user_channel_id: ::prost::alloc::string::String, - /// The hex-encoded public key of the counterparty node to update channel config with. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, - /// The updated channel configuration settings for a channel. - #[prost(message, optional, tag = "3")] - pub channel_config: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct UpdateChannelConfigResponse {} -/// ChannelConfig represents the configuration settings for a channel in a Lightning Network node. -/// See more: -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ChannelConfig { - /// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound - /// over the channel. - /// See more: - #[prost(uint32, optional, tag = "1")] - pub forwarding_fee_proportional_millionths: ::core::option::Option, - /// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, - /// in excess of forwarding_fee_proportional_millionths. - /// See more: - #[prost(uint32, optional, tag = "2")] - pub forwarding_fee_base_msat: ::core::option::Option, - /// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded - /// over the channel this config applies to. - /// See more: - #[prost(uint32, optional, tag = "3")] - pub cltv_expiry_delta: ::core::option::Option, - /// The maximum additional fee we’re willing to pay to avoid waiting for the counterparty’s - /// to_self_delay to reclaim funds. - /// See more: - #[prost(uint64, optional, tag = "4")] - pub force_close_avoidance_max_fee_satoshis: ::core::option::Option, - /// If set, allows this channel’s counterparty to skim an additional fee off this node’s - /// inbound HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users. - /// See more: - #[prost(bool, optional, tag = "5")] - pub accept_underpaying_htlcs: ::core::option::Option, - /// Limit our total exposure to potential loss to on-chain fees on close, including - /// in-flight HTLCs which are burned to fees as they are too small to claim on-chain - /// and fees on commitment transaction(s) broadcasted by our counterparty in excess of - /// our own fee estimate. - /// See more: - #[prost(oneof = "channel_config::MaxDustHtlcExposure", tags = "6, 7")] - pub max_dust_htlc_exposure: ::core::option::Option, -} -/// Nested message and enum types in `ChannelConfig`. -pub mod channel_config { - /// Limit our total exposure to potential loss to on-chain fees on close, including - /// in-flight HTLCs which are burned to fees as they are too small to claim on-chain - /// and fees on commitment transaction(s) broadcasted by our counterparty in excess of - /// our own fee estimate. - /// See more: - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum MaxDustHtlcExposure { - /// This sets a fixed limit on the total dust exposure in millisatoshis. - /// See more: - #[prost(uint64, tag = "6")] - FixedLimitMsat(u64), - /// This sets a multiplier on the ConfirmationTarget::OnChainSweep feerate (in sats/KW) to determine the maximum allowed dust exposure. - /// See more: - #[prost(uint64, tag = "7")] - FeeRateMultiplier(u64), - } -} -/// Closes the channel specified by given request. -/// See more: -/// - -/// - -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CloseChannelRequest { - /// The channel id of the created channel that user can use to refer to channel. - #[prost(bytes = "bytes", tag = "1")] - pub user_channel_id: ::prost::bytes::Bytes, - /// The hex-encoded public key of the node to close a channel with. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, - /// Whether to force close the specified channel. - #[prost(bool, optional, tag = "3")] - pub force_close: ::core::option::Option, - /// The reason for force-closing, can only be set while force closing a channel. - #[prost(string, optional, tag = "4")] - pub force_close_reason: ::core::option::Option<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CloseChannelResponse {} -/// Returns a list of known channels. -/// See more: -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ListChannelsRequest {} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ListChannelsResponse { - /// List of channels. - #[prost(message, repeated, tag = "1")] - pub channels: ::prost::alloc::vec::Vec, -} -/// Returns payment details for a given payment_id. -/// See more: -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetPaymentDetailsRequest { - /// An identifier used to uniquely identify a payment in hex-encoded form. - #[prost(string, tag = "1")] - pub payment_id: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetPaymentDetailsResponse { - /// Represents a payment. - /// Will be `None` if payment doesn't exist. - #[prost(message, optional, tag = "1")] - pub payment: ::core::option::Option, -} -/// Retrieves list of all payments. -/// See more: -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ListPaymentsRequest {} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ListPaymentsResponse { - /// List of payments. - #[prost(message, repeated, tag = "1")] - pub payments: ::prost::alloc::vec::Vec, -} -/// Represents a payment. -/// See more: -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Payment { - /// An identifier used to uniquely identify a payment in hex-encoded form. - #[prost(string, tag = "1")] - pub id: ::prost::alloc::string::String, - /// The kind of the payment. - #[prost(message, optional, tag = "2")] - pub kind: ::core::option::Option, - /// The amount transferred. - #[prost(uint64, optional, tag = "3")] - pub amount_msat: ::core::option::Option, - /// The direction of the payment. - #[prost(enumeration = "PaymentDirection", tag = "4")] - pub direction: i32, - /// The status of the payment. - #[prost(enumeration = "PaymentStatus", tag = "5")] - pub status: i32, - /// The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. - #[prost(uint64, tag = "6")] - pub latest_update_timestamp: u64, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PaymentKind { - #[prost(oneof = "payment_kind::Kind", tags = "1, 2, 3, 4, 5, 6")] - pub kind: ::core::option::Option, -} -/// Nested message and enum types in `PaymentKind`. -pub mod payment_kind { - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Kind { - #[prost(message, tag = "1")] - Onchain(super::Onchain), - #[prost(message, tag = "2")] - Bolt11(super::Bolt11), - #[prost(message, tag = "3")] - Bolt11Jit(super::Bolt11Jit), - #[prost(message, tag = "4")] - Bolt12Offer(super::Bolt12Offer), - #[prost(message, tag = "5")] - Bolt12Refund(super::Bolt12Refund), - #[prost(message, tag = "6")] - Spontaneous(super::Spontaneous), - } -} -/// Represents an on-chain payment. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Onchain {} -/// Represents a BOLT 11 payment. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt11 { - /// The payment hash, i.e., the hash of the preimage. - #[prost(string, tag = "1")] - pub hash: ::prost::alloc::string::String, - /// The pre-image used by the payment. - #[prost(string, optional, tag = "2")] - pub preimage: ::core::option::Option<::prost::alloc::string::String>, - /// The secret used by the payment. - #[prost(bytes = "bytes", optional, tag = "3")] - pub secret: ::core::option::Option<::prost::bytes::Bytes>, -} -/// Represents a BOLT 11 payment intended to open an LSPS 2 just-in-time channel. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt11Jit { - /// The payment hash, i.e., the hash of the preimage. - #[prost(string, tag = "1")] - pub hash: ::prost::alloc::string::String, - /// The pre-image used by the payment. - #[prost(string, optional, tag = "2")] - pub preimage: ::core::option::Option<::prost::alloc::string::String>, - /// The secret used by the payment. - #[prost(bytes = "bytes", optional, tag = "3")] - pub secret: ::core::option::Option<::prost::bytes::Bytes>, - /// Limits applying to how much fee we allow an LSP to deduct from the payment amount. - /// - /// Allowing them to deduct this fee from the first inbound payment will pay for the LSP’s channel opening fees. - /// - /// See \[`LdkChannelConfig::accept_underpaying_htlcs`\]() - /// for more information. - #[prost(message, optional, tag = "4")] - pub lsp_fee_limits: ::core::option::Option, -} -/// Represents a BOLT 12 ‘offer’ payment, i.e., a payment for an Offer. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt12Offer { - /// The payment hash, i.e., the hash of the preimage. - #[prost(string, optional, tag = "1")] - pub hash: ::core::option::Option<::prost::alloc::string::String>, - /// The pre-image used by the payment. - #[prost(string, optional, tag = "2")] - pub preimage: ::core::option::Option<::prost::alloc::string::String>, - /// The secret used by the payment. - #[prost(bytes = "bytes", optional, tag = "3")] - pub secret: ::core::option::Option<::prost::bytes::Bytes>, - /// The hex-encoded ID of the offer this payment is for. - #[prost(string, tag = "4")] - pub offer_id: ::prost::alloc::string::String, - /// The payer's note for the payment. - /// Truncated to \[PAYER_NOTE_LIMIT\](). - /// - /// **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, - /// all non-printable characters will be sanitized and replaced with safe characters. - #[prost(string, optional, tag = "5")] - pub payer_note: ::core::option::Option<::prost::alloc::string::String>, - /// The quantity of an item requested in the offer. - #[prost(uint64, optional, tag = "6")] - pub quantity: ::core::option::Option, -} -/// Represents a BOLT 12 ‘refund’ payment, i.e., a payment for a Refund. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt12Refund { - /// The payment hash, i.e., the hash of the preimage. - #[prost(string, optional, tag = "1")] - pub hash: ::core::option::Option<::prost::alloc::string::String>, - /// The pre-image used by the payment. - #[prost(string, optional, tag = "2")] - pub preimage: ::core::option::Option<::prost::alloc::string::String>, - /// The secret used by the payment. - #[prost(bytes = "bytes", optional, tag = "3")] - pub secret: ::core::option::Option<::prost::bytes::Bytes>, - /// The payer's note for the payment. - /// Truncated to \[PAYER_NOTE_LIMIT\](). - /// - /// **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, - /// all non-printable characters will be sanitized and replaced with safe characters. - #[prost(string, optional, tag = "5")] - pub payer_note: ::core::option::Option<::prost::alloc::string::String>, - /// The quantity of an item requested in the offer. - #[prost(uint64, optional, tag = "6")] - pub quantity: ::core::option::Option, -} -/// Represents a spontaneous (“keysend”) payment. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Spontaneous { - /// The payment hash, i.e., the hash of the preimage. - #[prost(string, tag = "1")] - pub hash: ::prost::alloc::string::String, - /// The pre-image used by the payment. - #[prost(string, optional, tag = "2")] - pub preimage: ::core::option::Option<::prost::alloc::string::String>, -} -/// Limits applying to how much fee we allow an LSP to deduct from the payment amount. -/// See \[`LdkChannelConfig::accept_underpaying_htlcs`\] for more information. -/// -/// \[`LdkChannelConfig::accept_underpaying_htlcs`\]: lightning::util::config::ChannelConfig::accept_underpaying_htlcs -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct LspFeeLimits { - /// The maximal total amount we allow any configured LSP withhold from us when forwarding the - /// payment. - #[prost(uint64, optional, tag = "1")] - pub max_total_opening_fee_msat: ::core::option::Option, - /// The maximal proportional fee, in parts-per-million millisatoshi, we allow any configured - /// LSP withhold from us when forwarding the payment. - #[prost(uint64, optional, tag = "2")] - pub max_proportional_opening_fee_ppm_msat: ::core::option::Option, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Channel { - /// The channel ID (prior to funding transaction generation, this is a random 32-byte - /// identifier, afterwards this is the transaction ID of the funding transaction XOR the - /// funding transaction output). - /// - /// Note that this means this value is *not* persistent - it can change once during the - /// lifetime of the channel. - #[prost(string, tag = "1")] - pub channel_id: ::prost::alloc::string::String, - /// The node ID of our the channel's remote counterparty. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, - /// The channel's funding transaction output, if we've negotiated the funding transaction with - /// our counterparty already. - #[prost(message, optional, tag = "3")] - pub funding_txo: ::core::option::Option, - /// The hex-encoded local `user_channel_id` of this channel. - #[prost(string, tag = "4")] - pub user_channel_id: ::prost::alloc::string::String, - /// The value, in satoshis, that must always be held as a reserve in the channel for us. This - /// value ensures that if we broadcast a revoked state, our counterparty can punish us by - /// claiming at least this value on chain. - /// - /// This value is not included in \[`outbound_capacity_msat`\] as it can never be spent. - /// - /// This value will be `None` for outbound channels until the counterparty accepts the channel. - #[prost(uint64, optional, tag = "5")] - pub unspendable_punishment_reserve: ::core::option::Option, - /// The value, in satoshis, of this channel as it appears in the funding output. - #[prost(uint64, tag = "6")] - pub channel_value_sats: u64, - /// The currently negotiated fee rate denominated in satoshi per 1000 weight units, - /// which is applied to commitment and HTLC transactions. - #[prost(uint32, tag = "7")] - pub feerate_sat_per_1000_weight: u32, - /// The available outbound capacity for sending HTLCs to the remote peer. - /// - /// The amount does not include any pending HTLCs which are not yet resolved (and, thus, whose - /// balance is not available for inclusion in new outbound HTLCs). This further does not include - /// any pending outgoing HTLCs which are awaiting some other resolution to be sent. - #[prost(uint64, tag = "8")] - pub outbound_capacity_msat: u64, - /// The available outbound capacity for sending HTLCs to the remote peer. - /// - /// The amount does not include any pending HTLCs which are not yet resolved - /// (and, thus, whose balance is not available for inclusion in new inbound HTLCs). This further - /// does not include any pending outgoing HTLCs which are awaiting some other resolution to be - /// sent. - #[prost(uint64, tag = "9")] - pub inbound_capacity_msat: u64, - /// The number of required confirmations on the funding transactions before the funding is - /// considered "locked". The amount is selected by the channel fundee. - /// - /// The value will be `None` for outbound channels until the counterparty accepts the channel. - #[prost(uint32, optional, tag = "10")] - pub confirmations_required: ::core::option::Option, - /// The current number of confirmations on the funding transaction. - #[prost(uint32, optional, tag = "11")] - pub confirmations: ::core::option::Option, - /// Is `true` if the channel was initiated (and therefore funded) by us. - #[prost(bool, tag = "12")] - pub is_outbound: bool, - /// Is `true` if both parties have exchanged `channel_ready` messages, and the channel is - /// not currently being shut down. Both parties exchange `channel_ready` messages upon - /// independently verifying that the required confirmations count provided by - /// `confirmations_required` has been reached. - #[prost(bool, tag = "13")] - pub is_channel_ready: bool, - /// Is `true` if the channel (a) `channel_ready` messages have been exchanged, (b) the - /// peer is connected, and (c) the channel is not currently negotiating shutdown. - /// - /// This is a strict superset of `is_channel_ready`. - #[prost(bool, tag = "14")] - pub is_usable: bool, - /// Is `true` if this channel is (or will be) publicly-announced - #[prost(bool, tag = "15")] - pub is_announced: bool, - /// Set of configurable parameters set by self that affect channel operation. - #[prost(message, optional, tag = "16")] - pub channel_config: ::core::option::Option, - /// The available outbound capacity for sending a single HTLC to the remote peer. This is - /// similar to `outbound_capacity_msat` but it may be further restricted by - /// the current state and per-HTLC limit(s). This is intended for use when routing, allowing us - /// to use a limit as close as possible to the HTLC limit we can currently send. - #[prost(uint64, tag = "17")] - pub next_outbound_htlc_limit_msat: u64, - /// The minimum value for sending a single HTLC to the remote peer. This is the equivalent of - /// `next_outbound_htlc_limit_msat` but represents a lower-bound, rather than - /// an upper-bound. This is intended for use when routing, allowing us to ensure we pick a - /// route which is valid. - #[prost(uint64, tag = "18")] - pub next_outbound_htlc_minimum_msat: u64, - /// The number of blocks (after our commitment transaction confirms) that we will need to wait - /// until we can claim our funds after we force-close the channel. During this time our - /// counterparty is allowed to punish us if we broadcasted a stale state. If our counterparty - /// force-closes the channel and broadcasts a commitment transaction we do not have to wait any - /// time to claim our non-HTLC-encumbered funds. - /// - /// This value will be `None` for outbound channels until the counterparty accepts the channel. - #[prost(uint32, optional, tag = "19")] - pub force_close_spend_delay: ::core::option::Option, - /// The smallest value HTLC (in msat) the remote peer will accept, for this channel. - /// - /// This field is only `None` before we have received either the `OpenChannel` or - /// `AcceptChannel` message from the remote peer. - #[prost(uint64, optional, tag = "20")] - pub counterparty_outbound_htlc_minimum_msat: ::core::option::Option, - /// The largest value HTLC (in msat) the remote peer currently will accept, for this channel. - #[prost(uint64, optional, tag = "21")] - pub counterparty_outbound_htlc_maximum_msat: ::core::option::Option, - /// The value, in satoshis, that must always be held in the channel for our counterparty. This - /// value ensures that if our counterparty broadcasts a revoked state, we can punish them by - /// claiming at least this value on chain. - /// - /// This value is not included in `inbound_capacity_msat` as it can never be spent. - #[prost(uint64, tag = "22")] - pub counterparty_unspendable_punishment_reserve: u64, - /// Base routing fee in millisatoshis. - #[prost(uint32, optional, tag = "23")] - pub counterparty_forwarding_info_fee_base_msat: ::core::option::Option, - /// Proportional fee, in millionths of a satoshi the channel will charge per transferred satoshi. - #[prost(uint32, optional, tag = "24")] - pub counterparty_forwarding_info_fee_proportional_millionths: ::core::option::Option, - /// The minimum difference in CLTV expiry between an ingoing HTLC and its outgoing counterpart, - /// such that the outgoing HTLC is forwardable to this counterparty. - #[prost(uint32, optional, tag = "25")] - pub counterparty_forwarding_info_cltv_expiry_delta: ::core::option::Option, -} -/// Represent a transaction outpoint. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct OutPoint { - /// The referenced transaction's txid. - #[prost(string, tag = "1")] - pub txid: ::prost::alloc::string::String, - /// The index of the referenced output in its transaction's vout. - #[prost(uint32, tag = "2")] - pub vout: u32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BestBlock { - /// The block’s hash - #[prost(string, tag = "1")] - pub block_hash: ::prost::alloc::string::String, - /// The height at which the block was confirmed. - #[prost(uint32, tag = "2")] - pub height: u32, -} -/// Represents the direction of a payment. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum PaymentDirection { - /// The payment is inbound. - Inbound = 0, - /// The payment is outbound. - Outbound = 1, -} -impl PaymentDirection { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - PaymentDirection::Inbound => "INBOUND", - PaymentDirection::Outbound => "OUTBOUND", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "INBOUND" => Some(Self::Inbound), - "OUTBOUND" => Some(Self::Outbound), - _ => None, - } - } -} -/// Represents the current status of a payment. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum PaymentStatus { - /// The payment is still pending. - Pending = 0, - /// The payment succeeded. - Succeeded = 1, - /// The payment failed. - Failed = 2, -} -impl PaymentStatus { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - PaymentStatus::Pending => "PENDING", - PaymentStatus::Succeeded => "SUCCEEDED", - PaymentStatus::Failed => "FAILED", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "PENDING" => Some(Self::Pending), - "SUCCEEDED" => Some(Self::Succeeded), - "FAILED" => Some(Self::Failed), - _ => None, - } - } -} +pub mod api; +pub mod types; diff --git a/ldk-server/protos/src/proto/api.proto b/ldk-server/protos/src/proto/api.proto new file mode 100644 index 000000000..f3ddd83db --- /dev/null +++ b/ldk-server/protos/src/proto/api.proto @@ -0,0 +1,295 @@ +syntax = "proto3"; +package api; + +import 'types.proto'; + +// Retrieve the latest node info like `node_id`, `current_best_block` etc. +// See more: +// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.node_id +// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.status +message GetNodeInfoRequest { +} + +message GetNodeInfoResponse { + + // The hex-encoded `node-id` or public key for our own lightning node. + string node_id = 1; + + // The best block to which our Lightning wallet is currently synced. + // + // Should be always set, will never be `None`. + types.BestBlock current_best_block = 3; + + // The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our Lightning wallet to + // the chain tip. + // + // Will be `None` if the wallet hasn't been synced yet. + optional uint64 latest_lightning_wallet_sync_timestamp = 4; + + // The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our on-chain + // wallet to the chain tip. + // + // Will be `None` if the wallet hasn’t been synced since the node was initialized. + optional uint64 latest_onchain_wallet_sync_timestamp = 5; + + // The timestamp, in seconds since start of the UNIX epoch, when we last successfully update our fee rate cache. + // + // Will be `None` if the cache hasn’t been updated since the node was initialized. + optional uint64 latest_fee_rate_cache_update_timestamp = 6; + + // The timestamp, in seconds since start of the UNIX epoch, when the last rapid gossip sync (RGS) snapshot we + // successfully applied was generated. + // + // Will be `None` if RGS isn’t configured or the snapshot hasn’t been updated since the node was initialized. + optional uint64 latest_rgs_snapshot_timestamp = 7; + + // The timestamp, in seconds since start of the UNIX epoch, when we last broadcasted a node announcement. + // + // Will be `None` if we have no public channels or we haven’t broadcasted since the node was initialized. + optional uint64 latest_node_announcement_broadcast_timestamp = 8; +} + +// Retrieve a new on-chain funding address. +// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.new_address +message OnchainReceiveRequest { +} + +message OnchainReceiveResponse { + + // A Bitcoin on-chain address. + string address = 1; +} + +// Send an on-chain payment to the given address. +message OnchainSendRequest { + + // The address to send coins to. + string address = 1; + + // The amount in satoshis to send. + // While sending the specified amount, we will respect any on-chain reserve we need to keep, + // i.e., won't allow to cut into `total_anchor_channels_reserve_sats`. + // See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.send_to_address + optional uint64 amount_sats = 2; + + // If set, the amount_sats field should be unset. + // It indicates that node will send full balance to the specified address. + // + // Please note that when send_all is used this operation will **not** retain any on-chain reserves, + // which might be potentially dangerous if you have open Anchor channels for which you can't trust + // the counterparty to spend the Anchor output after channel closure. + // See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.send_all_to_address + optional bool send_all = 3; +} + +message OnchainSendResponse { + + // The transaction ID of the broadcasted transaction. + string txid = 1; +} + +// Return a BOLT11 payable invoice that can be used to request and receive a payment +// for the given amount, if specified. +// The inbound payment will be automatically claimed upon arrival. +// See more: +// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.receive +// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.receive_variable_amount +message Bolt11ReceiveRequest { + + // The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount invoice is returned. + optional uint64 amount_msat = 1; + + // An optional description to attach along with the invoice. + // Will be set in the description field of the encoded payment request. + string description = 2; + + // Invoice expiry time in seconds. + uint32 expiry_secs = 3; +} + + +message Bolt11ReceiveResponse { + + // An invoice for a payment within the Lightning Network. + // With the details of the invoice, the sender has all the data necessary to send a payment + // to the recipient. + string invoice = 1; +} + +// Send a payment for a BOLT11 invoice. +// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.send +message Bolt11SendRequest { + + // An invoice for a payment within the Lightning Network. + string invoice = 1; + + // Set this field when paying a so-called "zero-amount" invoice, i.e., an invoice that leaves the + // amount paid to be determined by the user. + // This operation will fail if the amount specified is less than the value required by the given invoice. + optional uint64 amount_msat = 2; + +} + +message Bolt11SendResponse { + + // An identifier used to uniquely identify a payment. + bytes payment_id = 1; +} + +// Returns a BOLT12 offer for the given amount, if specified. +// +// See more: +// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.receive +// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.receive_variable_amount +message Bolt12ReceiveRequest { + + // An optional description to attach along with the offer. + // Will be set in the description field of the encoded offer. + string description = 1; + + // The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount offer is returned. + optional uint64 amount_msat = 2; + + // Offer expiry time in seconds. + optional uint32 expiry_secs = 3; + + // If set, it represents the number of items requested, can only be set for fixed-amount offers. + optional uint64 quantity = 4; +} + +message Bolt12ReceiveResponse { + + // An offer for a payment within the Lightning Network. + // With the details of the offer, the sender has all the data necessary to send a payment + // to the recipient. + string offer = 1; +} + +// Send a payment for a BOLT12 offer. +// See more: +// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.send +// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.send_using_amount +message Bolt12SendRequest { + + // An offer for a payment within the Lightning Network. + string offer = 1; + + // Set this field when paying a so-called "zero-amount" offer, i.e., an offer that leaves the + // amount paid to be determined by the user. + // This operation will fail if the amount specified is less than the value required by the given offer. + optional uint64 amount_msat = 2; + + // If set, it represents the number of items requested. + optional uint64 quantity = 3; + + // If set, it will be seen by the recipient and reflected back in the invoice. + optional string payer_note = 4; +} + +message Bolt12SendResponse { + + // An identifier used to uniquely identify a payment. + bytes payment_id = 1; +} + +// Creates a new outbound channel to the given remote node. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.connect_open_channel +message OpenChannelRequest { + + // The hex-encoded public key of the node to open a channel with. + string node_pubkey = 1; + + // 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 + string address = 2; + + // The amount of satoshis the caller is willing to commit to the channel. + uint64 channel_amount_sats = 3; + + // The amount of satoshis to push to the remote side as part of the initial commitment state. + optional uint64 push_to_counterparty_msat = 4; + + // The channel configuration to be used for opening this channel. If unset, default ChannelConfig is used. + optional types.ChannelConfig channel_config = 5; + + // Whether the channel should be public. + bool announce_channel = 6; +} + +message OpenChannelResponse { + + // The channel id of the created channel that user can use to refer to channel. + bytes user_channel_id = 1; +} + +// Update the config for a previously opened channel. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.update_channel_config +message UpdateChannelConfigRequest { + + // The hex-encoded local `user_channel_id` of this channel. + string user_channel_id = 1; + + // The hex-encoded public key of the counterparty node to update channel config with. + string counterparty_node_id = 2; + + // The updated channel configuration settings for a channel. + types.ChannelConfig channel_config = 3; +} + +message UpdateChannelConfigResponse { +} + +// Closes the channel specified by given request. +// See more: +// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.close_channel +// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.force_close_channel +message CloseChannelRequest { + + // The channel id of the created channel that user can use to refer to channel. + bytes user_channel_id = 1; + + // The hex-encoded public key of the node to close a channel with. + string counterparty_node_id = 2; + + // Whether to force close the specified channel. + optional bool force_close = 3; + + // The reason for force-closing, can only be set while force closing a channel. + optional string force_close_reason = 4; +} + +message CloseChannelResponse { + +} + +// Returns a list of known channels. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_channels +message ListChannelsRequest {} + +message ListChannelsResponse { + + // List of channels. + repeated types.Channel channels = 1; +} + +// Returns payment details for a given payment_id. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.payment +message GetPaymentDetailsRequest { + // An identifier used to uniquely identify a payment in hex-encoded form. + string payment_id = 1; +} + +message GetPaymentDetailsResponse { + // Represents a payment. + // Will be `None` if payment doesn't exist. + types.Payment payment = 1; +} + +// Retrieves list of all payments. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_payments +message ListPaymentsRequest {} + +message ListPaymentsResponse { + // List of payments. + repeated types.Payment payments = 1; +} diff --git a/ldk-server/protos/src/proto/ldk_node_server.proto b/ldk-server/protos/src/proto/types.proto similarity index 58% rename from ldk-server/protos/src/proto/ldk_node_server.proto rename to ldk-server/protos/src/proto/types.proto index 342f704d6..82eeee8ab 100644 --- a/ldk-server/protos/src/proto/ldk_node_server.proto +++ b/ldk-server/protos/src/proto/types.proto @@ -1,341 +1,5 @@ syntax = "proto3"; -package ldk_node_server; - -// Retrieve the latest node info like `node_id`, `current_best_block` etc. -// See more: -// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.node_id -// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.status -message GetNodeInfoRequest { -} - -message GetNodeInfoResponse { - - // The hex-encoded `node-id` or public key for our own lightning node. - string node_id = 1; - - // The best block to which our Lightning wallet is currently synced. - // - // Should be always set, will never be `None`. - BestBlock current_best_block = 3; - - // The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our Lightning wallet to - // the chain tip. - // - // Will be `None` if the wallet hasn't been synced yet. - optional uint64 latest_lightning_wallet_sync_timestamp = 4; - - // The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our on-chain - // wallet to the chain tip. - // - // Will be `None` if the wallet hasn’t been synced since the node was initialized. - optional uint64 latest_onchain_wallet_sync_timestamp = 5; - - // The timestamp, in seconds since start of the UNIX epoch, when we last successfully update our fee rate cache. - // - // Will be `None` if the cache hasn’t been updated since the node was initialized. - optional uint64 latest_fee_rate_cache_update_timestamp = 6; - - // The timestamp, in seconds since start of the UNIX epoch, when the last rapid gossip sync (RGS) snapshot we - // successfully applied was generated. - // - // Will be `None` if RGS isn’t configured or the snapshot hasn’t been updated since the node was initialized. - optional uint64 latest_rgs_snapshot_timestamp = 7; - - // The timestamp, in seconds since start of the UNIX epoch, when we last broadcasted a node announcement. - // - // Will be `None` if we have no public channels or we haven’t broadcasted since the node was initialized. - optional uint64 latest_node_announcement_broadcast_timestamp = 8; -} - -// Retrieve a new on-chain funding address. -// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.new_address -message OnchainReceiveRequest { -} - -message OnchainReceiveResponse { - - // A Bitcoin on-chain address. - string address = 1; -} - -// Send an on-chain payment to the given address. -message OnchainSendRequest { - - // The address to send coins to. - string address = 1; - - // The amount in satoshis to send. - // While sending the specified amount, we will respect any on-chain reserve we need to keep, - // i.e., won't allow to cut into `total_anchor_channels_reserve_sats`. - // See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.send_to_address - optional uint64 amount_sats = 2; - - // If set, the amount_sats field should be unset. - // It indicates that node will send full balance to the specified address. - // - // Please note that when send_all is used this operation will **not** retain any on-chain reserves, - // which might be potentially dangerous if you have open Anchor channels for which you can't trust - // the counterparty to spend the Anchor output after channel closure. - // See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.send_all_to_address - optional bool send_all = 3; -} - -message OnchainSendResponse { - - // The transaction ID of the broadcasted transaction. - string txid = 1; -} - -// Return a BOLT11 payable invoice that can be used to request and receive a payment -// for the given amount, if specified. -// The inbound payment will be automatically claimed upon arrival. -// See more: -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.receive -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.receive_variable_amount -message Bolt11ReceiveRequest { - - // The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount invoice is returned. - optional uint64 amount_msat = 1; - - // An optional description to attach along with the invoice. - // Will be set in the description field of the encoded payment request. - string description = 2; - - // Invoice expiry time in seconds. - uint32 expiry_secs = 3; -} - - -message Bolt11ReceiveResponse { - - // An invoice for a payment within the Lightning Network. - // With the details of the invoice, the sender has all the data necessary to send a payment - // to the recipient. - string invoice = 1; -} - -// Send a payment for a BOLT11 invoice. -// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.send -message Bolt11SendRequest { - - // An invoice for a payment within the Lightning Network. - string invoice = 1; - - // Set this field when paying a so-called "zero-amount" invoice, i.e., an invoice that leaves the - // amount paid to be determined by the user. - // This operation will fail if the amount specified is less than the value required by the given invoice. - optional uint64 amount_msat = 2; - -} - -message Bolt11SendResponse { - - // An identifier used to uniquely identify a payment. - bytes payment_id = 1; -} - -// Returns a BOLT12 offer for the given amount, if specified. -// -// See more: -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.receive -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.receive_variable_amount -message Bolt12ReceiveRequest { - - // An optional description to attach along with the offer. - // Will be set in the description field of the encoded offer. - string description = 1; - - // The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount offer is returned. - optional uint64 amount_msat = 2; - - // Offer expiry time in seconds. - optional uint32 expiry_secs = 3; - - // If set, it represents the number of items requested, can only be set for fixed-amount offers. - optional uint64 quantity = 4; -} - -message Bolt12ReceiveResponse { - - // An offer for a payment within the Lightning Network. - // With the details of the offer, the sender has all the data necessary to send a payment - // to the recipient. - string offer = 1; -} - -// Send a payment for a BOLT12 offer. -// See more: -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.send -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.send_using_amount -message Bolt12SendRequest { - - // An offer for a payment within the Lightning Network. - string offer = 1; - - // Set this field when paying a so-called "zero-amount" offer, i.e., an offer that leaves the - // amount paid to be determined by the user. - // This operation will fail if the amount specified is less than the value required by the given offer. - optional uint64 amount_msat = 2; - - // If set, it represents the number of items requested. - optional uint64 quantity = 3; - - // If set, it will be seen by the recipient and reflected back in the invoice. - optional string payer_note = 4; -} - -message Bolt12SendResponse { - - // An identifier used to uniquely identify a payment. - bytes payment_id = 1; -} - -// Creates a new outbound channel to the given remote node. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.connect_open_channel -message OpenChannelRequest { - - // The hex-encoded public key of the node to open a channel with. - string node_pubkey = 1; - - // 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 - string address = 2; - - // The amount of satoshis the caller is willing to commit to the channel. - uint64 channel_amount_sats = 3; - - // The amount of satoshis to push to the remote side as part of the initial commitment state. - optional uint64 push_to_counterparty_msat = 4; - - // The channel configuration to be used for opening this channel. If unset, default ChannelConfig is used. - optional ChannelConfig channel_config = 5; - - // Whether the channel should be public. - bool announce_channel = 6; -} - -message OpenChannelResponse { - - // The channel id of the created channel that user can use to refer to channel. - bytes user_channel_id = 1; -} - -// Update the config for a previously opened channel. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.update_channel_config -message UpdateChannelConfigRequest { - - // The hex-encoded local `user_channel_id` of this channel. - string user_channel_id = 1; - - // The hex-encoded public key of the counterparty node to update channel config with. - string counterparty_node_id = 2; - - // The updated channel configuration settings for a channel. - ChannelConfig channel_config = 3; -} - -message UpdateChannelConfigResponse { -} - -// ChannelConfig represents the configuration settings for a channel in a Lightning Network node. -// See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html -message ChannelConfig { - // Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound - // over the channel. - // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.forwarding_fee_proportional_millionths - optional uint32 forwarding_fee_proportional_millionths = 1; - - // Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, - // in excess of forwarding_fee_proportional_millionths. - // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.forwarding_fee_base_msat - optional uint32 forwarding_fee_base_msat = 2; - - // The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded - // over the channel this config applies to. - // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.cltv_expiry_delta - optional uint32 cltv_expiry_delta = 3; - - // The maximum additional fee we’re willing to pay to avoid waiting for the counterparty’s - // to_self_delay to reclaim funds. - // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.force_close_avoidance_max_fee_satoshis - optional uint64 force_close_avoidance_max_fee_satoshis = 4; - - // If set, allows this channel’s counterparty to skim an additional fee off this node’s - // inbound HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users. - // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.accept_underpaying_htlcs - optional bool accept_underpaying_htlcs = 5; - - // Limit our total exposure to potential loss to on-chain fees on close, including - // in-flight HTLCs which are burned to fees as they are too small to claim on-chain - // and fees on commitment transaction(s) broadcasted by our counterparty in excess of - // our own fee estimate. - // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.max_dust_htlc_exposure - oneof max_dust_htlc_exposure { - - // This sets a fixed limit on the total dust exposure in millisatoshis. - // See more: https://docs.rs/lightning/latest/lightning/util/config/enum.MaxDustHTLCExposure.html#variant.FixedLimitMsat - uint64 fixed_limit_msat = 6; - - // This sets a multiplier on the ConfirmationTarget::OnChainSweep feerate (in sats/KW) to determine the maximum allowed dust exposure. - // See more: https://docs.rs/lightning/latest/lightning/util/config/enum.MaxDustHTLCExposure.html#variant.FeeRateMultiplier - uint64 fee_rate_multiplier = 7; - } -} - -// Closes the channel specified by given request. -// See more: -// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.close_channel -// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.force_close_channel -message CloseChannelRequest { - - // The channel id of the created channel that user can use to refer to channel. - bytes user_channel_id = 1; - - // The hex-encoded public key of the node to close a channel with. - string counterparty_node_id = 2; - - // Whether to force close the specified channel. - optional bool force_close = 3; - - // The reason for force-closing, can only be set while force closing a channel. - optional string force_close_reason = 4; -} - -message CloseChannelResponse { - -} - -// Returns a list of known channels. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_channels -message ListChannelsRequest {} - -message ListChannelsResponse { - - // List of channels. - repeated Channel channels = 1; -} - -// Returns payment details for a given payment_id. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.payment -message GetPaymentDetailsRequest { - // An identifier used to uniquely identify a payment in hex-encoded form. - string payment_id = 1; -} - -message GetPaymentDetailsResponse { - // Represents a payment. - // Will be `None` if payment doesn't exist. - Payment payment = 1; -} - -// Retrieves list of all payments. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_payments -message ListPaymentsRequest {} - -message ListPaymentsResponse { - // List of payments. - repeated Payment payments = 1; -} +package types; // Represents a payment. // See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.PaymentDetails.html @@ -625,6 +289,51 @@ message Channel { optional uint32 counterparty_forwarding_info_cltv_expiry_delta = 25; } +// ChannelConfig represents the configuration settings for a channel in a Lightning Network node. +// See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html +message ChannelConfig { + // Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound + // over the channel. + // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.forwarding_fee_proportional_millionths + optional uint32 forwarding_fee_proportional_millionths = 1; + + // Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, + // in excess of forwarding_fee_proportional_millionths. + // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.forwarding_fee_base_msat + optional uint32 forwarding_fee_base_msat = 2; + + // The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded + // over the channel this config applies to. + // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.cltv_expiry_delta + optional uint32 cltv_expiry_delta = 3; + + // The maximum additional fee we’re willing to pay to avoid waiting for the counterparty’s + // to_self_delay to reclaim funds. + // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.force_close_avoidance_max_fee_satoshis + optional uint64 force_close_avoidance_max_fee_satoshis = 4; + + // If set, allows this channel’s counterparty to skim an additional fee off this node’s + // inbound HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users. + // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.accept_underpaying_htlcs + optional bool accept_underpaying_htlcs = 5; + + // Limit our total exposure to potential loss to on-chain fees on close, including + // in-flight HTLCs which are burned to fees as they are too small to claim on-chain + // and fees on commitment transaction(s) broadcasted by our counterparty in excess of + // our own fee estimate. + // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.max_dust_htlc_exposure + oneof max_dust_htlc_exposure { + + // This sets a fixed limit on the total dust exposure in millisatoshis. + // See more: https://docs.rs/lightning/latest/lightning/util/config/enum.MaxDustHTLCExposure.html#variant.FixedLimitMsat + uint64 fixed_limit_msat = 6; + + // This sets a multiplier on the ConfirmationTarget::OnChainSweep feerate (in sats/KW) to determine the maximum allowed dust exposure. + // See more: https://docs.rs/lightning/latest/lightning/util/config/enum.MaxDustHTLCExposure.html#variant.FeeRateMultiplier + uint64 fee_rate_multiplier = 7; + } +} + // Represent a transaction outpoint. message OutPoint { // The referenced transaction's txid. diff --git a/ldk-server/protos/src/types.rs b/ldk-server/protos/src/types.rs new file mode 100644 index 000000000..d99cfdeff --- /dev/null +++ b/ldk-server/protos/src/types.rs @@ -0,0 +1,438 @@ +/// Represents a payment. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Payment { + /// An identifier used to uniquely identify a payment in hex-encoded form. + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + /// The kind of the payment. + #[prost(message, optional, tag = "2")] + pub kind: ::core::option::Option, + /// The amount transferred. + #[prost(uint64, optional, tag = "3")] + pub amount_msat: ::core::option::Option, + /// The direction of the payment. + #[prost(enumeration = "PaymentDirection", tag = "4")] + pub direction: i32, + /// The status of the payment. + #[prost(enumeration = "PaymentStatus", tag = "5")] + pub status: i32, + /// The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. + #[prost(uint64, tag = "6")] + pub latest_update_timestamp: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PaymentKind { + #[prost(oneof = "payment_kind::Kind", tags = "1, 2, 3, 4, 5, 6")] + pub kind: ::core::option::Option, +} +/// Nested message and enum types in `PaymentKind`. +pub mod payment_kind { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Kind { + #[prost(message, tag = "1")] + Onchain(super::Onchain), + #[prost(message, tag = "2")] + Bolt11(super::Bolt11), + #[prost(message, tag = "3")] + Bolt11Jit(super::Bolt11Jit), + #[prost(message, tag = "4")] + Bolt12Offer(super::Bolt12Offer), + #[prost(message, tag = "5")] + Bolt12Refund(super::Bolt12Refund), + #[prost(message, tag = "6")] + Spontaneous(super::Spontaneous), + } +} +/// Represents an on-chain payment. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Onchain {} +/// Represents a BOLT 11 payment. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11 { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, tag = "1")] + pub hash: ::prost::alloc::string::String, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, + /// The secret used by the payment. + #[prost(bytes = "bytes", optional, tag = "3")] + pub secret: ::core::option::Option<::prost::bytes::Bytes>, +} +/// Represents a BOLT 11 payment intended to open an LSPS 2 just-in-time channel. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11Jit { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, tag = "1")] + pub hash: ::prost::alloc::string::String, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, + /// The secret used by the payment. + #[prost(bytes = "bytes", optional, tag = "3")] + pub secret: ::core::option::Option<::prost::bytes::Bytes>, + /// Limits applying to how much fee we allow an LSP to deduct from the payment amount. + /// + /// Allowing them to deduct this fee from the first inbound payment will pay for the LSP’s channel opening fees. + /// + /// See \[`LdkChannelConfig::accept_underpaying_htlcs`\]() + /// for more information. + #[prost(message, optional, tag = "4")] + pub lsp_fee_limits: ::core::option::Option, +} +/// Represents a BOLT 12 ‘offer’ payment, i.e., a payment for an Offer. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12Offer { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, optional, tag = "1")] + pub hash: ::core::option::Option<::prost::alloc::string::String>, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, + /// The secret used by the payment. + #[prost(bytes = "bytes", optional, tag = "3")] + pub secret: ::core::option::Option<::prost::bytes::Bytes>, + /// The hex-encoded ID of the offer this payment is for. + #[prost(string, tag = "4")] + pub offer_id: ::prost::alloc::string::String, + /// The payer's note for the payment. + /// Truncated to \[PAYER_NOTE_LIMIT\](). + /// + /// **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, + /// all non-printable characters will be sanitized and replaced with safe characters. + #[prost(string, optional, tag = "5")] + pub payer_note: ::core::option::Option<::prost::alloc::string::String>, + /// The quantity of an item requested in the offer. + #[prost(uint64, optional, tag = "6")] + pub quantity: ::core::option::Option, +} +/// Represents a BOLT 12 ‘refund’ payment, i.e., a payment for a Refund. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12Refund { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, optional, tag = "1")] + pub hash: ::core::option::Option<::prost::alloc::string::String>, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, + /// The secret used by the payment. + #[prost(bytes = "bytes", optional, tag = "3")] + pub secret: ::core::option::Option<::prost::bytes::Bytes>, + /// The payer's note for the payment. + /// Truncated to \[PAYER_NOTE_LIMIT\](). + /// + /// **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, + /// all non-printable characters will be sanitized and replaced with safe characters. + #[prost(string, optional, tag = "5")] + pub payer_note: ::core::option::Option<::prost::alloc::string::String>, + /// The quantity of an item requested in the offer. + #[prost(uint64, optional, tag = "6")] + pub quantity: ::core::option::Option, +} +/// Represents a spontaneous (“keysend”) payment. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Spontaneous { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, tag = "1")] + pub hash: ::prost::alloc::string::String, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, +} +/// Limits applying to how much fee we allow an LSP to deduct from the payment amount. +/// See \[`LdkChannelConfig::accept_underpaying_htlcs`\] for more information. +/// +/// \[`LdkChannelConfig::accept_underpaying_htlcs`\]: lightning::util::config::ChannelConfig::accept_underpaying_htlcs +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LspFeeLimits { + /// The maximal total amount we allow any configured LSP withhold from us when forwarding the + /// payment. + #[prost(uint64, optional, tag = "1")] + pub max_total_opening_fee_msat: ::core::option::Option, + /// The maximal proportional fee, in parts-per-million millisatoshi, we allow any configured + /// LSP withhold from us when forwarding the payment. + #[prost(uint64, optional, tag = "2")] + pub max_proportional_opening_fee_ppm_msat: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Channel { + /// The channel ID (prior to funding transaction generation, this is a random 32-byte + /// identifier, afterwards this is the transaction ID of the funding transaction XOR the + /// funding transaction output). + /// + /// Note that this means this value is *not* persistent - it can change once during the + /// lifetime of the channel. + #[prost(string, tag = "1")] + pub channel_id: ::prost::alloc::string::String, + /// The node ID of our the channel's remote counterparty. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// The channel's funding transaction output, if we've negotiated the funding transaction with + /// our counterparty already. + #[prost(message, optional, tag = "3")] + pub funding_txo: ::core::option::Option, + /// The hex-encoded local `user_channel_id` of this channel. + #[prost(string, tag = "4")] + pub user_channel_id: ::prost::alloc::string::String, + /// The value, in satoshis, that must always be held as a reserve in the channel for us. This + /// value ensures that if we broadcast a revoked state, our counterparty can punish us by + /// claiming at least this value on chain. + /// + /// This value is not included in \[`outbound_capacity_msat`\] as it can never be spent. + /// + /// This value will be `None` for outbound channels until the counterparty accepts the channel. + #[prost(uint64, optional, tag = "5")] + pub unspendable_punishment_reserve: ::core::option::Option, + /// The value, in satoshis, of this channel as it appears in the funding output. + #[prost(uint64, tag = "6")] + pub channel_value_sats: u64, + /// The currently negotiated fee rate denominated in satoshi per 1000 weight units, + /// which is applied to commitment and HTLC transactions. + #[prost(uint32, tag = "7")] + pub feerate_sat_per_1000_weight: u32, + /// The available outbound capacity for sending HTLCs to the remote peer. + /// + /// The amount does not include any pending HTLCs which are not yet resolved (and, thus, whose + /// balance is not available for inclusion in new outbound HTLCs). This further does not include + /// any pending outgoing HTLCs which are awaiting some other resolution to be sent. + #[prost(uint64, tag = "8")] + pub outbound_capacity_msat: u64, + /// The available outbound capacity for sending HTLCs to the remote peer. + /// + /// The amount does not include any pending HTLCs which are not yet resolved + /// (and, thus, whose balance is not available for inclusion in new inbound HTLCs). This further + /// does not include any pending outgoing HTLCs which are awaiting some other resolution to be + /// sent. + #[prost(uint64, tag = "9")] + pub inbound_capacity_msat: u64, + /// The number of required confirmations on the funding transactions before the funding is + /// considered "locked". The amount is selected by the channel fundee. + /// + /// The value will be `None` for outbound channels until the counterparty accepts the channel. + #[prost(uint32, optional, tag = "10")] + pub confirmations_required: ::core::option::Option, + /// The current number of confirmations on the funding transaction. + #[prost(uint32, optional, tag = "11")] + pub confirmations: ::core::option::Option, + /// Is `true` if the channel was initiated (and therefore funded) by us. + #[prost(bool, tag = "12")] + pub is_outbound: bool, + /// Is `true` if both parties have exchanged `channel_ready` messages, and the channel is + /// not currently being shut down. Both parties exchange `channel_ready` messages upon + /// independently verifying that the required confirmations count provided by + /// `confirmations_required` has been reached. + #[prost(bool, tag = "13")] + pub is_channel_ready: bool, + /// Is `true` if the channel (a) `channel_ready` messages have been exchanged, (b) the + /// peer is connected, and (c) the channel is not currently negotiating shutdown. + /// + /// This is a strict superset of `is_channel_ready`. + #[prost(bool, tag = "14")] + pub is_usable: bool, + /// Is `true` if this channel is (or will be) publicly-announced + #[prost(bool, tag = "15")] + pub is_announced: bool, + /// Set of configurable parameters set by self that affect channel operation. + #[prost(message, optional, tag = "16")] + pub channel_config: ::core::option::Option, + /// The available outbound capacity for sending a single HTLC to the remote peer. This is + /// similar to `outbound_capacity_msat` but it may be further restricted by + /// the current state and per-HTLC limit(s). This is intended for use when routing, allowing us + /// to use a limit as close as possible to the HTLC limit we can currently send. + #[prost(uint64, tag = "17")] + pub next_outbound_htlc_limit_msat: u64, + /// The minimum value for sending a single HTLC to the remote peer. This is the equivalent of + /// `next_outbound_htlc_limit_msat` but represents a lower-bound, rather than + /// an upper-bound. This is intended for use when routing, allowing us to ensure we pick a + /// route which is valid. + #[prost(uint64, tag = "18")] + pub next_outbound_htlc_minimum_msat: u64, + /// The number of blocks (after our commitment transaction confirms) that we will need to wait + /// until we can claim our funds after we force-close the channel. During this time our + /// counterparty is allowed to punish us if we broadcasted a stale state. If our counterparty + /// force-closes the channel and broadcasts a commitment transaction we do not have to wait any + /// time to claim our non-HTLC-encumbered funds. + /// + /// This value will be `None` for outbound channels until the counterparty accepts the channel. + #[prost(uint32, optional, tag = "19")] + pub force_close_spend_delay: ::core::option::Option, + /// The smallest value HTLC (in msat) the remote peer will accept, for this channel. + /// + /// This field is only `None` before we have received either the `OpenChannel` or + /// `AcceptChannel` message from the remote peer. + #[prost(uint64, optional, tag = "20")] + pub counterparty_outbound_htlc_minimum_msat: ::core::option::Option, + /// The largest value HTLC (in msat) the remote peer currently will accept, for this channel. + #[prost(uint64, optional, tag = "21")] + pub counterparty_outbound_htlc_maximum_msat: ::core::option::Option, + /// The value, in satoshis, that must always be held in the channel for our counterparty. This + /// value ensures that if our counterparty broadcasts a revoked state, we can punish them by + /// claiming at least this value on chain. + /// + /// This value is not included in `inbound_capacity_msat` as it can never be spent. + #[prost(uint64, tag = "22")] + pub counterparty_unspendable_punishment_reserve: u64, + /// Base routing fee in millisatoshis. + #[prost(uint32, optional, tag = "23")] + pub counterparty_forwarding_info_fee_base_msat: ::core::option::Option, + /// Proportional fee, in millionths of a satoshi the channel will charge per transferred satoshi. + #[prost(uint32, optional, tag = "24")] + pub counterparty_forwarding_info_fee_proportional_millionths: ::core::option::Option, + /// The minimum difference in CLTV expiry between an ingoing HTLC and its outgoing counterpart, + /// such that the outgoing HTLC is forwardable to this counterparty. + #[prost(uint32, optional, tag = "25")] + pub counterparty_forwarding_info_cltv_expiry_delta: ::core::option::Option, +} +/// ChannelConfig represents the configuration settings for a channel in a Lightning Network node. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ChannelConfig { + /// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound + /// over the channel. + /// See more: + #[prost(uint32, optional, tag = "1")] + pub forwarding_fee_proportional_millionths: ::core::option::Option, + /// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, + /// in excess of forwarding_fee_proportional_millionths. + /// See more: + #[prost(uint32, optional, tag = "2")] + pub forwarding_fee_base_msat: ::core::option::Option, + /// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded + /// over the channel this config applies to. + /// See more: + #[prost(uint32, optional, tag = "3")] + pub cltv_expiry_delta: ::core::option::Option, + /// The maximum additional fee we’re willing to pay to avoid waiting for the counterparty’s + /// to_self_delay to reclaim funds. + /// See more: + #[prost(uint64, optional, tag = "4")] + pub force_close_avoidance_max_fee_satoshis: ::core::option::Option, + /// If set, allows this channel’s counterparty to skim an additional fee off this node’s + /// inbound HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users. + /// See more: + #[prost(bool, optional, tag = "5")] + pub accept_underpaying_htlcs: ::core::option::Option, + /// Limit our total exposure to potential loss to on-chain fees on close, including + /// in-flight HTLCs which are burned to fees as they are too small to claim on-chain + /// and fees on commitment transaction(s) broadcasted by our counterparty in excess of + /// our own fee estimate. + /// See more: + #[prost(oneof = "channel_config::MaxDustHtlcExposure", tags = "6, 7")] + pub max_dust_htlc_exposure: ::core::option::Option, +} +/// Nested message and enum types in `ChannelConfig`. +pub mod channel_config { + /// Limit our total exposure to potential loss to on-chain fees on close, including + /// in-flight HTLCs which are burned to fees as they are too small to claim on-chain + /// and fees on commitment transaction(s) broadcasted by our counterparty in excess of + /// our own fee estimate. + /// See more: + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum MaxDustHtlcExposure { + /// This sets a fixed limit on the total dust exposure in millisatoshis. + /// See more: + #[prost(uint64, tag = "6")] + FixedLimitMsat(u64), + /// This sets a multiplier on the ConfirmationTarget::OnChainSweep feerate (in sats/KW) to determine the maximum allowed dust exposure. + /// See more: + #[prost(uint64, tag = "7")] + FeeRateMultiplier(u64), + } +} +/// Represent a transaction outpoint. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OutPoint { + /// The referenced transaction's txid. + #[prost(string, tag = "1")] + pub txid: ::prost::alloc::string::String, + /// The index of the referenced output in its transaction's vout. + #[prost(uint32, tag = "2")] + pub vout: u32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BestBlock { + /// The block’s hash + #[prost(string, tag = "1")] + pub block_hash: ::prost::alloc::string::String, + /// The height at which the block was confirmed. + #[prost(uint32, tag = "2")] + pub height: u32, +} +/// Represents the direction of a payment. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum PaymentDirection { + /// The payment is inbound. + Inbound = 0, + /// The payment is outbound. + Outbound = 1, +} +impl PaymentDirection { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + PaymentDirection::Inbound => "INBOUND", + PaymentDirection::Outbound => "OUTBOUND", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "INBOUND" => Some(Self::Inbound), + "OUTBOUND" => Some(Self::Outbound), + _ => None, + } + } +} +/// Represents the current status of a payment. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum PaymentStatus { + /// The payment is still pending. + Pending = 0, + /// The payment succeeded. + Succeeded = 1, + /// The payment failed. + Failed = 2, +} +impl PaymentStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + PaymentStatus::Pending => "PENDING", + PaymentStatus::Succeeded => "SUCCEEDED", + PaymentStatus::Failed => "FAILED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "PENDING" => Some(Self::Pending), + "SUCCEEDED" => Some(Self::Succeeded), + "FAILED" => Some(Self::Failed), + _ => None, + } + } +} From 45efc09663b8aeea49c888e48a40fc66f8ffe769 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 29 Oct 2024 23:46:58 -0700 Subject: [PATCH 063/203] Adjust ldk-node-server acc. to proto path changes. --- ldk-server/server/src/api/bolt11_receive.rs | 2 +- ldk-server/server/src/api/bolt11_send.rs | 2 +- ldk-server/server/src/api/bolt12_receive.rs | 2 +- ldk-server/server/src/api/bolt12_send.rs | 2 +- ldk-server/server/src/api/close_channel.rs | 2 +- ldk-server/server/src/api/get_node_info.rs | 3 +- .../server/src/api/get_payment_details.rs | 2 +- ldk-server/server/src/api/list_channels.rs | 2 +- ldk-server/server/src/api/list_payments.rs | 2 +- ldk-server/server/src/api/onchain_receive.rs | 2 +- ldk-server/server/src/api/onchain_send.rs | 2 +- ldk-server/server/src/api/open_channel.rs | 2 +- .../server/src/api/update_channel_config.rs | 9 ++- ldk-server/server/src/util/proto_adapter.rs | 74 ++++++++++--------- 14 files changed, 58 insertions(+), 50 deletions(-) diff --git a/ldk-server/server/src/api/bolt11_receive.rs b/ldk-server/server/src/api/bolt11_receive.rs index 8778c6761..7c8ef29e9 100644 --- a/ldk-server/server/src/api/bolt11_receive.rs +++ b/ldk-server/server/src/api/bolt11_receive.rs @@ -1,5 +1,5 @@ use ldk_node::Node; -use protos::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; +use protos::api::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; use std::sync::Arc; pub(crate) const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; diff --git a/ldk-server/server/src/api/bolt11_send.rs b/ldk-server/server/src/api/bolt11_send.rs index fc3e09bf0..2376f167d 100644 --- a/ldk-server/server/src/api/bolt11_send.rs +++ b/ldk-server/server/src/api/bolt11_send.rs @@ -1,7 +1,7 @@ use bytes::Bytes; use ldk_node::lightning_invoice::Bolt11Invoice; use ldk_node::Node; -use protos::{Bolt11SendRequest, Bolt11SendResponse}; +use protos::api::{Bolt11SendRequest, Bolt11SendResponse}; use std::str::FromStr; use std::sync::Arc; diff --git a/ldk-server/server/src/api/bolt12_receive.rs b/ldk-server/server/src/api/bolt12_receive.rs index 203a81fc9..5d495312a 100644 --- a/ldk-server/server/src/api/bolt12_receive.rs +++ b/ldk-server/server/src/api/bolt12_receive.rs @@ -1,5 +1,5 @@ use ldk_node::Node; -use protos::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; +use protos::api::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; use std::sync::Arc; pub(crate) const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive"; diff --git a/ldk-server/server/src/api/bolt12_send.rs b/ldk-server/server/src/api/bolt12_send.rs index 8a0982338..423c57936 100644 --- a/ldk-server/server/src/api/bolt12_send.rs +++ b/ldk-server/server/src/api/bolt12_send.rs @@ -1,7 +1,7 @@ use bytes::Bytes; use ldk_node::lightning::offers::offer::Offer; use ldk_node::Node; -use protos::{Bolt12SendRequest, Bolt12SendResponse}; +use protos::api::{Bolt12SendRequest, Bolt12SendResponse}; use std::str::FromStr; use std::sync::Arc; diff --git a/ldk-server/server/src/api/close_channel.rs b/ldk-server/server/src/api/close_channel.rs index 2d58bc1c8..e9f6e3d7d 100644 --- a/ldk-server/server/src/api/close_channel.rs +++ b/ldk-server/server/src/api/close_channel.rs @@ -1,6 +1,6 @@ use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::{Node, UserChannelId}; -use protos::{CloseChannelRequest, CloseChannelResponse}; +use protos::api::{CloseChannelRequest, CloseChannelResponse}; use std::str::FromStr; use std::sync::Arc; diff --git a/ldk-server/server/src/api/get_node_info.rs b/ldk-server/server/src/api/get_node_info.rs index c221c9ddb..eabc25ea5 100644 --- a/ldk-server/server/src/api/get_node_info.rs +++ b/ldk-server/server/src/api/get_node_info.rs @@ -1,5 +1,6 @@ use ldk_node::Node; -use protos::{BestBlock, GetNodeInfoRequest, GetNodeInfoResponse}; +use protos::api::{GetNodeInfoRequest, GetNodeInfoResponse}; +use protos::types::BestBlock; use std::sync::Arc; pub(crate) const GET_NODE_INFO: &str = "GetNodeInfo"; diff --git a/ldk-server/server/src/api/get_payment_details.rs b/ldk-server/server/src/api/get_payment_details.rs index 52008a3c4..d1f2734db 100644 --- a/ldk-server/server/src/api/get_payment_details.rs +++ b/ldk-server/server/src/api/get_payment_details.rs @@ -2,7 +2,7 @@ use crate::util::proto_adapter::payment_to_proto; use hex::FromHex; use ldk_node::lightning::ln::channelmanager::PaymentId; use ldk_node::Node; -use protos::{GetPaymentDetailsRequest, GetPaymentDetailsResponse}; +use protos::api::{GetPaymentDetailsRequest, GetPaymentDetailsResponse}; use std::sync::Arc; pub(crate) const GET_PAYMENT_DETAILS_PATH: &str = "GetPaymentDetails"; diff --git a/ldk-server/server/src/api/list_channels.rs b/ldk-server/server/src/api/list_channels.rs index 32688d6bc..90520c5b6 100644 --- a/ldk-server/server/src/api/list_channels.rs +++ b/ldk-server/server/src/api/list_channels.rs @@ -1,6 +1,6 @@ use crate::util::proto_adapter::channel_to_proto; use ldk_node::Node; -use protos::{ListChannelsRequest, ListChannelsResponse}; +use protos::api::{ListChannelsRequest, ListChannelsResponse}; use std::sync::Arc; pub(crate) const LIST_CHANNELS_PATH: &str = "ListChannels"; diff --git a/ldk-server/server/src/api/list_payments.rs b/ldk-server/server/src/api/list_payments.rs index 2667d58f4..671741d61 100644 --- a/ldk-server/server/src/api/list_payments.rs +++ b/ldk-server/server/src/api/list_payments.rs @@ -1,6 +1,6 @@ use crate::util::proto_adapter::payment_to_proto; use ldk_node::Node; -use protos::{ListPaymentsRequest, ListPaymentsResponse}; +use protos::api::{ListPaymentsRequest, ListPaymentsResponse}; use std::sync::Arc; pub(crate) const LIST_PAYMENTS_PATH: &str = "ListPayments"; diff --git a/ldk-server/server/src/api/onchain_receive.rs b/ldk-server/server/src/api/onchain_receive.rs index 565bfd930..884552f4c 100644 --- a/ldk-server/server/src/api/onchain_receive.rs +++ b/ldk-server/server/src/api/onchain_receive.rs @@ -1,5 +1,5 @@ use ldk_node::Node; -use protos::{OnchainReceiveRequest, OnchainReceiveResponse}; +use protos::api::{OnchainReceiveRequest, OnchainReceiveResponse}; use std::sync::Arc; pub(crate) const ONCHAIN_RECEIVE_PATH: &str = "OnchainReceive"; diff --git a/ldk-server/server/src/api/onchain_send.rs b/ldk-server/server/src/api/onchain_send.rs index 0e40d6310..7d9348f8a 100644 --- a/ldk-server/server/src/api/onchain_send.rs +++ b/ldk-server/server/src/api/onchain_send.rs @@ -1,6 +1,6 @@ use ldk_node::bitcoin::Address; use ldk_node::Node; -use protos::{OnchainSendRequest, OnchainSendResponse}; +use protos::api::{OnchainSendRequest, OnchainSendResponse}; use std::str::FromStr; use std::sync::Arc; diff --git a/ldk-server/server/src/api/open_channel.rs b/ldk-server/server/src/api/open_channel.rs index 0f744594f..214746d2a 100644 --- a/ldk-server/server/src/api/open_channel.rs +++ b/ldk-server/server/src/api/open_channel.rs @@ -2,7 +2,7 @@ use bytes::Bytes; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_node::Node; -use protos::{OpenChannelRequest, OpenChannelResponse}; +use protos::api::{OpenChannelRequest, OpenChannelResponse}; use std::str::FromStr; use std::sync::Arc; diff --git a/ldk-server/server/src/api/update_channel_config.rs b/ldk-server/server/src/api/update_channel_config.rs index 1f8cec293..306cdbba1 100644 --- a/ldk-server/server/src/api/update_channel_config.rs +++ b/ldk-server/server/src/api/update_channel_config.rs @@ -1,8 +1,8 @@ use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; use ldk_node::{Node, UserChannelId}; -use protos::channel_config::MaxDustHtlcExposure; -use protos::{UpdateChannelConfigRequest, UpdateChannelConfigResponse}; +use protos::api::{UpdateChannelConfigRequest, UpdateChannelConfigResponse}; +use protos::types::channel_config::MaxDustHtlcExposure; use std::str::FromStr; use std::sync::Arc; @@ -38,7 +38,7 @@ pub(crate) fn handle_update_channel_config_request( } fn build_updated_channel_config( - current_config: ChannelConfig, proto_channel_config: protos::ChannelConfig, + current_config: ChannelConfig, proto_channel_config: protos::types::ChannelConfig, ) -> ChannelConfig { let max_dust_htlc_exposure = proto_channel_config .max_dust_htlc_exposure @@ -53,7 +53,8 @@ fn build_updated_channel_config( .unwrap_or(current_config.max_dust_htlc_exposure); let cltv_expiry_delta = proto_channel_config - .cltv_expiry_delta.map(|c| u16::try_from(c).unwrap()) + .cltv_expiry_delta + .map(|c| u16::try_from(c).unwrap()) .unwrap_or(current_config.cltv_expiry_delta); ChannelConfig { diff --git a/ldk-server/server/src/util/proto_adapter.rs b/ldk-server/server/src/util/proto_adapter.rs index 9f9efe73d..e7855640b 100644 --- a/ldk-server/server/src/util/proto_adapter.rs +++ b/ldk-server/server/src/util/proto_adapter.rs @@ -3,10 +3,10 @@ use hex::prelude::*; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; use ldk_node::payment::{PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus}; use ldk_node::ChannelDetails; -use protos::payment_kind::Kind::{ +use protos::types::payment_kind::Kind::{ Bolt11, Bolt11Jit, Bolt12Offer, Bolt12Refund, Onchain, Spontaneous, }; -use protos::{Channel, LspFeeLimits, OutPoint, Payment}; +use protos::types::{Channel, LspFeeLimits, OutPoint, Payment}; pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { Channel { @@ -45,8 +45,10 @@ pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { } } -pub(crate) fn channel_config_to_proto(channel_config: ChannelConfig) -> protos::ChannelConfig { - protos::ChannelConfig { +pub(crate) fn channel_config_to_proto( + channel_config: ChannelConfig, +) -> protos::types::ChannelConfig { + protos::types::ChannelConfig { forwarding_fee_proportional_millionths: Some( channel_config.forwarding_fee_proportional_millionths, ), @@ -58,11 +60,11 @@ pub(crate) fn channel_config_to_proto(channel_config: ChannelConfig) -> protos:: accept_underpaying_htlcs: Some(channel_config.accept_underpaying_htlcs), max_dust_htlc_exposure: match channel_config.max_dust_htlc_exposure { MaxDustHTLCExposure::FixedLimit { limit_msat } => { - Some(protos::channel_config::MaxDustHtlcExposure::FixedLimitMsat(limit_msat)) - }, - MaxDustHTLCExposure::FeeRateMultiplier { multiplier } => { - Some(protos::channel_config::MaxDustHtlcExposure::FeeRateMultiplier(multiplier)) + Some(protos::types::channel_config::MaxDustHtlcExposure::FixedLimitMsat(limit_msat)) }, + MaxDustHTLCExposure::FeeRateMultiplier { multiplier } => Some( + protos::types::channel_config::MaxDustHtlcExposure::FeeRateMultiplier(multiplier), + ), }, } } @@ -73,43 +75,47 @@ pub(crate) fn payment_to_proto(payment: PaymentDetails) -> Payment { kind: Some(payment_kind_to_proto(payment.kind)), amount_msat: payment.amount_msat, direction: match payment.direction { - PaymentDirection::Inbound => protos::PaymentDirection::Inbound.into(), - PaymentDirection::Outbound => protos::PaymentDirection::Outbound.into(), + PaymentDirection::Inbound => protos::types::PaymentDirection::Inbound.into(), + PaymentDirection::Outbound => protos::types::PaymentDirection::Outbound.into(), }, status: match payment.status { - PaymentStatus::Pending => protos::PaymentStatus::Pending.into(), - PaymentStatus::Succeeded => protos::PaymentStatus::Succeeded.into(), - PaymentStatus::Failed => protos::PaymentStatus::Failed.into(), + PaymentStatus::Pending => protos::types::PaymentStatus::Pending.into(), + PaymentStatus::Succeeded => protos::types::PaymentStatus::Succeeded.into(), + PaymentStatus::Failed => protos::types::PaymentStatus::Failed.into(), }, latest_update_timestamp: payment.latest_update_timestamp, } } -pub(crate) fn payment_kind_to_proto(payment_kind: PaymentKind) -> protos::PaymentKind { +pub(crate) fn payment_kind_to_proto(payment_kind: PaymentKind) -> protos::types::PaymentKind { match payment_kind { - PaymentKind::Onchain => protos::PaymentKind { kind: Some(Onchain(protos::Onchain {})) }, - PaymentKind::Bolt11 { hash, preimage, secret } => protos::PaymentKind { - kind: Some(Bolt11(protos::Bolt11 { - hash: hash.to_string(), - preimage: preimage.map(|p| p.to_string()), - secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), - })), + PaymentKind::Onchain => { + protos::types::PaymentKind { kind: Some(Onchain(protos::types::Onchain {})) } }, - PaymentKind::Bolt11Jit { hash, preimage, secret, lsp_fee_limits } => protos::PaymentKind { - kind: Some(Bolt11Jit(protos::Bolt11Jit { + PaymentKind::Bolt11 { hash, preimage, secret } => protos::types::PaymentKind { + kind: Some(Bolt11(protos::types::Bolt11 { hash: hash.to_string(), preimage: preimage.map(|p| p.to_string()), secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), - lsp_fee_limits: Some(LspFeeLimits { - max_total_opening_fee_msat: lsp_fee_limits.max_total_opening_fee_msat, - max_proportional_opening_fee_ppm_msat: lsp_fee_limits - .max_proportional_opening_fee_ppm_msat, - }), })), }, + PaymentKind::Bolt11Jit { hash, preimage, secret, lsp_fee_limits } => { + protos::types::PaymentKind { + kind: Some(Bolt11Jit(protos::types::Bolt11Jit { + hash: hash.to_string(), + preimage: preimage.map(|p| p.to_string()), + secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), + lsp_fee_limits: Some(LspFeeLimits { + max_total_opening_fee_msat: lsp_fee_limits.max_total_opening_fee_msat, + max_proportional_opening_fee_ppm_msat: lsp_fee_limits + .max_proportional_opening_fee_ppm_msat, + }), + })), + } + }, PaymentKind::Bolt12Offer { hash, preimage, secret, offer_id, payer_note, quantity } => { - protos::PaymentKind { - kind: Some(Bolt12Offer(protos::Bolt12Offer { + protos::types::PaymentKind { + kind: Some(Bolt12Offer(protos::types::Bolt12Offer { hash: hash.map(|h| h.to_string()), preimage: preimage.map(|p| p.to_string()), secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), @@ -120,8 +126,8 @@ pub(crate) fn payment_kind_to_proto(payment_kind: PaymentKind) -> protos::Paymen } }, PaymentKind::Bolt12Refund { hash, preimage, secret, payer_note, quantity } => { - protos::PaymentKind { - kind: Some(Bolt12Refund(protos::Bolt12Refund { + protos::types::PaymentKind { + kind: Some(Bolt12Refund(protos::types::Bolt12Refund { hash: hash.map(|h| h.to_string()), preimage: preimage.map(|p| p.to_string()), secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), @@ -130,8 +136,8 @@ pub(crate) fn payment_kind_to_proto(payment_kind: PaymentKind) -> protos::Paymen })), } }, - PaymentKind::Spontaneous { hash, preimage } => protos::PaymentKind { - kind: Some(Spontaneous(protos::Spontaneous { + PaymentKind::Spontaneous { hash, preimage } => protos::types::PaymentKind { + kind: Some(Spontaneous(protos::types::Spontaneous { hash: hash.to_string(), preimage: preimage.map(|p| p.to_string()), })), From 009bf3bc87499672079f69359ee722dd8ec3ebda Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 29 Oct 2024 23:47:44 -0700 Subject: [PATCH 064/203] Adjust client acc. to proto path changes. --- ldk-server/client/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/client/src/client.rs b/ldk-server/client/src/client.rs index ea97b7a88..b7a283064 100644 --- a/ldk-server/client/src/client.rs +++ b/ldk-server/client/src/client.rs @@ -1,7 +1,7 @@ use prost::Message; use crate::error::LdkNodeServerError; -use protos::{ +use protos::api::{ Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse, Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, CloseChannelRequest, CloseChannelResponse, ListChannelsRequest, ListChannelsResponse, From da7314954ce9143f7ae91af5544170a63cef3eaf Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 29 Oct 2024 23:48:39 -0700 Subject: [PATCH 065/203] Adjust cli acc. to proto path changes. --- ldk-server/cli/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/cli/src/main.rs b/ldk-server/cli/src/main.rs index 0db105dee..e7cd9a717 100644 --- a/ldk-server/cli/src/main.rs +++ b/ldk-server/cli/src/main.rs @@ -1,7 +1,7 @@ use clap::{Parser, Subcommand}; use client::client::LdkNodeServerClient; use client::error::LdkNodeServerError; -use client::protos::{ +use client::protos::api::{ Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, Bolt12SendRequest, OnchainReceiveRequest, OnchainSendRequest, OpenChannelRequest, }; From 452395ce18310cdb105ab5f161eb296d0e070769 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:36:17 -0800 Subject: [PATCH 066/203] Add proto definitions for ErrorResponse. --- ldk-server/protos/build.rs | 7 ++- ldk-server/protos/src/error.rs | 66 +++++++++++++++++++++++++ ldk-server/protos/src/lib.rs | 1 + ldk-server/protos/src/proto/error.proto | 45 +++++++++++++++++ 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 ldk-server/protos/src/error.rs create mode 100644 ldk-server/protos/src/proto/error.proto diff --git a/ldk-server/protos/build.rs b/ldk-server/protos/build.rs index 70ddc33e0..3d8ce462a 100644 --- a/ldk-server/protos/build.rs +++ b/ldk-server/protos/build.rs @@ -14,11 +14,16 @@ fn main() { fn generate_protos() { prost_build::Config::new() .bytes(&["."]) - .compile_protos(&["src/proto/api.proto", "src/proto/types.proto"], &["src/proto/"]) + .compile_protos( + &["src/proto/api.proto", "src/proto/types.proto", "src/proto/error.proto"], + &["src/proto/"], + ) .expect("protobuf compilation failed"); println!("OUT_DIR: {}", &env::var("OUT_DIR").unwrap()); let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("api.rs"); fs::copy(from_path, "src/api.rs").unwrap(); let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("types.rs"); fs::copy(from_path, "src/types.rs").unwrap(); + let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("error.rs"); + fs::copy(from_path, "src/error.rs").unwrap(); } diff --git a/ldk-server/protos/src/error.rs b/ldk-server/protos/src/error.rs new file mode 100644 index 000000000..a78c75a32 --- /dev/null +++ b/ldk-server/protos/src/error.rs @@ -0,0 +1,66 @@ +/// When HttpStatusCode is not ok (200), the response `content` contains a serialized `ErrorResponse` +/// with the relevant ErrorCode and `message` +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ErrorResponse { + /// The error message containing a generic description of the error condition in English. + /// It is intended for a human audience only and should not be parsed to extract any information + /// programmatically. Client-side code may use it for logging only. + #[prost(string, tag = "1")] + pub message: ::prost::alloc::string::String, + /// The error code uniquely identifying an error condition. + /// It is meant to be read and understood programmatically by code that detects/handles errors by + /// type. + /// + /// **Caution**: If a new type of `error_code` is introduced in the `ErrorCode` enum, `error_code` field will be set to + /// `UnknownError`. + #[prost(enumeration = "ErrorCode", tag = "2")] + pub error_code: i32, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ErrorCode { + /// Will neve be used as `error_code` by server. + /// + /// **Caution**: If a new type of `error_code` is introduced in the `ErrorCode` enum, `error_code` field will be set to + /// `UnknownError`. + UnknownError = 0, + /// Used in the following cases: + /// - The request was missing a required argument. + /// - The specified argument was invalid, incomplete or in the wrong format. + /// - The request body of api cannot be deserialized into corresponding protobuf object. + /// - The request does not follow api contract. + InvalidRequestError = 1, + /// Used when authentication fails or in case of an unauthorized request. + AuthError = 2, + /// Used to represent an error while doing a Lightning operation. + LightningError = 3, + /// Used when an internal server error occurred. The client is probably at no fault. + InternalServerError = 4, +} +impl ErrorCode { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + ErrorCode::UnknownError => "UNKNOWN_ERROR", + ErrorCode::InvalidRequestError => "INVALID_REQUEST_ERROR", + ErrorCode::AuthError => "AUTH_ERROR", + ErrorCode::LightningError => "LIGHTNING_ERROR", + ErrorCode::InternalServerError => "INTERNAL_SERVER_ERROR", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UNKNOWN_ERROR" => Some(Self::UnknownError), + "INVALID_REQUEST_ERROR" => Some(Self::InvalidRequestError), + "AUTH_ERROR" => Some(Self::AuthError), + "LIGHTNING_ERROR" => Some(Self::LightningError), + "INTERNAL_SERVER_ERROR" => Some(Self::InternalServerError), + _ => None, + } + } +} diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/protos/src/lib.rs index 8389f117b..d66938372 100644 --- a/ldk-server/protos/src/lib.rs +++ b/ldk-server/protos/src/lib.rs @@ -1,2 +1,3 @@ pub mod api; +pub mod error; pub mod types; diff --git a/ldk-server/protos/src/proto/error.proto b/ldk-server/protos/src/proto/error.proto new file mode 100644 index 000000000..f6f85cd10 --- /dev/null +++ b/ldk-server/protos/src/proto/error.proto @@ -0,0 +1,45 @@ +syntax = "proto3"; +package error; + +// When HttpStatusCode is not ok (200), the response `content` contains a serialized `ErrorResponse` +// with the relevant ErrorCode and `message` +message ErrorResponse { + + // The error message containing a generic description of the error condition in English. + // It is intended for a human audience only and should not be parsed to extract any information + // programmatically. Client-side code may use it for logging only. + string message = 1; + + // The error code uniquely identifying an error condition. + // It is meant to be read and understood programmatically by code that detects/handles errors by + // type. + // + // **Caution**: If a new type of `error_code` is introduced in the `ErrorCode` enum, `error_code` field will be set to + // `UnknownError`. + ErrorCode error_code = 2; +} + +enum ErrorCode { + + // Will neve be used as `error_code` by server. + // + // **Caution**: If a new type of `error_code` is introduced in the `ErrorCode` enum, `error_code` field will be set to + // `UnknownError`. + UNKNOWN_ERROR = 0; + + // Used in the following cases: + // - The request was missing a required argument. + // - The specified argument was invalid, incomplete or in the wrong format. + // - The request body of api cannot be deserialized into corresponding protobuf object. + // - The request does not follow api contract. + INVALID_REQUEST_ERROR = 1; + + // Used when authentication fails or in case of an unauthorized request. + AUTH_ERROR = 2; + + // Used to represent an error while doing a Lightning operation. + LIGHTNING_ERROR = 3; + + // Used when an internal server error occurred. The client is probably at no fault. + INTERNAL_SERVER_ERROR = 4; +} From affb0b58b6dfab333b5e188fb3840cac8ea9ff48 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:36:46 -0800 Subject: [PATCH 067/203] Add error struct for LdkServerError. --- ldk-server/server/src/api/error.rs | 25 +++++++++++++++++++++++++ ldk-server/server/src/api/mod.rs | 1 + 2 files changed, 26 insertions(+) create mode 100644 ldk-server/server/src/api/error.rs diff --git a/ldk-server/server/src/api/error.rs b/ldk-server/server/src/api/error.rs new file mode 100644 index 000000000..d7ad95fef --- /dev/null +++ b/ldk-server/server/src/api/error.rs @@ -0,0 +1,25 @@ +pub(crate) struct LdkServerError { + // The error message containing a generic description of the error condition in English. + // It is intended for a human audience only and should not be parsed to extract any information + // programmatically. Client-side code may use it for logging only. + pub(crate) message: String, + + // The error code uniquely identifying an error condition. + // It is meant to be read and understood programmatically by code that detects/handles errors by + // type. + pub(crate) error_code: LdkServerErrorCode, +} + +pub(crate) enum LdkServerErrorCode { + /// Please refer to [`protos::error::ErrorCode::InvalidRequestError`]. + InvalidRequestError, + + /// Please refer to [`protos::error::ErrorCode::AuthError`]. + AuthError, + + /// Please refer to [`protos::error::ErrorCode::LightningError`]. + LightningError, + + /// Please refer to [`protos::error::ErrorCode::InternalServerError`]. + InternalServerError, +} diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/server/src/api/mod.rs index e7561fd32..cd1e0da7f 100644 --- a/ldk-server/server/src/api/mod.rs +++ b/ldk-server/server/src/api/mod.rs @@ -3,6 +3,7 @@ pub(crate) mod bolt11_send; pub(crate) mod bolt12_receive; pub(crate) mod bolt12_send; pub(crate) mod close_channel; +pub(crate) mod error; pub(crate) mod get_node_info; pub(crate) mod get_payment_details; pub(crate) mod list_channels; From cf3a68dc7b390eabdaf40489d8d4ea93116f4b2c Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:55:14 -0800 Subject: [PATCH 068/203] RIP Esplora, configure bitcoin-d as chain source. --- ldk-server/server/src/main.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/ldk-server/server/src/main.rs b/ldk-server/server/src/main.rs index 4615b02f2..d486c1dee 100644 --- a/ldk-server/server/src/main.rs +++ b/ldk-server/server/src/main.rs @@ -22,9 +22,9 @@ use std::sync::Arc; fn main() { let args: Vec = std::env::args().collect(); - if args.len() < 6 { + if args.len() < 8 { eprintln!( - "Usage: {} storage_path listening_addr rest_svc_addr network esplora_server_url", + "Usage: {} storage_path listening_addr rest_svc_addr network bitcoind_rpc_addr bitcoind_rpc_user bitcoind_rpc_password", args[0] ); std::process::exit(-1); @@ -59,7 +59,21 @@ fn main() { }; let mut builder = Builder::from_config(config); - builder.set_chain_source_esplora(args[5].clone(), None); + + let bitcoind_rpc_addr = match SocketAddr::from_str(&args[5]) { + Ok(addr) => addr, + Err(_) => { + eprintln!("Failed to parse bitcoind_rpc_addr: {}", args[3]); + std::process::exit(-1); + }, + }; + + builder.set_chain_source_bitcoind_rpc( + bitcoind_rpc_addr.ip().to_string(), + bitcoind_rpc_addr.port(), + args[6].clone(), + args[7].clone(), + ); let runtime = match tokio::runtime::Builder::new_multi_thread().enable_all().build() { Ok(runtime) => Arc::new(runtime), From d45c9a155fbbe4224150758fc7c177c3640ac764 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 13 Nov 2024 20:55:46 -0800 Subject: [PATCH 069/203] Add interface for PaginatedKVStore. Pagination in list is required because: 1. To bound query size for database. 2. Bound execution time of request on server. 3. Bound in-memory footprint of request on server. 4. Bound response size to client. --- ldk-server/server/src/io/mod.rs | 1 + .../server/src/io/paginated_kv_store.rs | 102 ++++++++++++++++++ ldk-server/server/src/main.rs | 1 + 3 files changed, 104 insertions(+) create mode 100644 ldk-server/server/src/io/mod.rs create mode 100644 ldk-server/server/src/io/paginated_kv_store.rs diff --git a/ldk-server/server/src/io/mod.rs b/ldk-server/server/src/io/mod.rs new file mode 100644 index 000000000..ff65caf67 --- /dev/null +++ b/ldk-server/server/src/io/mod.rs @@ -0,0 +1 @@ +pub(crate) mod paginated_kv_store; diff --git a/ldk-server/server/src/io/paginated_kv_store.rs b/ldk-server/server/src/io/paginated_kv_store.rs new file mode 100644 index 000000000..f0792d6bf --- /dev/null +++ b/ldk-server/server/src/io/paginated_kv_store.rs @@ -0,0 +1,102 @@ +use std::io; + +/// Provides an interface that allows storage and retrieval of persisted values that are associated +/// with given keys, with support for pagination with time-based ordering. +/// +/// In order to avoid collisions, the key space is segmented based on the given `primary_namespace`s +/// and `secondary_namespace`s. Implementations of this trait are free to handle them in different +/// ways, as long as per-namespace key uniqueness is asserted. +/// +/// Keys and namespaces are required to be valid ASCII strings in the range of +/// [`KVSTORE_NAMESPACE_KEY_ALPHABET`] and no longer than [`KVSTORE_NAMESPACE_KEY_MAX_LEN`]. Empty +/// primary namespaces and secondary namespaces (`""`) are considered valid; however, if +/// `primary_namespace` is empty, `secondary_namespace` must also be empty. This means that concerns +/// should always be separated by primary namespace first, before secondary namespaces are used. +/// While the number of primary namespaces will be relatively small and determined at compile time, +/// there may be many secondary namespaces per primary namespace. Note that per-namespace uniqueness +/// needs to also hold for keys *and* namespaces in any given namespace, i.e., conflicts between keys +/// and equally named primary or secondary namespaces must be avoided. +/// +/// **Note:** This trait extends the functionality of [`KVStore`] by adding support for +/// paginated listing of keys based on a monotonic counter or logical timestamp. This is useful +/// when dealing with a large number of keys that cannot be efficiently retrieved all at once. +/// +/// See also [`KVStore`]. +/// +/// [`KVStore`]: ldk_node::lightning::util::persist::KVStore +/// [`KVSTORE_NAMESPACE_KEY_ALPHABET`]: ldk_node::lightning::util::persist::KVSTORE_NAMESPACE_KEY_ALPHABET +/// [`KVSTORE_NAMESPACE_KEY_MAX_LEN`]: ldk_node::lightning::util::persist::KVSTORE_NAMESPACE_KEY_MAX_LEN +pub trait PaginatedKVStore { + /// Returns the data stored for the given `primary_namespace`, `secondary_namespace`, and `key`. + /// + /// Returns an [`ErrorKind::NotFound`] if the given `key` could not be found in the given + /// `primary_namespace` and `secondary_namespace`. + /// + /// [`ErrorKind::NotFound`]: io::ErrorKind::NotFound + fn read( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> Result, io::Error>; + + /// Persists the given data under the given `key` with an associated `time`. + /// + /// The `time` parameter is a `i64` representing a monotonic counter or logical timestamp. + /// It is used to track the order of keys for list operations. Implementations should store the + /// `time` value and use it for ordering in the `list` method. + /// + /// Will create the given `primary_namespace` and `secondary_namespace` if not already present + /// in the store. + fn write( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, time: i64, buf: &[u8], + ) -> Result<(), io::Error>; + + /// Removes any data that had previously been persisted under the given `key`. + /// + /// If the `lazy` flag is set to `true`, the backend implementation might choose to lazily + /// remove the given `key` at some point in time after the method returns, e.g., as part of an + /// eventual batch deletion of multiple keys. As a consequence, subsequent calls to + /// [`PaginatedKVStore::list`] might include the removed key until the changes are actually persisted. + /// + /// Note that while setting the `lazy` flag reduces the I/O burden of multiple subsequent + /// `remove` calls, it also influences the atomicity guarantees as lazy `remove`s could + /// potentially get lost on crash after the method returns. Therefore, this flag should only be + /// set for `remove` operations that can be safely replayed at a later time. + /// + /// Returns successfully if no data will be stored for the given `primary_namespace`, + /// `secondary_namespace`, and `key`, independently of whether it was present before its + /// invocation or not. + fn remove( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool, + ) -> Result<(), io::Error>; + + /// Returns a paginated list of keys that are stored under the given `secondary_namespace` in + /// `primary_namespace`, ordered in descending order of `time`. + /// + /// The `list` method returns the latest records first, based on the `time` associated with each key. + /// Pagination is controlled by the `next_page_token`, which is an `Option` + /// used to determine the starting point for the next page of results. If `next_page_token` is `None`, + /// the listing starts from the most recent entry. The `next_page_token` in the returned + /// [`ListResponse`] can be used to fetch the next page of results. + /// + /// Implementations should ensure that keys are returned in descending order of `time` and that + /// pagination tokens are correctly managed. + /// + /// Returns an empty list if `primary_namespace` or `secondary_namespace` is unknown or if + /// there are no more keys to return. + /// + /// [`ListResponse`]: struct.ListResponse.html + fn list( + &self, primary_namespace: &str, secondary_namespace: &str, next_page_token: Option, + ) -> Result; +} + +/// Represents the response from a paginated `list` operation. +/// +/// Contains the list of keys and an optional `next_page_token` that can be used to retrieve the +/// next set of keys. +pub struct ListResponse { + /// A vector of keys, ordered in descending order of `time`. + pub keys: Vec, + + /// A token that can be used to retrieve the next set of keys. + pub next_page_token: Option, +} diff --git a/ldk-server/server/src/main.rs b/ldk-server/server/src/main.rs index 4615b02f2..6331a3006 100644 --- a/ldk-server/server/src/main.rs +++ b/ldk-server/server/src/main.rs @@ -1,4 +1,5 @@ mod api; +mod io; mod service; mod util; From 9bd1d132524edb41f3571c899e8201a8b092e644 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 22 Nov 2024 15:32:06 -0800 Subject: [PATCH 070/203] Rename to LdkServer. --- ldk-server/Cargo.lock | 2 +- ldk-server/cli/src/main.rs | 8 ++++---- ldk-server/client/src/client.rs | 34 ++++++++++++++++----------------- ldk-server/client/src/error.rs | 12 ++++++------ ldk-server/client/src/lib.rs | 6 +++--- ldk-server/server/Cargo.toml | 2 +- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 3e07926ef..084674a8f 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -955,7 +955,7 @@ dependencies = [ ] [[package]] -name = "ldk-node-server" +name = "ldk-server" version = "0.1.0" dependencies = [ "bytes", diff --git a/ldk-server/cli/src/main.rs b/ldk-server/cli/src/main.rs index e7cd9a717..b8fac3734 100644 --- a/ldk-server/cli/src/main.rs +++ b/ldk-server/cli/src/main.rs @@ -1,6 +1,6 @@ use clap::{Parser, Subcommand}; -use client::client::LdkNodeServerClient; -use client::error::LdkNodeServerError; +use client::client::LdkServerClient; +use client::error::LdkServerError; use client::protos::api::{ Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, Bolt12SendRequest, OnchainReceiveRequest, OnchainSendRequest, OpenChannelRequest, @@ -78,7 +78,7 @@ enum Commands { #[tokio::main] async fn main() { let cli = Cli::parse(); - let client = LdkNodeServerClient::new(cli.base_url); + let client = LdkServerClient::new(cli.base_url); match cli.command { Commands::OnchainReceive => { @@ -141,7 +141,7 @@ async fn main() { } } -fn handle_response(response: Result) { +fn handle_response(response: Result) { match response { Ok(response) => { println!("{:?}", response); diff --git a/ldk-server/client/src/client.rs b/ldk-server/client/src/client.rs index b7a283064..2fb9c47a8 100644 --- a/ldk-server/client/src/client.rs +++ b/ldk-server/client/src/client.rs @@ -1,6 +1,6 @@ use prost::Message; -use crate::error::LdkNodeServerError; +use crate::error::LdkServerError; use protos::api::{ Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse, Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, @@ -23,15 +23,15 @@ const OPEN_CHANNEL_PATH: &str = "OpenChannel"; const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; const LIST_CHANNELS_PATH: &str = "ListChannels"; -/// Client to access a hosted instance of LDK Node Server. +/// Client to access a hosted instance of LDK Server. #[derive(Clone)] -pub struct LdkNodeServerClient { +pub struct LdkServerClient { base_url: String, client: Client, } -impl LdkNodeServerClient { - /// Constructs a [`LdkNodeServerClient`] using `base_url` as the server endpoint. +impl LdkServerClient { + /// Constructs a [`LdkServerClient`] using `base_url` as the server endpoint. pub fn new(base_url: String) -> Self { Self { base_url, client: Client::new() } } @@ -40,7 +40,7 @@ impl LdkNodeServerClient { /// For API contract/usage, refer to docs for [`OnchainReceiveRequest`] and [`OnchainReceiveResponse`]. pub async fn onchain_receive( &self, request: OnchainReceiveRequest, - ) -> Result { + ) -> Result { let url = format!("http://{}/{ONCHAIN_RECEIVE_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -49,7 +49,7 @@ impl LdkNodeServerClient { /// For API contract/usage, refer to docs for [`OnchainSendRequest`] and [`OnchainSendResponse`]. pub async fn onchain_send( &self, request: OnchainSendRequest, - ) -> Result { + ) -> Result { let url = format!("http://{}/{ONCHAIN_SEND_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -58,7 +58,7 @@ impl LdkNodeServerClient { /// For API contract/usage, refer to docs for [`Bolt11ReceiveRequest`] and [`Bolt11ReceiveResponse`]. pub async fn bolt11_receive( &self, request: Bolt11ReceiveRequest, - ) -> Result { + ) -> Result { let url = format!("http://{}/{BOLT11_RECEIVE_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -67,7 +67,7 @@ impl LdkNodeServerClient { /// For API contract/usage, refer to docs for [`Bolt11SendRequest`] and [`Bolt11SendResponse`]. pub async fn bolt11_send( &self, request: Bolt11SendRequest, - ) -> Result { + ) -> Result { let url = format!("http://{}/{BOLT11_SEND_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -76,7 +76,7 @@ impl LdkNodeServerClient { /// For API contract/usage, refer to docs for [`Bolt12ReceiveRequest`] and [`Bolt12ReceiveResponse`]. pub async fn bolt12_receive( &self, request: Bolt12ReceiveRequest, - ) -> Result { + ) -> Result { let url = format!("http://{}/{BOLT12_RECEIVE_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -85,7 +85,7 @@ impl LdkNodeServerClient { /// For API contract/usage, refer to docs for [`Bolt12SendRequest`] and [`Bolt12SendResponse`]. pub async fn bolt12_send( &self, request: Bolt12SendRequest, - ) -> Result { + ) -> Result { let url = format!("http://{}/{BOLT12_SEND_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -94,7 +94,7 @@ impl LdkNodeServerClient { /// For API contract/usage, refer to docs for [`OpenChannelRequest`] and [`OpenChannelResponse`]. pub async fn open_channel( &self, request: OpenChannelRequest, - ) -> Result { + ) -> Result { let url = format!("http://{}/{OPEN_CHANNEL_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -103,7 +103,7 @@ impl LdkNodeServerClient { /// For API contract/usage, refer to docs for [`CloseChannelRequest`] and [`CloseChannelResponse`]. pub async fn close_channel( &self, request: CloseChannelRequest, - ) -> Result { + ) -> Result { let url = format!("http://{}/{CLOSE_CHANNEL_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -112,14 +112,14 @@ impl LdkNodeServerClient { /// For API contract/usage, refer to docs for [`ListChannelsRequest`] and [`ListChannelsResponse`]. pub async fn list_channels( &self, request: ListChannelsRequest, - ) -> Result { + ) -> Result { let url = format!("http://{}/{LIST_CHANNELS_PATH}", self.base_url); self.post_request(&request, &url).await } async fn post_request( &self, request: &Rq, url: &str, - ) -> Result { + ) -> Result { let request_body = request.encode_to_vec(); let response_raw = match self .client @@ -131,7 +131,7 @@ impl LdkNodeServerClient { { Ok(response) => response, Err(e) => { - return Err(LdkNodeServerError::InternalError(e.to_string())); + return Err(LdkServerError::InternalError(e.to_string())); }, }; let status = response_raw.status(); @@ -141,7 +141,7 @@ impl LdkNodeServerClient { Ok(Rs::decode(&payload[..])?) } else { //TODO: Error handling and error response parsing. - Err(LdkNodeServerError::InternalError("Unknown Error".to_string())) + Err(LdkServerError::InternalError("Unknown Error".to_string())) } } } diff --git a/ldk-server/client/src/error.rs b/ldk-server/client/src/error.rs index c15726de6..37f916e59 100644 --- a/ldk-server/client/src/error.rs +++ b/ldk-server/client/src/error.rs @@ -1,20 +1,20 @@ use prost::DecodeError; -/// When there is an error in request to LDK Node Server, the response contains a relevant error code. +/// When there is an error in request to LDK Server, the response contains a relevant error code. #[derive(Debug)] -pub enum LdkNodeServerError { +pub enum LdkServerError { /// There is an unknown error. (Placeholder until error handling is done.) InternalError(String), } -impl From for LdkNodeServerError { +impl From for LdkServerError { fn from(err: DecodeError) -> Self { - LdkNodeServerError::InternalError(err.to_string()) + LdkServerError::InternalError(err.to_string()) } } -impl From for LdkNodeServerError { +impl From for LdkServerError { fn from(err: reqwest::Error) -> Self { - LdkNodeServerError::InternalError(err.to_string()) + LdkServerError::InternalError(err.to_string()) } } diff --git a/ldk-server/client/src/lib.rs b/ldk-server/client/src/lib.rs index 36e9f52a9..96d79388d 100644 --- a/ldk-server/client/src/lib.rs +++ b/ldk-server/client/src/lib.rs @@ -1,13 +1,13 @@ -//! Client-side library to interact with LDK Node Server. +//! Client-side library to interact with LDK Server. #![deny(rustdoc::broken_intra_doc_links)] #![deny(rustdoc::private_intra_doc_links)] #![deny(missing_docs)] -/// Implements a client ([`client::LdkNodeServerClient`]) to access a hosted instance of LDK Node Server. +/// Implements a client ([`client::LdkServerClient`]) to access a hosted instance of LDK Server. pub mod client; -/// Implements the error type ([`error::LdkNodeServerError`]) returned on interacting with [`client::LdkNodeServerClient`] +/// Implements the error type ([`error::LdkServerError`]) returned on interacting with [`client::LdkServerClient`] pub mod error; /// Request/Response structs required for interacting with the client. diff --git a/ldk-server/server/Cargo.toml b/ldk-server/server/Cargo.toml index a0b9194f6..daf71d805 100644 --- a/ldk-server/server/Cargo.toml +++ b/ldk-server/server/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "ldk-node-server" +name = "ldk-server" version = "0.1.0" edition = "2021" From 01494c87cc092847f375ab7c88dfc9fec9facfc2 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:05:09 -0800 Subject: [PATCH 071/203] Rename crates to have ldk-server- prefix. --- ldk-server/Cargo.lock | 58 +++++++++---------- ldk-server/Cargo.toml | 2 +- ldk-server/{cli => ldk-server-cli}/Cargo.toml | 4 +- .../{cli => ldk-server-cli}/src/main.rs | 6 +- .../{client => ldk-server-client}/Cargo.toml | 4 +- .../src/client.rs | 4 +- .../src/error.rs | 0 .../{client => ldk-server-client}/src/lib.rs | 6 +- .../{protos => ldk-server-protos}/Cargo.toml | 2 +- .../{protos => ldk-server-protos}/build.rs | 0 .../{protos => ldk-server-protos}/src/api.rs | 0 .../src/error.rs | 4 +- .../{protos => ldk-server-protos}/src/lib.rs | 0 .../src/proto/api.proto | 0 .../src/proto/error.proto | 0 .../src/proto/types.proto | 0 .../src/types.rs | 0 ldk-server/{server => ldk-server}/Cargo.toml | 2 +- .../src/api/bolt11_receive.rs | 2 +- .../src/api/bolt11_send.rs | 2 +- .../src/api/bolt12_receive.rs | 2 +- .../src/api/bolt12_send.rs | 2 +- .../src/api/close_channel.rs | 2 +- .../{server => ldk-server}/src/api/error.rs | 0 .../src/api/get_node_info.rs | 4 +- .../src/api/get_payment_details.rs | 2 +- .../src/api/list_channels.rs | 2 +- .../src/api/list_payments.rs | 2 +- .../{server => ldk-server}/src/api/mod.rs | 0 .../src/api/onchain_receive.rs | 2 +- .../src/api/onchain_send.rs | 2 +- .../src/api/open_channel.rs | 2 +- .../src/api/update_channel_config.rs | 6 +- .../{server => ldk-server}/src/io/mod.rs | 0 .../src/io/paginated_kv_store.rs | 0 ldk-server/{server => ldk-server}/src/main.rs | 0 .../{server => ldk-server}/src/service.rs | 0 .../{server => ldk-server}/src/util/mod.rs | 0 .../src/util/proto_adapter.rs | 56 ++++++++++-------- 39 files changed, 94 insertions(+), 86 deletions(-) rename ldk-server/{cli => ldk-server-cli}/Cargo.toml (81%) rename ldk-server/{cli => ldk-server-cli}/src/main.rs (96%) rename ldk-server/{client => ldk-server-client}/Cargo.toml (78%) rename ldk-server/{client => ldk-server-client}/src/client.rs (97%) rename ldk-server/{client => ldk-server-client}/src/error.rs (100%) rename ldk-server/{client => ldk-server-client}/src/lib.rs (58%) rename ldk-server/{protos => ldk-server-protos}/Cargo.toml (91%) rename ldk-server/{protos => ldk-server-protos}/build.rs (100%) rename ldk-server/{protos => ldk-server-protos}/src/api.rs (100%) rename ldk-server/{protos => ldk-server-protos}/src/error.rs (94%) rename ldk-server/{protos => ldk-server-protos}/src/lib.rs (100%) rename ldk-server/{protos => ldk-server-protos}/src/proto/api.proto (100%) rename ldk-server/{protos => ldk-server-protos}/src/proto/error.proto (100%) rename ldk-server/{protos => ldk-server-protos}/src/proto/types.proto (100%) rename ldk-server/{protos => ldk-server-protos}/src/types.rs (100%) rename ldk-server/{server => ldk-server}/Cargo.toml (93%) rename ldk-server/{server => ldk-server}/src/api/bolt11_receive.rs (89%) rename ldk-server/{server => ldk-server}/src/api/bolt11_send.rs (91%) rename ldk-server/{server => ldk-server}/src/api/bolt12_receive.rs (89%) rename ldk-server/{server => ldk-server}/src/api/bolt12_send.rs (92%) rename ldk-server/{server => ldk-server}/src/api/close_channel.rs (93%) rename ldk-server/{server => ldk-server}/src/api/error.rs (100%) rename ldk-server/{server => ldk-server}/src/api/get_node_info.rs (90%) rename ldk-server/{server => ldk-server}/src/api/get_payment_details.rs (89%) rename ldk-server/{server => ldk-server}/src/api/list_channels.rs (86%) rename ldk-server/{server => ldk-server}/src/api/list_payments.rs (86%) rename ldk-server/{server => ldk-server}/src/api/mod.rs (100%) rename ldk-server/{server => ldk-server}/src/api/onchain_receive.rs (83%) rename ldk-server/{server => ldk-server}/src/api/onchain_send.rs (92%) rename ldk-server/{server => ldk-server}/src/api/open_channel.rs (94%) rename ldk-server/{server => ldk-server}/src/api/update_channel_config.rs (91%) rename ldk-server/{server => ldk-server}/src/io/mod.rs (100%) rename ldk-server/{server => ldk-server}/src/io/paginated_kv_store.rs (100%) rename ldk-server/{server => ldk-server}/src/main.rs (100%) rename ldk-server/{server => ldk-server}/src/service.rs (100%) rename ldk-server/{server => ldk-server}/src/util/mod.rs (100%) rename ldk-server/{server => ldk-server}/src/util/proto_adapter.rs (72%) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 084674a8f..33c213346 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -385,26 +385,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "cli" -version = "0.1.0" -dependencies = [ - "clap", - "client", - "prost", - "tokio", -] - -[[package]] -name = "client" -version = "0.1.0" -dependencies = [ - "prost", - "protos", - "reqwest", - "tokio", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -964,13 +944,41 @@ dependencies = [ "hyper 1.4.1", "hyper-util", "ldk-node", + "ldk-server-protos", "prost", - "protos", "serde", "serde_json", "tokio", ] +[[package]] +name = "ldk-server-cli" +version = "0.1.0" +dependencies = [ + "clap", + "ldk-server-client", + "prost", + "tokio", +] + +[[package]] +name = "ldk-server-client" +version = "0.1.0" +dependencies = [ + "ldk-server-protos", + "prost", + "reqwest", + "tokio", +] + +[[package]] +name = "ldk-server-protos" +version = "0.1.0" +dependencies = [ + "prost", + "prost-build", +] + [[package]] name = "libc" version = "0.2.155" @@ -1351,14 +1359,6 @@ dependencies = [ "prost", ] -[[package]] -name = "protos" -version = "0.1.0" -dependencies = [ - "prost", - "prost-build", -] - [[package]] name = "quote" version = "1.0.36" diff --git a/ldk-server/Cargo.toml b/ldk-server/Cargo.toml index 61b420c9b..16d6cedd5 100644 --- a/ldk-server/Cargo.toml +++ b/ldk-server/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = [ "cli", "client", "protos", "server"] +members = [ "ldk-server-cli", "ldk-server-client", "ldk-server-protos", "ldk-server"] [profile.release] panic = "abort" diff --git a/ldk-server/cli/Cargo.toml b/ldk-server/ldk-server-cli/Cargo.toml similarity index 81% rename from ldk-server/cli/Cargo.toml rename to ldk-server/ldk-server-cli/Cargo.toml index a8f9df755..a38ca83b8 100644 --- a/ldk-server/cli/Cargo.toml +++ b/ldk-server/ldk-server-cli/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "cli" +name = "ldk-server-cli" version = "0.1.0" edition = "2021" [dependencies] -client = { path = "../client" } +ldk-server-client = { path = "../ldk-server-client" } clap = { version = "4.0.5", default-features = false, features = ["derive", "std", "error-context", "suggestions", "help"] } tokio = { version = "1.38.0", default-features = false, features = ["rt-multi-thread", "macros"] } prost = { version = "0.11.6", default-features = false} diff --git a/ldk-server/cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs similarity index 96% rename from ldk-server/cli/src/main.rs rename to ldk-server/ldk-server-cli/src/main.rs index b8fac3734..42557356f 100644 --- a/ldk-server/cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -1,7 +1,7 @@ use clap::{Parser, Subcommand}; -use client::client::LdkServerClient; -use client::error::LdkServerError; -use client::protos::api::{ +use ldk_server_client::client::LdkServerClient; +use ldk_server_client::error::LdkServerError; +use ldk_server_client::ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, Bolt12SendRequest, OnchainReceiveRequest, OnchainSendRequest, OpenChannelRequest, }; diff --git a/ldk-server/client/Cargo.toml b/ldk-server/ldk-server-client/Cargo.toml similarity index 78% rename from ldk-server/client/Cargo.toml rename to ldk-server/ldk-server-client/Cargo.toml index dd823fc90..616cc2d93 100644 --- a/ldk-server/client/Cargo.toml +++ b/ldk-server/ldk-server-client/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "client" +name = "ldk-server-client" version = "0.1.0" edition = "2021" [dependencies] -protos = { path = "../protos" } +ldk-server-protos = { path = "../ldk-server-protos" } reqwest = { version = "0.11.13", default-features = false, features = ["rustls-tls"] } tokio = { version = "1.38.0", default-features = false } prost = { version = "0.11.6", default-features = false, features = ["std", "prost-derive"] } diff --git a/ldk-server/client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs similarity index 97% rename from ldk-server/client/src/client.rs rename to ldk-server/ldk-server-client/src/client.rs index 2fb9c47a8..be9b15a0c 100644 --- a/ldk-server/client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -1,7 +1,7 @@ use prost::Message; use crate::error::LdkServerError; -use protos::api::{ +use ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse, Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, CloseChannelRequest, CloseChannelResponse, ListChannelsRequest, ListChannelsResponse, @@ -31,7 +31,7 @@ pub struct LdkServerClient { } impl LdkServerClient { - /// Constructs a [`LdkServerClient`] using `base_url` as the server endpoint. + /// Constructs a [`LdkServerClient`] using `base_url` as the ldk-server endpoint. pub fn new(base_url: String) -> Self { Self { base_url, client: Client::new() } } diff --git a/ldk-server/client/src/error.rs b/ldk-server/ldk-server-client/src/error.rs similarity index 100% rename from ldk-server/client/src/error.rs rename to ldk-server/ldk-server-client/src/error.rs diff --git a/ldk-server/client/src/lib.rs b/ldk-server/ldk-server-client/src/lib.rs similarity index 58% rename from ldk-server/client/src/lib.rs rename to ldk-server/ldk-server-client/src/lib.rs index 96d79388d..19540ee24 100644 --- a/ldk-server/client/src/lib.rs +++ b/ldk-server/ldk-server-client/src/lib.rs @@ -4,11 +4,11 @@ #![deny(rustdoc::private_intra_doc_links)] #![deny(missing_docs)] -/// Implements a client ([`client::LdkServerClient`]) to access a hosted instance of LDK Server. +/// Implements a ldk-ldk-server-client ([`client::LdkServerClient`]) to access a hosted instance of LDK Server. pub mod client; /// Implements the error type ([`error::LdkServerError`]) returned on interacting with [`client::LdkServerClient`] pub mod error; -/// Request/Response structs required for interacting with the client. -pub use protos; +/// Request/Response structs required for interacting with the ldk-ldk-server-client. +pub use ldk_server_protos; diff --git a/ldk-server/protos/Cargo.toml b/ldk-server/ldk-server-protos/Cargo.toml similarity index 91% rename from ldk-server/protos/Cargo.toml rename to ldk-server/ldk-server-protos/Cargo.toml index 7a69b66a6..5d164846c 100644 --- a/ldk-server/protos/Cargo.toml +++ b/ldk-server/ldk-server-protos/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "protos" +name = "ldk-server-protos" version = "0.1.0" edition = "2021" diff --git a/ldk-server/protos/build.rs b/ldk-server/ldk-server-protos/build.rs similarity index 100% rename from ldk-server/protos/build.rs rename to ldk-server/ldk-server-protos/build.rs diff --git a/ldk-server/protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs similarity index 100% rename from ldk-server/protos/src/api.rs rename to ldk-server/ldk-server-protos/src/api.rs diff --git a/ldk-server/protos/src/error.rs b/ldk-server/ldk-server-protos/src/error.rs similarity index 94% rename from ldk-server/protos/src/error.rs rename to ldk-server/ldk-server-protos/src/error.rs index a78c75a32..e6e848faa 100644 --- a/ldk-server/protos/src/error.rs +++ b/ldk-server/ldk-server-protos/src/error.rs @@ -20,7 +20,7 @@ pub struct ErrorResponse { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum ErrorCode { - /// Will neve be used as `error_code` by server. + /// Will neve be used as `error_code` by ldk-server. /// /// **Caution**: If a new type of `error_code` is introduced in the `ErrorCode` enum, `error_code` field will be set to /// `UnknownError`. @@ -35,7 +35,7 @@ pub enum ErrorCode { AuthError = 2, /// Used to represent an error while doing a Lightning operation. LightningError = 3, - /// Used when an internal server error occurred. The client is probably at no fault. + /// Used when an internal ldk-server error occurred. The ldk-ldk-server-client is probably at no fault. InternalServerError = 4, } impl ErrorCode { diff --git a/ldk-server/protos/src/lib.rs b/ldk-server/ldk-server-protos/src/lib.rs similarity index 100% rename from ldk-server/protos/src/lib.rs rename to ldk-server/ldk-server-protos/src/lib.rs diff --git a/ldk-server/protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto similarity index 100% rename from ldk-server/protos/src/proto/api.proto rename to ldk-server/ldk-server-protos/src/proto/api.proto diff --git a/ldk-server/protos/src/proto/error.proto b/ldk-server/ldk-server-protos/src/proto/error.proto similarity index 100% rename from ldk-server/protos/src/proto/error.proto rename to ldk-server/ldk-server-protos/src/proto/error.proto diff --git a/ldk-server/protos/src/proto/types.proto b/ldk-server/ldk-server-protos/src/proto/types.proto similarity index 100% rename from ldk-server/protos/src/proto/types.proto rename to ldk-server/ldk-server-protos/src/proto/types.proto diff --git a/ldk-server/protos/src/types.rs b/ldk-server/ldk-server-protos/src/types.rs similarity index 100% rename from ldk-server/protos/src/types.rs rename to ldk-server/ldk-server-protos/src/types.rs diff --git a/ldk-server/server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml similarity index 93% rename from ldk-server/server/Cargo.toml rename to ldk-server/ldk-server/Cargo.toml index daf71d805..984e207f8 100644 --- a/ldk-server/server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -12,6 +12,6 @@ http-body-util = { version = "0.1", default-features = false } hyper-util = { version = "0.1", default-features = false, features = ["server-graceful"] } tokio = { version = "1.38.0", default-features = false, features = ["time", "signal", "rt-multi-thread"] } prost = { version = "0.11.6", default-features = false, features = ["std"] } -protos = { path = "../protos" } +ldk-server-protos = { path = "../ldk-server-protos" } bytes = "1.4.0" hex = { package = "hex-conservative", version = "0.2.1", default-features = false } diff --git a/ldk-server/server/src/api/bolt11_receive.rs b/ldk-server/ldk-server/src/api/bolt11_receive.rs similarity index 89% rename from ldk-server/server/src/api/bolt11_receive.rs rename to ldk-server/ldk-server/src/api/bolt11_receive.rs index 7c8ef29e9..ff2c03fca 100644 --- a/ldk-server/server/src/api/bolt11_receive.rs +++ b/ldk-server/ldk-server/src/api/bolt11_receive.rs @@ -1,5 +1,5 @@ use ldk_node::Node; -use protos::api::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; +use ldk_server_protos::api::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; use std::sync::Arc; pub(crate) const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; diff --git a/ldk-server/server/src/api/bolt11_send.rs b/ldk-server/ldk-server/src/api/bolt11_send.rs similarity index 91% rename from ldk-server/server/src/api/bolt11_send.rs rename to ldk-server/ldk-server/src/api/bolt11_send.rs index 2376f167d..8e12096c8 100644 --- a/ldk-server/server/src/api/bolt11_send.rs +++ b/ldk-server/ldk-server/src/api/bolt11_send.rs @@ -1,7 +1,7 @@ use bytes::Bytes; use ldk_node::lightning_invoice::Bolt11Invoice; use ldk_node::Node; -use protos::api::{Bolt11SendRequest, Bolt11SendResponse}; +use ldk_server_protos::api::{Bolt11SendRequest, Bolt11SendResponse}; use std::str::FromStr; use std::sync::Arc; diff --git a/ldk-server/server/src/api/bolt12_receive.rs b/ldk-server/ldk-server/src/api/bolt12_receive.rs similarity index 89% rename from ldk-server/server/src/api/bolt12_receive.rs rename to ldk-server/ldk-server/src/api/bolt12_receive.rs index 5d495312a..8cac1b74e 100644 --- a/ldk-server/server/src/api/bolt12_receive.rs +++ b/ldk-server/ldk-server/src/api/bolt12_receive.rs @@ -1,5 +1,5 @@ use ldk_node::Node; -use protos::api::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; +use ldk_server_protos::api::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; use std::sync::Arc; pub(crate) const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive"; diff --git a/ldk-server/server/src/api/bolt12_send.rs b/ldk-server/ldk-server/src/api/bolt12_send.rs similarity index 92% rename from ldk-server/server/src/api/bolt12_send.rs rename to ldk-server/ldk-server/src/api/bolt12_send.rs index 423c57936..ea0f85ce4 100644 --- a/ldk-server/server/src/api/bolt12_send.rs +++ b/ldk-server/ldk-server/src/api/bolt12_send.rs @@ -1,7 +1,7 @@ use bytes::Bytes; use ldk_node::lightning::offers::offer::Offer; use ldk_node::Node; -use protos::api::{Bolt12SendRequest, Bolt12SendResponse}; +use ldk_server_protos::api::{Bolt12SendRequest, Bolt12SendResponse}; use std::str::FromStr; use std::sync::Arc; diff --git a/ldk-server/server/src/api/close_channel.rs b/ldk-server/ldk-server/src/api/close_channel.rs similarity index 93% rename from ldk-server/server/src/api/close_channel.rs rename to ldk-server/ldk-server/src/api/close_channel.rs index e9f6e3d7d..d3735352c 100644 --- a/ldk-server/server/src/api/close_channel.rs +++ b/ldk-server/ldk-server/src/api/close_channel.rs @@ -1,6 +1,6 @@ use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::{Node, UserChannelId}; -use protos::api::{CloseChannelRequest, CloseChannelResponse}; +use ldk_server_protos::api::{CloseChannelRequest, CloseChannelResponse}; use std::str::FromStr; use std::sync::Arc; diff --git a/ldk-server/server/src/api/error.rs b/ldk-server/ldk-server/src/api/error.rs similarity index 100% rename from ldk-server/server/src/api/error.rs rename to ldk-server/ldk-server/src/api/error.rs diff --git a/ldk-server/server/src/api/get_node_info.rs b/ldk-server/ldk-server/src/api/get_node_info.rs similarity index 90% rename from ldk-server/server/src/api/get_node_info.rs rename to ldk-server/ldk-server/src/api/get_node_info.rs index eabc25ea5..ed612f801 100644 --- a/ldk-server/server/src/api/get_node_info.rs +++ b/ldk-server/ldk-server/src/api/get_node_info.rs @@ -1,6 +1,6 @@ use ldk_node::Node; -use protos::api::{GetNodeInfoRequest, GetNodeInfoResponse}; -use protos::types::BestBlock; +use ldk_server_protos::api::{GetNodeInfoRequest, GetNodeInfoResponse}; +use ldk_server_protos::types::BestBlock; use std::sync::Arc; pub(crate) const GET_NODE_INFO: &str = "GetNodeInfo"; diff --git a/ldk-server/server/src/api/get_payment_details.rs b/ldk-server/ldk-server/src/api/get_payment_details.rs similarity index 89% rename from ldk-server/server/src/api/get_payment_details.rs rename to ldk-server/ldk-server/src/api/get_payment_details.rs index d1f2734db..6a43df2ad 100644 --- a/ldk-server/server/src/api/get_payment_details.rs +++ b/ldk-server/ldk-server/src/api/get_payment_details.rs @@ -2,7 +2,7 @@ use crate::util::proto_adapter::payment_to_proto; use hex::FromHex; use ldk_node::lightning::ln::channelmanager::PaymentId; use ldk_node::Node; -use protos::api::{GetPaymentDetailsRequest, GetPaymentDetailsResponse}; +use ldk_server_protos::api::{GetPaymentDetailsRequest, GetPaymentDetailsResponse}; use std::sync::Arc; pub(crate) const GET_PAYMENT_DETAILS_PATH: &str = "GetPaymentDetails"; diff --git a/ldk-server/server/src/api/list_channels.rs b/ldk-server/ldk-server/src/api/list_channels.rs similarity index 86% rename from ldk-server/server/src/api/list_channels.rs rename to ldk-server/ldk-server/src/api/list_channels.rs index 90520c5b6..318eb3801 100644 --- a/ldk-server/server/src/api/list_channels.rs +++ b/ldk-server/ldk-server/src/api/list_channels.rs @@ -1,6 +1,6 @@ use crate::util::proto_adapter::channel_to_proto; use ldk_node::Node; -use protos::api::{ListChannelsRequest, ListChannelsResponse}; +use ldk_server_protos::api::{ListChannelsRequest, ListChannelsResponse}; use std::sync::Arc; pub(crate) const LIST_CHANNELS_PATH: &str = "ListChannels"; diff --git a/ldk-server/server/src/api/list_payments.rs b/ldk-server/ldk-server/src/api/list_payments.rs similarity index 86% rename from ldk-server/server/src/api/list_payments.rs rename to ldk-server/ldk-server/src/api/list_payments.rs index 671741d61..89da42d5e 100644 --- a/ldk-server/server/src/api/list_payments.rs +++ b/ldk-server/ldk-server/src/api/list_payments.rs @@ -1,6 +1,6 @@ use crate::util::proto_adapter::payment_to_proto; use ldk_node::Node; -use protos::api::{ListPaymentsRequest, ListPaymentsResponse}; +use ldk_server_protos::api::{ListPaymentsRequest, ListPaymentsResponse}; use std::sync::Arc; pub(crate) const LIST_PAYMENTS_PATH: &str = "ListPayments"; diff --git a/ldk-server/server/src/api/mod.rs b/ldk-server/ldk-server/src/api/mod.rs similarity index 100% rename from ldk-server/server/src/api/mod.rs rename to ldk-server/ldk-server/src/api/mod.rs diff --git a/ldk-server/server/src/api/onchain_receive.rs b/ldk-server/ldk-server/src/api/onchain_receive.rs similarity index 83% rename from ldk-server/server/src/api/onchain_receive.rs rename to ldk-server/ldk-server/src/api/onchain_receive.rs index 884552f4c..b7d767691 100644 --- a/ldk-server/server/src/api/onchain_receive.rs +++ b/ldk-server/ldk-server/src/api/onchain_receive.rs @@ -1,5 +1,5 @@ use ldk_node::Node; -use protos::api::{OnchainReceiveRequest, OnchainReceiveResponse}; +use ldk_server_protos::api::{OnchainReceiveRequest, OnchainReceiveResponse}; use std::sync::Arc; pub(crate) const ONCHAIN_RECEIVE_PATH: &str = "OnchainReceive"; diff --git a/ldk-server/server/src/api/onchain_send.rs b/ldk-server/ldk-server/src/api/onchain_send.rs similarity index 92% rename from ldk-server/server/src/api/onchain_send.rs rename to ldk-server/ldk-server/src/api/onchain_send.rs index 7d9348f8a..fd1ef5fb4 100644 --- a/ldk-server/server/src/api/onchain_send.rs +++ b/ldk-server/ldk-server/src/api/onchain_send.rs @@ -1,6 +1,6 @@ use ldk_node::bitcoin::Address; use ldk_node::Node; -use protos::api::{OnchainSendRequest, OnchainSendResponse}; +use ldk_server_protos::api::{OnchainSendRequest, OnchainSendResponse}; use std::str::FromStr; use std::sync::Arc; diff --git a/ldk-server/server/src/api/open_channel.rs b/ldk-server/ldk-server/src/api/open_channel.rs similarity index 94% rename from ldk-server/server/src/api/open_channel.rs rename to ldk-server/ldk-server/src/api/open_channel.rs index 214746d2a..927ea0b70 100644 --- a/ldk-server/server/src/api/open_channel.rs +++ b/ldk-server/ldk-server/src/api/open_channel.rs @@ -2,7 +2,7 @@ use bytes::Bytes; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_node::Node; -use protos::api::{OpenChannelRequest, OpenChannelResponse}; +use ldk_server_protos::api::{OpenChannelRequest, OpenChannelResponse}; use std::str::FromStr; use std::sync::Arc; diff --git a/ldk-server/server/src/api/update_channel_config.rs b/ldk-server/ldk-server/src/api/update_channel_config.rs similarity index 91% rename from ldk-server/server/src/api/update_channel_config.rs rename to ldk-server/ldk-server/src/api/update_channel_config.rs index 306cdbba1..0d6c51037 100644 --- a/ldk-server/server/src/api/update_channel_config.rs +++ b/ldk-server/ldk-server/src/api/update_channel_config.rs @@ -1,8 +1,8 @@ use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; use ldk_node::{Node, UserChannelId}; -use protos::api::{UpdateChannelConfigRequest, UpdateChannelConfigResponse}; -use protos::types::channel_config::MaxDustHtlcExposure; +use ldk_server_protos::api::{UpdateChannelConfigRequest, UpdateChannelConfigResponse}; +use ldk_server_protos::types::channel_config::MaxDustHtlcExposure; use std::str::FromStr; use std::sync::Arc; @@ -38,7 +38,7 @@ pub(crate) fn handle_update_channel_config_request( } fn build_updated_channel_config( - current_config: ChannelConfig, proto_channel_config: protos::types::ChannelConfig, + current_config: ChannelConfig, proto_channel_config: ldk_server_protos::types::ChannelConfig, ) -> ChannelConfig { let max_dust_htlc_exposure = proto_channel_config .max_dust_htlc_exposure diff --git a/ldk-server/server/src/io/mod.rs b/ldk-server/ldk-server/src/io/mod.rs similarity index 100% rename from ldk-server/server/src/io/mod.rs rename to ldk-server/ldk-server/src/io/mod.rs diff --git a/ldk-server/server/src/io/paginated_kv_store.rs b/ldk-server/ldk-server/src/io/paginated_kv_store.rs similarity index 100% rename from ldk-server/server/src/io/paginated_kv_store.rs rename to ldk-server/ldk-server/src/io/paginated_kv_store.rs diff --git a/ldk-server/server/src/main.rs b/ldk-server/ldk-server/src/main.rs similarity index 100% rename from ldk-server/server/src/main.rs rename to ldk-server/ldk-server/src/main.rs diff --git a/ldk-server/server/src/service.rs b/ldk-server/ldk-server/src/service.rs similarity index 100% rename from ldk-server/server/src/service.rs rename to ldk-server/ldk-server/src/service.rs diff --git a/ldk-server/server/src/util/mod.rs b/ldk-server/ldk-server/src/util/mod.rs similarity index 100% rename from ldk-server/server/src/util/mod.rs rename to ldk-server/ldk-server/src/util/mod.rs diff --git a/ldk-server/server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs similarity index 72% rename from ldk-server/server/src/util/proto_adapter.rs rename to ldk-server/ldk-server/src/util/proto_adapter.rs index e7855640b..5446bc6cb 100644 --- a/ldk-server/server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -3,10 +3,10 @@ use hex::prelude::*; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; use ldk_node::payment::{PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus}; use ldk_node::ChannelDetails; -use protos::types::payment_kind::Kind::{ +use ldk_server_protos::types::payment_kind::Kind::{ Bolt11, Bolt11Jit, Bolt12Offer, Bolt12Refund, Onchain, Spontaneous, }; -use protos::types::{Channel, LspFeeLimits, OutPoint, Payment}; +use ldk_server_protos::types::{Channel, LspFeeLimits, OutPoint, Payment}; pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { Channel { @@ -47,8 +47,8 @@ pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { pub(crate) fn channel_config_to_proto( channel_config: ChannelConfig, -) -> protos::types::ChannelConfig { - protos::types::ChannelConfig { +) -> ldk_server_protos::types::ChannelConfig { + ldk_server_protos::types::ChannelConfig { forwarding_fee_proportional_millionths: Some( channel_config.forwarding_fee_proportional_millionths, ), @@ -60,10 +60,14 @@ pub(crate) fn channel_config_to_proto( accept_underpaying_htlcs: Some(channel_config.accept_underpaying_htlcs), max_dust_htlc_exposure: match channel_config.max_dust_htlc_exposure { MaxDustHTLCExposure::FixedLimit { limit_msat } => { - Some(protos::types::channel_config::MaxDustHtlcExposure::FixedLimitMsat(limit_msat)) + Some(ldk_server_protos::types::channel_config::MaxDustHtlcExposure::FixedLimitMsat( + limit_msat, + )) }, MaxDustHTLCExposure::FeeRateMultiplier { multiplier } => Some( - protos::types::channel_config::MaxDustHtlcExposure::FeeRateMultiplier(multiplier), + ldk_server_protos::types::channel_config::MaxDustHtlcExposure::FeeRateMultiplier( + multiplier, + ), ), }, } @@ -75,33 +79,37 @@ pub(crate) fn payment_to_proto(payment: PaymentDetails) -> Payment { kind: Some(payment_kind_to_proto(payment.kind)), amount_msat: payment.amount_msat, direction: match payment.direction { - PaymentDirection::Inbound => protos::types::PaymentDirection::Inbound.into(), - PaymentDirection::Outbound => protos::types::PaymentDirection::Outbound.into(), + PaymentDirection::Inbound => ldk_server_protos::types::PaymentDirection::Inbound.into(), + PaymentDirection::Outbound => { + ldk_server_protos::types::PaymentDirection::Outbound.into() + }, }, status: match payment.status { - PaymentStatus::Pending => protos::types::PaymentStatus::Pending.into(), - PaymentStatus::Succeeded => protos::types::PaymentStatus::Succeeded.into(), - PaymentStatus::Failed => protos::types::PaymentStatus::Failed.into(), + PaymentStatus::Pending => ldk_server_protos::types::PaymentStatus::Pending.into(), + PaymentStatus::Succeeded => ldk_server_protos::types::PaymentStatus::Succeeded.into(), + PaymentStatus::Failed => ldk_server_protos::types::PaymentStatus::Failed.into(), }, latest_update_timestamp: payment.latest_update_timestamp, } } -pub(crate) fn payment_kind_to_proto(payment_kind: PaymentKind) -> protos::types::PaymentKind { +pub(crate) fn payment_kind_to_proto( + payment_kind: PaymentKind, +) -> ldk_server_protos::types::PaymentKind { match payment_kind { - PaymentKind::Onchain => { - protos::types::PaymentKind { kind: Some(Onchain(protos::types::Onchain {})) } + PaymentKind::Onchain => ldk_server_protos::types::PaymentKind { + kind: Some(Onchain(ldk_server_protos::types::Onchain {})), }, - PaymentKind::Bolt11 { hash, preimage, secret } => protos::types::PaymentKind { - kind: Some(Bolt11(protos::types::Bolt11 { + PaymentKind::Bolt11 { hash, preimage, secret } => ldk_server_protos::types::PaymentKind { + kind: Some(Bolt11(ldk_server_protos::types::Bolt11 { hash: hash.to_string(), preimage: preimage.map(|p| p.to_string()), secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), })), }, PaymentKind::Bolt11Jit { hash, preimage, secret, lsp_fee_limits } => { - protos::types::PaymentKind { - kind: Some(Bolt11Jit(protos::types::Bolt11Jit { + ldk_server_protos::types::PaymentKind { + kind: Some(Bolt11Jit(ldk_server_protos::types::Bolt11Jit { hash: hash.to_string(), preimage: preimage.map(|p| p.to_string()), secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), @@ -114,8 +122,8 @@ pub(crate) fn payment_kind_to_proto(payment_kind: PaymentKind) -> protos::types: } }, PaymentKind::Bolt12Offer { hash, preimage, secret, offer_id, payer_note, quantity } => { - protos::types::PaymentKind { - kind: Some(Bolt12Offer(protos::types::Bolt12Offer { + ldk_server_protos::types::PaymentKind { + kind: Some(Bolt12Offer(ldk_server_protos::types::Bolt12Offer { hash: hash.map(|h| h.to_string()), preimage: preimage.map(|p| p.to_string()), secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), @@ -126,8 +134,8 @@ pub(crate) fn payment_kind_to_proto(payment_kind: PaymentKind) -> protos::types: } }, PaymentKind::Bolt12Refund { hash, preimage, secret, payer_note, quantity } => { - protos::types::PaymentKind { - kind: Some(Bolt12Refund(protos::types::Bolt12Refund { + ldk_server_protos::types::PaymentKind { + kind: Some(Bolt12Refund(ldk_server_protos::types::Bolt12Refund { hash: hash.map(|h| h.to_string()), preimage: preimage.map(|p| p.to_string()), secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), @@ -136,8 +144,8 @@ pub(crate) fn payment_kind_to_proto(payment_kind: PaymentKind) -> protos::types: })), } }, - PaymentKind::Spontaneous { hash, preimage } => protos::types::PaymentKind { - kind: Some(Spontaneous(protos::types::Spontaneous { + PaymentKind::Spontaneous { hash, preimage } => ldk_server_protos::types::PaymentKind { + kind: Some(Spontaneous(ldk_server_protos::types::Spontaneous { hash: hash.to_string(), preimage: preimage.map(|p| p.to_string()), })), From 2cfdc7e17103985aa340b24eadaa91bf2e0d63d8 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:10:56 -0800 Subject: [PATCH 072/203] Add proto definition for GetBalances API. --- ldk-server/ldk-server-protos/src/api.rs | 47 +++ .../ldk-server-protos/src/proto/api.proto | 43 +++ .../ldk-server-protos/src/proto/types.proto | 229 +++++++++++++++ ldk-server/ldk-server-protos/src/types.rs | 273 ++++++++++++++++++ 4 files changed, 592 insertions(+) diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index 1c99ba937..268965d50 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -311,3 +311,50 @@ pub struct ListPaymentsResponse { #[prost(message, repeated, tag = "1")] pub payments: ::prost::alloc::vec::Vec, } +/// Retrieves an overview of all known balances. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetBalancesRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetBalancesResponse { + /// The total balance of our on-chain wallet. + #[prost(uint64, tag = "1")] + pub total_onchain_balance_sats: u64, + /// The currently spendable balance of our on-chain wallet. + /// + /// This includes any sufficiently confirmed funds, minus `total_anchor_channels_reserve_sats`. + #[prost(uint64, tag = "2")] + pub spendable_onchain_balance_sats: u64, + /// The share of our total balance that we retain as an emergency reserve to (hopefully) be + /// able to spend the Anchor outputs when one of our channels is closed. + #[prost(uint64, tag = "3")] + pub total_anchor_channels_reserve_sats: u64, + /// The total balance that we would be able to claim across all our Lightning channels. + /// + /// Note this excludes balances that we are unsure if we are able to claim (e.g., as we are + /// waiting for a preimage or for a timeout to expire). These balances will however be included + /// as `MaybePreimageClaimableHTLC` and `MaybeTimeoutClaimableHTLC` in `lightning_balances`. + #[prost(uint64, tag = "4")] + pub total_lightning_balance_sats: u64, + /// A detailed list of all known Lightning balances that would be claimable on channel closure. + /// + /// Note that less than the listed amounts are spendable over lightning as further reserve + /// restrictions apply. Please refer to `Channel::outbound_capacity_msat` and + /// Channel::next_outbound_htlc_limit_msat as returned by `ListChannels` + /// for a better approximation of the spendable amounts. + #[prost(message, repeated, tag = "5")] + pub lightning_balances: ::prost::alloc::vec::Vec, + /// A detailed list of balances currently being swept from the Lightning to the on-chain + /// wallet. + /// + /// These are balances resulting from channel closures that may have been encumbered by a + /// delay, but are now being claimed and useable once sufficiently confirmed on-chain. + /// + /// Note that, depending on the sync status of the wallets, swept balances listed here might or + /// might not already be accounted for in `total_onchain_balance_sats`. + #[prost(message, repeated, tag = "6")] + pub pending_balances_from_channel_closures: + ::prost::alloc::vec::Vec, +} diff --git a/ldk-server/ldk-server-protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto index f3ddd83db..9002ce4ff 100644 --- a/ldk-server/ldk-server-protos/src/proto/api.proto +++ b/ldk-server/ldk-server-protos/src/proto/api.proto @@ -293,3 +293,46 @@ message ListPaymentsResponse { // List of payments. repeated types.Payment payments = 1; } + +// Retrieves an overview of all known balances. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_balances +message GetBalancesRequest {} + +message GetBalancesResponse { + // The total balance of our on-chain wallet. + uint64 total_onchain_balance_sats = 1; + + // The currently spendable balance of our on-chain wallet. + // + // This includes any sufficiently confirmed funds, minus `total_anchor_channels_reserve_sats`. + uint64 spendable_onchain_balance_sats = 2; + + // The share of our total balance that we retain as an emergency reserve to (hopefully) be + // able to spend the Anchor outputs when one of our channels is closed. + uint64 total_anchor_channels_reserve_sats = 3; + + // The total balance that we would be able to claim across all our Lightning channels. + // + // Note this excludes balances that we are unsure if we are able to claim (e.g., as we are + // waiting for a preimage or for a timeout to expire). These balances will however be included + // as `MaybePreimageClaimableHTLC` and `MaybeTimeoutClaimableHTLC` in `lightning_balances`. + uint64 total_lightning_balance_sats = 4; + + // A detailed list of all known Lightning balances that would be claimable on channel closure. + // + // Note that less than the listed amounts are spendable over lightning as further reserve + // restrictions apply. Please refer to `Channel::outbound_capacity_msat` and + // Channel::next_outbound_htlc_limit_msat as returned by `ListChannels` + // for a better approximation of the spendable amounts. + repeated types.LightningBalance lightning_balances = 5; + + // A detailed list of balances currently being swept from the Lightning to the on-chain + // wallet. + // + // These are balances resulting from channel closures that may have been encumbered by a + // delay, but are now being claimed and useable once sufficiently confirmed on-chain. + // + // Note that, depending on the sync status of the wallets, swept balances listed here might or + // might not already be accounted for in `total_onchain_balance_sats`. + repeated types.PendingSweepBalance pending_balances_from_channel_closures = 6; +} diff --git a/ldk-server/ldk-server-protos/src/proto/types.proto b/ldk-server/ldk-server-protos/src/proto/types.proto index 82eeee8ab..cc7433b90 100644 --- a/ldk-server/ldk-server-protos/src/proto/types.proto +++ b/ldk-server/ldk-server-protos/src/proto/types.proto @@ -350,3 +350,232 @@ message BestBlock { // The height at which the block was confirmed. uint32 height = 2; } + +// Details about the status of a known Lightning balance. +message LightningBalance { + oneof balance_type { + ClaimableOnChannelClose claimable_on_channel_close = 1; + ClaimableAwaitingConfirmations claimable_awaiting_confirmations = 2; + ContentiousClaimable contentious_claimable = 3; + MaybeTimeoutClaimableHTLC maybe_timeout_claimable_htlc = 4; + MaybePreimageClaimableHTLC maybe_preimage_claimable_htlc = 5; + CounterpartyRevokedOutputClaimable counterparty_revoked_output_claimable = 6; + } +} + +// The channel is not yet closed (or the commitment or closing transaction has not yet appeared in a block). +// The given balance is claimable (less on-chain fees) if the channel is force-closed now. +// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.LightningBalance.html#variant.ClaimableOnChannelClose +message ClaimableOnChannelClose { + // The identifier of the channel this balance belongs to. + string channel_id = 1; + + // The identifier of our channel counterparty. + string counterparty_node_id = 2; + + // The amount available to claim, in satoshis, excluding the on-chain fees which will be required to do so. + uint64 amount_satoshis = 3; + + // The transaction fee we pay for the closing commitment transaction. + // This amount is not included in the `amount_satoshis` value. + // + // Note that if this channel is inbound (and thus our counterparty pays the commitment transaction fee) this value + // will be zero. + uint64 transaction_fee_satoshis = 4; + + // The amount of millisatoshis which has been burned to fees from HTLCs which are outbound from us and are related to + // a payment which was sent by us. This is the sum of the millisatoshis part of all HTLCs which are otherwise + // represented by `LightningBalance::MaybeTimeoutClaimableHTLC` with their + // `LightningBalance::MaybeTimeoutClaimableHTLC::outbound_payment` flag set, as well as any dust HTLCs which would + // otherwise be represented the same. + // + // This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. + uint64 outbound_payment_htlc_rounded_msat = 5; + + // The amount of millisatoshis which has been burned to fees from HTLCs which are outbound from us and are related to + // a forwarded HTLC. This is the sum of the millisatoshis part of all HTLCs which are otherwise represented by + // `LightningBalance::MaybeTimeoutClaimableHTLC` with their `LightningBalance::MaybeTimeoutClaimableHTLC::outbound_payment` + // flag not set, as well as any dust HTLCs which would otherwise be represented the same. + // + // This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. + uint64 outbound_forwarded_htlc_rounded_msat = 6; + + // The amount of millisatoshis which has been burned to fees from HTLCs which are inbound to us and for which we know + // the preimage. This is the sum of the millisatoshis part of all HTLCs which would be represented by + // `LightningBalance::ContentiousClaimable` on channel close, but whose current value is included in `amount_satoshis`, + // as well as any dust HTLCs which would otherwise be represented the same. + // + // This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. + uint64 inbound_claiming_htlc_rounded_msat = 7; + + // The amount of millisatoshis which has been burned to fees from HTLCs which are inbound to us and for which we do + // not know the preimage. This is the sum of the millisatoshis part of all HTLCs which would be represented by + // `LightningBalance::MaybePreimageClaimableHTLC` on channel close, as well as any dust HTLCs which would otherwise be + // represented the same. + // + // This amount (rounded up to a whole satoshi value) will not be included in the counterparty’s `amount_satoshis`. + uint64 inbound_htlc_rounded_msat = 8; +} + +// The channel has been closed, and the given balance is ours but awaiting confirmations until we consider it spendable. +// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.LightningBalance.html#variant.ClaimableAwaitingConfirmations +message ClaimableAwaitingConfirmations { + // The identifier of the channel this balance belongs to. + string channel_id = 1; + + // The identifier of our channel counterparty. + string counterparty_node_id = 2; + + // The amount available to claim, in satoshis, possibly excluding the on-chain fees which were spent in broadcasting + // the transaction. + uint64 amount_satoshis = 3; + + // The height at which we start tracking it as `SpendableOutput`. + uint32 confirmation_height = 4; +} + +// The channel has been closed, and the given balance should be ours but awaiting spending transaction confirmation. +// If the spending transaction does not confirm in time, it is possible our counterparty can take the funds by +// broadcasting an HTLC timeout on-chain. +// +// Once the spending transaction confirms, before it has reached enough confirmations to be considered safe from chain +// reorganizations, the balance will instead be provided via `LightningBalance::ClaimableAwaitingConfirmations`. +// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.LightningBalance.html#variant.ContentiousClaimable +message ContentiousClaimable { + // The identifier of the channel this balance belongs to. + string channel_id = 1; + + // The identifier of our channel counterparty. + string counterparty_node_id = 2; + + // The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting + // the transaction. + uint64 amount_satoshis = 3; + + // The height at which the counterparty may be able to claim the balance if we have not done so. + uint32 timeout_height = 4; + + // The payment hash that locks this HTLC. + string payment_hash = 5; + + // The preimage that can be used to claim this HTLC. + string payment_preimage = 6; +} + +// HTLCs which we sent to our counterparty which are claimable after a timeout (less on-chain fees) if the counterparty +// does not know the preimage for the HTLCs. These are somewhat likely to be claimed by our counterparty before we do. +// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.LightningBalance.html#variant.MaybeTimeoutClaimableHTLC +message MaybeTimeoutClaimableHTLC { + // The identifier of the channel this balance belongs to. + string channel_id = 1; + + // The identifier of our channel counterparty. + string counterparty_node_id = 2; + + // The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting + // the transaction. + uint64 amount_satoshis = 3; + + // The height at which we will be able to claim the balance if our counterparty has not done so. + uint32 claimable_height = 4; + + // The payment hash whose preimage our counterparty needs to claim this HTLC. + string payment_hash = 5; + + // Indicates whether this HTLC represents a payment which was sent outbound from us. + bool outbound_payment = 6; +} + +// HTLCs which we received from our counterparty which are claimable with a preimage which we do not currently have. +// This will only be claimable if we receive the preimage from the node to which we forwarded this HTLC before the +// timeout. +// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.LightningBalance.html#variant.MaybePreimageClaimableHTLC +message MaybePreimageClaimableHTLC { + // The identifier of the channel this balance belongs to. + string channel_id = 1; + + // The identifier of our channel counterparty. + string counterparty_node_id = 2; + + // The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting + // the transaction. + uint64 amount_satoshis = 3; + + // The height at which our counterparty will be able to claim the balance if we have not yet received the preimage and + // claimed it ourselves. + uint32 expiry_height = 4; + + // The payment hash whose preimage we need to claim this HTLC. + string payment_hash = 5; +} +// The channel has been closed, and our counterparty broadcasted a revoked commitment transaction. +// +// Thus, we’re able to claim all outputs in the commitment transaction, one of which has the following amount. +// +// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.LightningBalance.html#variant.CounterpartyRevokedOutputClaimable +message CounterpartyRevokedOutputClaimable { + // The identifier of the channel this balance belongs to. + string channel_id = 1; + + // The identifier of our channel counterparty. + string counterparty_node_id = 2; + + // The amount, in satoshis, of the output which we can claim. + uint64 amount_satoshis = 3; +} + +// Details about the status of a known balance currently being swept to our on-chain wallet. +message PendingSweepBalance { + oneof balance_type { + PendingBroadcast pending_broadcast = 1; + BroadcastAwaitingConfirmation broadcast_awaiting_confirmation = 2; + AwaitingThresholdConfirmations awaiting_threshold_confirmations = 3; + } +} + +// The spendable output is about to be swept, but a spending transaction has yet to be generated and broadcast. +// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.PendingSweepBalance.html#variant.PendingBroadcast +message PendingBroadcast { + // The identifier of the channel this balance belongs to. + optional string channel_id = 1; + + // The amount, in satoshis, of the output being swept. + uint64 amount_satoshis = 2; +} + +// A spending transaction has been generated and broadcast and is awaiting confirmation on-chain. +// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.PendingSweepBalance.html#variant.BroadcastAwaitingConfirmation +message BroadcastAwaitingConfirmation { + // The identifier of the channel this balance belongs to. + optional string channel_id = 1; + + // The best height when we last broadcast a transaction spending the output being swept. + uint32 latest_broadcast_height = 2; + + // The identifier of the transaction spending the swept output we last broadcast. + string latest_spending_txid = 3; + + // The amount, in satoshis, of the output being swept. + uint64 amount_satoshis = 4; +} + +// A spending transaction has been confirmed on-chain and is awaiting threshold confirmations. +// +// It will be considered irrevocably confirmed after reaching `ANTI_REORG_DELAY`. +// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.PendingSweepBalance.html#variant.AwaitingThresholdConfirmations +message AwaitingThresholdConfirmations { + // The identifier of the channel this balance belongs to. + optional string channel_id = 1; + + // The identifier of the confirmed transaction spending the swept output. + string latest_spending_txid = 2; + + // The hash of the block in which the spending transaction was confirmed. + string confirmation_hash = 3; + + // The height at which the spending transaction was confirmed. + uint32 confirmation_height = 4; + + // The amount, in satoshis, of the output being swept. + uint64 amount_satoshis = 5; +} diff --git a/ldk-server/ldk-server-protos/src/types.rs b/ldk-server/ldk-server-protos/src/types.rs index d99cfdeff..82b7168f9 100644 --- a/ldk-server/ldk-server-protos/src/types.rs +++ b/ldk-server/ldk-server-protos/src/types.rs @@ -374,6 +374,279 @@ pub struct BestBlock { #[prost(uint32, tag = "2")] pub height: u32, } +/// Details about the status of a known Lightning balance. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LightningBalance { + #[prost(oneof = "lightning_balance::BalanceType", tags = "1, 2, 3, 4, 5, 6")] + pub balance_type: ::core::option::Option, +} +/// Nested message and enum types in `LightningBalance`. +pub mod lightning_balance { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum BalanceType { + #[prost(message, tag = "1")] + ClaimableOnChannelClose(super::ClaimableOnChannelClose), + #[prost(message, tag = "2")] + ClaimableAwaitingConfirmations(super::ClaimableAwaitingConfirmations), + #[prost(message, tag = "3")] + ContentiousClaimable(super::ContentiousClaimable), + #[prost(message, tag = "4")] + MaybeTimeoutClaimableHtlc(super::MaybeTimeoutClaimableHtlc), + #[prost(message, tag = "5")] + MaybePreimageClaimableHtlc(super::MaybePreimageClaimableHtlc), + #[prost(message, tag = "6")] + CounterpartyRevokedOutputClaimable(super::CounterpartyRevokedOutputClaimable), + } +} +/// The channel is not yet closed (or the commitment or closing transaction has not yet appeared in a block). +/// The given balance is claimable (less on-chain fees) if the channel is force-closed now. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClaimableOnChannelClose { + /// The identifier of the channel this balance belongs to. + #[prost(string, tag = "1")] + pub channel_id: ::prost::alloc::string::String, + /// The identifier of our channel counterparty. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// The amount available to claim, in satoshis, excluding the on-chain fees which will be required to do so. + #[prost(uint64, tag = "3")] + pub amount_satoshis: u64, + /// The transaction fee we pay for the closing commitment transaction. + /// This amount is not included in the `amount_satoshis` value. + /// + /// Note that if this channel is inbound (and thus our counterparty pays the commitment transaction fee) this value + /// will be zero. + #[prost(uint64, tag = "4")] + pub transaction_fee_satoshis: u64, + /// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound from us and are related to + /// a payment which was sent by us. This is the sum of the millisatoshis part of all HTLCs which are otherwise + /// represented by `LightningBalance::MaybeTimeoutClaimableHTLC` with their + /// `LightningBalance::MaybeTimeoutClaimableHTLC::outbound_payment` flag set, as well as any dust HTLCs which would + /// otherwise be represented the same. + /// + /// This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. + #[prost(uint64, tag = "5")] + pub outbound_payment_htlc_rounded_msat: u64, + /// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound from us and are related to + /// a forwarded HTLC. This is the sum of the millisatoshis part of all HTLCs which are otherwise represented by + /// `LightningBalance::MaybeTimeoutClaimableHTLC` with their `LightningBalance::MaybeTimeoutClaimableHTLC::outbound_payment` + /// flag not set, as well as any dust HTLCs which would otherwise be represented the same. + /// + /// This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. + #[prost(uint64, tag = "6")] + pub outbound_forwarded_htlc_rounded_msat: u64, + /// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound to us and for which we know + /// the preimage. This is the sum of the millisatoshis part of all HTLCs which would be represented by + /// `LightningBalance::ContentiousClaimable` on channel close, but whose current value is included in `amount_satoshis`, + /// as well as any dust HTLCs which would otherwise be represented the same. + /// + /// This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. + #[prost(uint64, tag = "7")] + pub inbound_claiming_htlc_rounded_msat: u64, + /// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound to us and for which we do + /// not know the preimage. This is the sum of the millisatoshis part of all HTLCs which would be represented by + /// `LightningBalance::MaybePreimageClaimableHTLC` on channel close, as well as any dust HTLCs which would otherwise be + /// represented the same. + /// + /// This amount (rounded up to a whole satoshi value) will not be included in the counterparty’s `amount_satoshis`. + #[prost(uint64, tag = "8")] + pub inbound_htlc_rounded_msat: u64, +} +/// The channel has been closed, and the given balance is ours but awaiting confirmations until we consider it spendable. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClaimableAwaitingConfirmations { + /// The identifier of the channel this balance belongs to. + #[prost(string, tag = "1")] + pub channel_id: ::prost::alloc::string::String, + /// The identifier of our channel counterparty. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// The amount available to claim, in satoshis, possibly excluding the on-chain fees which were spent in broadcasting + /// the transaction. + #[prost(uint64, tag = "3")] + pub amount_satoshis: u64, + /// The height at which we start tracking it as `SpendableOutput`. + #[prost(uint32, tag = "4")] + pub confirmation_height: u32, +} +/// The channel has been closed, and the given balance should be ours but awaiting spending transaction confirmation. +/// If the spending transaction does not confirm in time, it is possible our counterparty can take the funds by +/// broadcasting an HTLC timeout on-chain. +/// +/// Once the spending transaction confirms, before it has reached enough confirmations to be considered safe from chain +/// reorganizations, the balance will instead be provided via `LightningBalance::ClaimableAwaitingConfirmations`. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ContentiousClaimable { + /// The identifier of the channel this balance belongs to. + #[prost(string, tag = "1")] + pub channel_id: ::prost::alloc::string::String, + /// The identifier of our channel counterparty. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting + /// the transaction. + #[prost(uint64, tag = "3")] + pub amount_satoshis: u64, + /// The height at which the counterparty may be able to claim the balance if we have not done so. + #[prost(uint32, tag = "4")] + pub timeout_height: u32, + /// The payment hash that locks this HTLC. + #[prost(string, tag = "5")] + pub payment_hash: ::prost::alloc::string::String, + /// The preimage that can be used to claim this HTLC. + #[prost(string, tag = "6")] + pub payment_preimage: ::prost::alloc::string::String, +} +/// HTLCs which we sent to our counterparty which are claimable after a timeout (less on-chain fees) if the counterparty +/// does not know the preimage for the HTLCs. These are somewhat likely to be claimed by our counterparty before we do. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MaybeTimeoutClaimableHtlc { + /// The identifier of the channel this balance belongs to. + #[prost(string, tag = "1")] + pub channel_id: ::prost::alloc::string::String, + /// The identifier of our channel counterparty. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting + /// the transaction. + #[prost(uint64, tag = "3")] + pub amount_satoshis: u64, + /// The height at which we will be able to claim the balance if our counterparty has not done so. + #[prost(uint32, tag = "4")] + pub claimable_height: u32, + /// The payment hash whose preimage our counterparty needs to claim this HTLC. + #[prost(string, tag = "5")] + pub payment_hash: ::prost::alloc::string::String, + /// Indicates whether this HTLC represents a payment which was sent outbound from us. + #[prost(bool, tag = "6")] + pub outbound_payment: bool, +} +/// HTLCs which we received from our counterparty which are claimable with a preimage which we do not currently have. +/// This will only be claimable if we receive the preimage from the node to which we forwarded this HTLC before the +/// timeout. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MaybePreimageClaimableHtlc { + /// The identifier of the channel this balance belongs to. + #[prost(string, tag = "1")] + pub channel_id: ::prost::alloc::string::String, + /// The identifier of our channel counterparty. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting + /// the transaction. + #[prost(uint64, tag = "3")] + pub amount_satoshis: u64, + /// The height at which our counterparty will be able to claim the balance if we have not yet received the preimage and + /// claimed it ourselves. + #[prost(uint32, tag = "4")] + pub expiry_height: u32, + /// The payment hash whose preimage we need to claim this HTLC. + #[prost(string, tag = "5")] + pub payment_hash: ::prost::alloc::string::String, +} +/// The channel has been closed, and our counterparty broadcasted a revoked commitment transaction. +/// +/// Thus, we’re able to claim all outputs in the commitment transaction, one of which has the following amount. +/// +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CounterpartyRevokedOutputClaimable { + /// The identifier of the channel this balance belongs to. + #[prost(string, tag = "1")] + pub channel_id: ::prost::alloc::string::String, + /// The identifier of our channel counterparty. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// The amount, in satoshis, of the output which we can claim. + #[prost(uint64, tag = "3")] + pub amount_satoshis: u64, +} +/// Details about the status of a known balance currently being swept to our on-chain wallet. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PendingSweepBalance { + #[prost(oneof = "pending_sweep_balance::BalanceType", tags = "1, 2, 3")] + pub balance_type: ::core::option::Option, +} +/// Nested message and enum types in `PendingSweepBalance`. +pub mod pending_sweep_balance { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum BalanceType { + #[prost(message, tag = "1")] + PendingBroadcast(super::PendingBroadcast), + #[prost(message, tag = "2")] + BroadcastAwaitingConfirmation(super::BroadcastAwaitingConfirmation), + #[prost(message, tag = "3")] + AwaitingThresholdConfirmations(super::AwaitingThresholdConfirmations), + } +} +/// The spendable output is about to be swept, but a spending transaction has yet to be generated and broadcast. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PendingBroadcast { + /// The identifier of the channel this balance belongs to. + #[prost(string, optional, tag = "1")] + pub channel_id: ::core::option::Option<::prost::alloc::string::String>, + /// The amount, in satoshis, of the output being swept. + #[prost(uint64, tag = "2")] + pub amount_satoshis: u64, +} +/// A spending transaction has been generated and broadcast and is awaiting confirmation on-chain. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BroadcastAwaitingConfirmation { + /// The identifier of the channel this balance belongs to. + #[prost(string, optional, tag = "1")] + pub channel_id: ::core::option::Option<::prost::alloc::string::String>, + /// The best height when we last broadcast a transaction spending the output being swept. + #[prost(uint32, tag = "2")] + pub latest_broadcast_height: u32, + /// The identifier of the transaction spending the swept output we last broadcast. + #[prost(string, tag = "3")] + pub latest_spending_txid: ::prost::alloc::string::String, + /// The amount, in satoshis, of the output being swept. + #[prost(uint64, tag = "4")] + pub amount_satoshis: u64, +} +/// A spending transaction has been confirmed on-chain and is awaiting threshold confirmations. +/// +/// It will be considered irrevocably confirmed after reaching `ANTI_REORG_DELAY`. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AwaitingThresholdConfirmations { + /// The identifier of the channel this balance belongs to. + #[prost(string, optional, tag = "1")] + pub channel_id: ::core::option::Option<::prost::alloc::string::String>, + /// The identifier of the confirmed transaction spending the swept output. + #[prost(string, tag = "2")] + pub latest_spending_txid: ::prost::alloc::string::String, + /// The hash of the block in which the spending transaction was confirmed. + #[prost(string, tag = "3")] + pub confirmation_hash: ::prost::alloc::string::String, + /// The height at which the spending transaction was confirmed. + #[prost(uint32, tag = "4")] + pub confirmation_height: u32, + /// The amount, in satoshis, of the output being swept. + #[prost(uint64, tag = "5")] + pub amount_satoshis: u64, +} /// Represents the direction of a payment. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] From ff97facf27fd98410f6b72b4d619870e9713e45e Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:11:35 -0800 Subject: [PATCH 073/203] Fix typo in error proto. --- ldk-server/ldk-server-protos/src/error.rs | 4 ++-- ldk-server/ldk-server-protos/src/proto/error.proto | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ldk-server/ldk-server-protos/src/error.rs b/ldk-server/ldk-server-protos/src/error.rs index e6e848faa..bd76d36da 100644 --- a/ldk-server/ldk-server-protos/src/error.rs +++ b/ldk-server/ldk-server-protos/src/error.rs @@ -20,7 +20,7 @@ pub struct ErrorResponse { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum ErrorCode { - /// Will neve be used as `error_code` by ldk-server. + /// Will never be used as `error_code` by server. /// /// **Caution**: If a new type of `error_code` is introduced in the `ErrorCode` enum, `error_code` field will be set to /// `UnknownError`. @@ -35,7 +35,7 @@ pub enum ErrorCode { AuthError = 2, /// Used to represent an error while doing a Lightning operation. LightningError = 3, - /// Used when an internal ldk-server error occurred. The ldk-ldk-server-client is probably at no fault. + /// Used when an internal server error occurred. The client is probably at no fault. InternalServerError = 4, } impl ErrorCode { diff --git a/ldk-server/ldk-server-protos/src/proto/error.proto b/ldk-server/ldk-server-protos/src/proto/error.proto index f6f85cd10..c5a75d7dd 100644 --- a/ldk-server/ldk-server-protos/src/proto/error.proto +++ b/ldk-server/ldk-server-protos/src/proto/error.proto @@ -21,7 +21,7 @@ message ErrorResponse { enum ErrorCode { - // Will neve be used as `error_code` by server. + // Will never be used as `error_code` by server. // // **Caution**: If a new type of `error_code` is introduced in the `ErrorCode` enum, `error_code` field will be set to // `UnknownError`. From 85ec0e67e6ecb15e6568af0d6e375c4dc1c199cb Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:57:52 -0800 Subject: [PATCH 074/203] Add GetBalances API impl. --- ldk-server/ldk-server/src/api/get_balances.rs | 30 ++++ ldk-server/ldk-server/src/api/mod.rs | 1 + ldk-server/ldk-server/src/service.rs | 2 + .../ldk-server/src/util/proto_adapter.rs | 170 +++++++++++++++++- 4 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 ldk-server/ldk-server/src/api/get_balances.rs diff --git a/ldk-server/ldk-server/src/api/get_balances.rs b/ldk-server/ldk-server/src/api/get_balances.rs new file mode 100644 index 000000000..535aa5fca --- /dev/null +++ b/ldk-server/ldk-server/src/api/get_balances.rs @@ -0,0 +1,30 @@ +use crate::util::proto_adapter::{lightning_balance_to_proto, pending_sweep_balance_to_proto}; +use ldk_node::Node; +use ldk_server_protos::api::{GetBalancesRequest, GetBalancesResponse}; +use std::sync::Arc; + +pub(crate) const GET_BALANCES: &str = "GetBalances"; + +pub(crate) fn handle_get_balances_request( + node: Arc, _request: GetBalancesRequest, +) -> Result { + let balance_details = node.list_balances(); + + let response = GetBalancesResponse { + total_onchain_balance_sats: balance_details.total_onchain_balance_sats, + spendable_onchain_balance_sats: balance_details.spendable_onchain_balance_sats, + total_anchor_channels_reserve_sats: balance_details.total_anchor_channels_reserve_sats, + total_lightning_balance_sats: balance_details.total_lightning_balance_sats, + lightning_balances: balance_details + .lightning_balances + .into_iter() + .map(lightning_balance_to_proto) + .collect(), + pending_balances_from_channel_closures: balance_details + .pending_balances_from_channel_closures + .into_iter() + .map(pending_sweep_balance_to_proto) + .collect(), + }; + Ok(response) +} diff --git a/ldk-server/ldk-server/src/api/mod.rs b/ldk-server/ldk-server/src/api/mod.rs index cd1e0da7f..7d0770d7d 100644 --- a/ldk-server/ldk-server/src/api/mod.rs +++ b/ldk-server/ldk-server/src/api/mod.rs @@ -4,6 +4,7 @@ pub(crate) mod bolt12_receive; pub(crate) mod bolt12_send; pub(crate) mod close_channel; pub(crate) mod error; +pub(crate) mod get_balances; pub(crate) mod get_node_info; pub(crate) mod get_payment_details; pub(crate) mod list_channels; diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index b8fb52596..1062cbc5a 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -16,6 +16,7 @@ use crate::api::bolt11_send::{handle_bolt11_send_request, BOLT11_SEND_PATH}; use crate::api::bolt12_receive::{handle_bolt12_receive_request, BOLT12_RECEIVE_PATH}; use crate::api::bolt12_send::{handle_bolt12_send_request, BOLT12_SEND_PATH}; use crate::api::close_channel::{handle_close_channel_request, CLOSE_CHANNEL_PATH}; +use crate::api::get_balances::{handle_get_balances_request, GET_BALANCES}; use crate::api::get_node_info::{handle_get_node_info_request, GET_NODE_INFO}; use crate::api::get_payment_details::{ handle_get_payment_details_request, GET_PAYMENT_DETAILS_PATH, @@ -50,6 +51,7 @@ impl Service> for NodeService { // Exclude '/' from path pattern matching. match &req.uri().path()[1..] { GET_NODE_INFO => Box::pin(handle_request(node, req, handle_get_node_info_request)), + GET_BALANCES => Box::pin(handle_request(node, req, handle_get_balances_request)), ONCHAIN_RECEIVE_PATH => { Box::pin(handle_request(node, req, handle_onchain_receive_request)) }, diff --git a/ldk-server/ldk-server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs index 5446bc6cb..5d5b7d5a0 100644 --- a/ldk-server/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -2,10 +2,17 @@ use bytes::Bytes; use hex::prelude::*; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; use ldk_node::payment::{PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus}; -use ldk_node::ChannelDetails; +use ldk_node::{ChannelDetails, LightningBalance, PendingSweepBalance}; +use ldk_server_protos::types::lightning_balance::BalanceType::{ + ClaimableAwaitingConfirmations, ClaimableOnChannelClose, ContentiousClaimable, + CounterpartyRevokedOutputClaimable, MaybePreimageClaimableHtlc, MaybeTimeoutClaimableHtlc, +}; use ldk_server_protos::types::payment_kind::Kind::{ Bolt11, Bolt11Jit, Bolt12Offer, Bolt12Refund, Onchain, Spontaneous, }; +use ldk_server_protos::types::pending_sweep_balance::BalanceType::{ + AwaitingThresholdConfirmations, BroadcastAwaitingConfirmation, PendingBroadcast, +}; use ldk_server_protos::types::{Channel, LspFeeLimits, OutPoint, Payment}; pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { @@ -152,3 +159,164 @@ pub(crate) fn payment_kind_to_proto( }, } } + +pub(crate) fn lightning_balance_to_proto( + lightning_balance: LightningBalance, +) -> ldk_server_protos::types::LightningBalance { + match lightning_balance { + LightningBalance::ClaimableOnChannelClose { + channel_id, + counterparty_node_id, + amount_satoshis, + transaction_fee_satoshis, + outbound_payment_htlc_rounded_msat, + outbound_forwarded_htlc_rounded_msat, + inbound_claiming_htlc_rounded_msat, + inbound_htlc_rounded_msat, + } => ldk_server_protos::types::LightningBalance { + balance_type: Some(ClaimableOnChannelClose( + ldk_server_protos::types::ClaimableOnChannelClose { + channel_id: channel_id.0.to_lower_hex_string(), + counterparty_node_id: counterparty_node_id.to_string(), + amount_satoshis, + transaction_fee_satoshis, + outbound_payment_htlc_rounded_msat, + outbound_forwarded_htlc_rounded_msat, + inbound_claiming_htlc_rounded_msat, + inbound_htlc_rounded_msat, + }, + )), + }, + LightningBalance::ClaimableAwaitingConfirmations { + channel_id, + counterparty_node_id, + amount_satoshis, + confirmation_height, + .. + } => ldk_server_protos::types::LightningBalance { + balance_type: Some(ClaimableAwaitingConfirmations( + ldk_server_protos::types::ClaimableAwaitingConfirmations { + channel_id: channel_id.0.to_lower_hex_string(), + counterparty_node_id: counterparty_node_id.to_string(), + amount_satoshis, + confirmation_height, + }, + )), + }, + LightningBalance::ContentiousClaimable { + channel_id, + counterparty_node_id, + amount_satoshis, + timeout_height, + payment_hash, + payment_preimage, + } => ldk_server_protos::types::LightningBalance { + balance_type: Some(ContentiousClaimable( + ldk_server_protos::types::ContentiousClaimable { + channel_id: channel_id.0.to_lower_hex_string(), + counterparty_node_id: counterparty_node_id.to_string(), + amount_satoshis, + timeout_height, + payment_hash: payment_hash.to_string(), + payment_preimage: payment_preimage.to_string(), + }, + )), + }, + LightningBalance::MaybeTimeoutClaimableHTLC { + channel_id, + counterparty_node_id, + amount_satoshis, + claimable_height, + payment_hash, + outbound_payment, + } => ldk_server_protos::types::LightningBalance { + balance_type: Some(MaybeTimeoutClaimableHtlc( + ldk_server_protos::types::MaybeTimeoutClaimableHtlc { + channel_id: channel_id.0.to_lower_hex_string(), + counterparty_node_id: counterparty_node_id.to_string(), + amount_satoshis, + claimable_height, + payment_hash: payment_hash.to_string(), + outbound_payment, + }, + )), + }, + LightningBalance::MaybePreimageClaimableHTLC { + channel_id, + counterparty_node_id, + amount_satoshis, + expiry_height, + payment_hash, + } => ldk_server_protos::types::LightningBalance { + balance_type: Some(MaybePreimageClaimableHtlc( + ldk_server_protos::types::MaybePreimageClaimableHtlc { + channel_id: channel_id.0.to_lower_hex_string(), + counterparty_node_id: counterparty_node_id.to_string(), + amount_satoshis, + expiry_height, + payment_hash: payment_hash.to_string(), + }, + )), + }, + LightningBalance::CounterpartyRevokedOutputClaimable { + channel_id, + counterparty_node_id, + amount_satoshis, + } => ldk_server_protos::types::LightningBalance { + balance_type: Some(CounterpartyRevokedOutputClaimable( + ldk_server_protos::types::CounterpartyRevokedOutputClaimable { + channel_id: channel_id.0.to_lower_hex_string(), + counterparty_node_id: counterparty_node_id.to_string(), + amount_satoshis, + }, + )), + }, + } +} + +pub(crate) fn pending_sweep_balance_to_proto( + pending_sweep_balance: PendingSweepBalance, +) -> ldk_server_protos::types::PendingSweepBalance { + match pending_sweep_balance { + PendingSweepBalance::PendingBroadcast { channel_id, amount_satoshis } => { + ldk_server_protos::types::PendingSweepBalance { + balance_type: Some(PendingBroadcast(ldk_server_protos::types::PendingBroadcast { + channel_id: channel_id.map(|c| c.0.to_lower_hex_string()), + amount_satoshis, + })), + } + }, + PendingSweepBalance::BroadcastAwaitingConfirmation { + channel_id, + latest_broadcast_height, + latest_spending_txid, + amount_satoshis, + } => ldk_server_protos::types::PendingSweepBalance { + balance_type: Some(BroadcastAwaitingConfirmation( + ldk_server_protos::types::BroadcastAwaitingConfirmation { + channel_id: channel_id.map(|c| c.0.to_lower_hex_string()), + latest_broadcast_height, + latest_spending_txid: latest_spending_txid.to_string(), + amount_satoshis, + }, + )), + }, + PendingSweepBalance::AwaitingThresholdConfirmations { + channel_id, + latest_spending_txid, + confirmation_hash, + confirmation_height, + amount_satoshis, + } => ldk_server_protos::types::PendingSweepBalance { + balance_type: Some(AwaitingThresholdConfirmations( + ldk_server_protos::types::AwaitingThresholdConfirmations { + channel_id: channel_id.map(|c| c.0.to_lower_hex_string()), + latest_spending_txid: latest_spending_txid.to_string(), + confirmation_hash: confirmation_hash.to_string(), + confirmation_height, + amount_satoshis, + }, + )), + }, + } +} From fc6012963af6abb545338b17b437093ec9525e1a Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:09:12 -0800 Subject: [PATCH 075/203] Add docs for API response objects. --- ldk-server/ldk-server-protos/src/api.rs | 28 ++++++++++++++++++ .../ldk-server-protos/src/proto/api.proto | 29 ++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index 268965d50..673734de2 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -5,6 +5,8 @@ #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GetNodeInfoRequest {} +/// The response `content` for the `GetNodeInfo` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GetNodeInfoResponse { @@ -50,6 +52,8 @@ pub struct GetNodeInfoResponse { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OnchainReceiveRequest {} +/// The response `content` for the `OnchainReceive` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`.. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OnchainReceiveResponse { @@ -80,6 +84,8 @@ pub struct OnchainSendRequest { #[prost(bool, optional, tag = "3")] pub send_all: ::core::option::Option, } +/// The response `content` for the `OnchainSend` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OnchainSendResponse { @@ -107,6 +113,8 @@ pub struct Bolt11ReceiveRequest { #[prost(uint32, tag = "3")] pub expiry_secs: u32, } +/// The response `content` for the `Bolt11Receive` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Bolt11ReceiveResponse { @@ -130,6 +138,8 @@ pub struct Bolt11SendRequest { #[prost(uint64, optional, tag = "2")] pub amount_msat: ::core::option::Option, } +/// The response `content` for the `Bolt11Send` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Bolt11SendResponse { @@ -159,6 +169,8 @@ pub struct Bolt12ReceiveRequest { #[prost(uint64, optional, tag = "4")] pub quantity: ::core::option::Option, } +/// The response `content` for the `Bolt12Receive` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Bolt12ReceiveResponse { @@ -190,6 +202,8 @@ pub struct Bolt12SendRequest { #[prost(string, optional, tag = "4")] pub payer_note: ::core::option::Option<::prost::alloc::string::String>, } +/// The response `content` for the `Bolt12Send` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Bolt12SendResponse { @@ -222,6 +236,8 @@ pub struct OpenChannelRequest { #[prost(bool, tag = "6")] pub announce_channel: bool, } +/// The response `content` for the `OpenChannel` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OpenChannelResponse { @@ -244,6 +260,8 @@ pub struct UpdateChannelConfigRequest { #[prost(message, optional, tag = "3")] pub channel_config: ::core::option::Option, } +/// The response `content` for the `UpdateChannelConfig` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct UpdateChannelConfigResponse {} @@ -267,6 +285,8 @@ pub struct CloseChannelRequest { #[prost(string, optional, tag = "4")] pub force_close_reason: ::core::option::Option<::prost::alloc::string::String>, } +/// The response `content` for the `CloseChannel` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CloseChannelResponse {} @@ -275,6 +295,8 @@ pub struct CloseChannelResponse {} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ListChannelsRequest {} +/// The response `content` for the `ListChannels` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ListChannelsResponse { @@ -291,6 +313,8 @@ pub struct GetPaymentDetailsRequest { #[prost(string, tag = "1")] pub payment_id: ::prost::alloc::string::String, } +/// The response `content` for the `GetPaymentDetails` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GetPaymentDetailsResponse { @@ -304,6 +328,8 @@ pub struct GetPaymentDetailsResponse { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ListPaymentsRequest {} +/// The response `content` for the `ListPayments` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ListPaymentsResponse { @@ -316,6 +342,8 @@ pub struct ListPaymentsResponse { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GetBalancesRequest {} +/// The response `content` for the `GetBalances` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct GetBalancesResponse { diff --git a/ldk-server/ldk-server-protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto index 9002ce4ff..e9a26ba70 100644 --- a/ldk-server/ldk-server-protos/src/proto/api.proto +++ b/ldk-server/ldk-server-protos/src/proto/api.proto @@ -10,6 +10,8 @@ import 'types.proto'; message GetNodeInfoRequest { } +// The response `content` for the `GetNodeInfo` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message GetNodeInfoResponse { // The hex-encoded `node-id` or public key for our own lightning node. @@ -54,6 +56,8 @@ message GetNodeInfoResponse { message OnchainReceiveRequest { } +// The response `content` for the `OnchainReceive` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`.. message OnchainReceiveResponse { // A Bitcoin on-chain address. @@ -82,6 +86,8 @@ message OnchainSendRequest { optional bool send_all = 3; } +// The response `content` for the `OnchainSend` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message OnchainSendResponse { // The transaction ID of the broadcasted transaction. @@ -107,7 +113,8 @@ message Bolt11ReceiveRequest { uint32 expiry_secs = 3; } - +// The response `content` for the `Bolt11Receive` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message Bolt11ReceiveResponse { // An invoice for a payment within the Lightning Network. @@ -130,6 +137,8 @@ message Bolt11SendRequest { } +// The response `content` for the `Bolt11Send` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message Bolt11SendResponse { // An identifier used to uniquely identify a payment. @@ -157,6 +166,8 @@ message Bolt12ReceiveRequest { optional uint64 quantity = 4; } +// The response `content` for the `Bolt12Receive` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message Bolt12ReceiveResponse { // An offer for a payment within the Lightning Network. @@ -186,6 +197,8 @@ message Bolt12SendRequest { optional string payer_note = 4; } +// The response `content` for the `Bolt12Send` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message Bolt12SendResponse { // An identifier used to uniquely identify a payment. @@ -216,6 +229,8 @@ message OpenChannelRequest { bool announce_channel = 6; } +// The response `content` for the `OpenChannel` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message OpenChannelResponse { // The channel id of the created channel that user can use to refer to channel. @@ -236,6 +251,8 @@ message UpdateChannelConfigRequest { types.ChannelConfig channel_config = 3; } +// The response `content` for the `UpdateChannelConfig` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message UpdateChannelConfigResponse { } @@ -258,6 +275,8 @@ message CloseChannelRequest { optional string force_close_reason = 4; } +// The response `content` for the `CloseChannel` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message CloseChannelResponse { } @@ -266,6 +285,8 @@ message CloseChannelResponse { // See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_channels message ListChannelsRequest {} +// The response `content` for the `ListChannels` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message ListChannelsResponse { // List of channels. @@ -279,6 +300,8 @@ message GetPaymentDetailsRequest { string payment_id = 1; } +// The response `content` for the `GetPaymentDetails` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message GetPaymentDetailsResponse { // Represents a payment. // Will be `None` if payment doesn't exist. @@ -289,6 +312,8 @@ message GetPaymentDetailsResponse { // See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_payments message ListPaymentsRequest {} +// The response `content` for the `ListPayments` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message ListPaymentsResponse { // List of payments. repeated types.Payment payments = 1; @@ -298,6 +323,8 @@ message ListPaymentsResponse { // See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_balances message GetBalancesRequest {} +// The response `content` for the `GetBalances` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message GetBalancesResponse { // The total balance of our on-chain wallet. uint64 total_onchain_balance_sats = 1; From 6bdcf016adaf6dc012e10c45804c58582bf01422 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:13:52 -0800 Subject: [PATCH 076/203] Add file based Config support. --- ldk-server/ldk-server/ldk-server.config | 22 ++++ ldk-server/ldk-server/src/main.rs | 64 +++-------- ldk-server/ldk-server/src/util/config.rs | 136 +++++++++++++++++++++++ ldk-server/ldk-server/src/util/mod.rs | 1 + 4 files changed, 176 insertions(+), 47 deletions(-) create mode 100644 ldk-server/ldk-server/ldk-server.config create mode 100644 ldk-server/ldk-server/src/util/config.rs diff --git a/ldk-server/ldk-server/ldk-server.config b/ldk-server/ldk-server/ldk-server.config new file mode 100644 index 000000000..b44dc4808 --- /dev/null +++ b/ldk-server/ldk-server/ldk-server.config @@ -0,0 +1,22 @@ +{ + // The addresses on which the lightning node will listen for incoming connections. + "listening_address": "localhost:3001", + + // The Bitcoin network to use. + "network": "regtest", + + // The address on which LDK Server will accept incoming requests. + "rest_service_address": "127.0.0.1:3002", + + // The path where the underlying LDK and BDK persist their data. + "storage_dir_path": "/tmp", + + // Bitcoin Core's RPC endpoint. + "bitcoind_rpc_address": "127.0.0.1:8332", + + // Bitcoin Core's RPC user. + "bitcoind_rpc_user": "bitcoind-testuser", + + // Bitcoin Core's RPC password. + "bitcoind_rpc_password": "bitcoind-testpassword" +} diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index c75c44663..6d31341d9 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -5,8 +5,6 @@ mod util; use crate::service::NodeService; -use ldk_node::bitcoin::Network; -use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_node::{Builder, Event, LogLevel}; use tokio::net::TcpListener; @@ -15,65 +13,36 @@ use tokio::signal::unix::SignalKind; use hyper::server::conn::http1; use hyper_util::rt::TokioIo; +use crate::util::config::load_config; use ldk_node::config::Config; -use std::net::SocketAddr; -use std::str::FromStr; +use std::path::Path; use std::sync::Arc; fn main() { let args: Vec = std::env::args().collect(); - if args.len() < 8 { - eprintln!( - "Usage: {} storage_path listening_addr rest_svc_addr network bitcoind_rpc_addr bitcoind_rpc_user bitcoind_rpc_password", - args[0] - ); + if args.len() < 2 { + eprintln!("Usage: {} config_path", args[0]); std::process::exit(-1); } - let mut config = Config::default(); - config.storage_dir_path = args[1].clone(); - config.log_level = LogLevel::Trace; + let mut ldk_node_config = Config::default(); + let config_file = load_config(Path::new(&args[1])).expect("Invalid configuration file."); - config.listening_addresses = match SocketAddress::from_str(&args[2]) { - Ok(addr) => Some(vec![addr]), - Err(_) => { - eprintln!("Failed to parse listening_addr: {}", args[2]); - std::process::exit(-1); - }, - }; - - let rest_svc_addr = match SocketAddr::from_str(&args[3]) { - Ok(addr) => addr, - Err(_) => { - eprintln!("Failed to parse rest_svc_addr: {}", args[3]); - std::process::exit(-1); - }, - }; + ldk_node_config.log_level = LogLevel::Trace; + ldk_node_config.storage_dir_path = config_file.storage_dir_path; + ldk_node_config.listening_addresses = Some(vec![config_file.listening_addr]); + ldk_node_config.network = config_file.network; - config.network = match Network::from_str(&args[4]) { - Ok(network) => network, - Err(_) => { - eprintln!("Unsupported network: {}. Use 'bitcoin', 'testnet', 'regtest', 'signet', 'regtest'.", args[4]); - std::process::exit(-1); - }, - }; - - let mut builder = Builder::from_config(config); + let mut builder = Builder::from_config(ldk_node_config); - let bitcoind_rpc_addr = match SocketAddr::from_str(&args[5]) { - Ok(addr) => addr, - Err(_) => { - eprintln!("Failed to parse bitcoind_rpc_addr: {}", args[3]); - std::process::exit(-1); - }, - }; + let bitcoind_rpc_addr = config_file.bitcoind_rpc_addr; builder.set_chain_source_bitcoind_rpc( bitcoind_rpc_addr.ip().to_string(), bitcoind_rpc_addr.port(), - args[6].clone(), - args[7].clone(), + config_file.bitcoind_rpc_user, + config_file.bitcoind_rpc_password, ); let runtime = match tokio::runtime::Builder::new_multi_thread().enable_all().build() { @@ -116,8 +85,9 @@ fn main() { }, }; let event_node = Arc::clone(&node); - let rest_svc_listener = - TcpListener::bind(rest_svc_addr).await.expect("Failed to bind listening port"); + let rest_svc_listener = TcpListener::bind(config_file.rest_service_addr) + .await + .expect("Failed to bind listening port"); loop { tokio::select! { event = event_node.next_event_async() => { diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs new file mode 100644 index 000000000..5c6e7b3a8 --- /dev/null +++ b/ldk-server/ldk-server/src/util/config.rs @@ -0,0 +1,136 @@ +use ldk_node::bitcoin::Network; +use ldk_node::lightning::ln::msgs::SocketAddress; +use serde::{Deserialize, Serialize}; +use std::net::SocketAddr; +use std::path::Path; +use std::str::FromStr; +use std::{fs, io}; + +/// Configuration for LDK Server. +#[derive(PartialEq, Eq, Debug)] +pub struct Config { + pub listening_addr: SocketAddress, + pub network: Network, + pub rest_service_addr: SocketAddr, + pub storage_dir_path: String, + pub bitcoind_rpc_addr: SocketAddr, + pub bitcoind_rpc_user: String, + pub bitcoind_rpc_password: String, +} + +impl TryFrom for Config { + type Error = io::Error; + + fn try_from(json_config: JsonConfig) -> io::Result { + let listening_addr = + SocketAddress::from_str(&json_config.listening_address).map_err(|e| { + io::Error::new( + io::ErrorKind::InvalidInput, + format!("Invalid listening address configured: {}", e), + ) + })?; + let rest_service_addr = + SocketAddr::from_str(&json_config.rest_service_address).map_err(|e| { + io::Error::new( + io::ErrorKind::InvalidInput, + format!("Invalid rest service address configured: {}", e), + ) + })?; + + let bitcoind_rpc_addr = + SocketAddr::from_str(&json_config.bitcoind_rpc_address).map_err(|e| { + io::Error::new( + io::ErrorKind::InvalidInput, + format!("Invalid bitcoind RPC address configured: {}", e), + ) + })?; + + Ok(Config { + listening_addr, + network: json_config.network, + rest_service_addr, + storage_dir_path: json_config.storage_dir_path, + bitcoind_rpc_addr, + bitcoind_rpc_user: json_config.bitcoind_rpc_user, + bitcoind_rpc_password: json_config.bitcoind_rpc_password, + }) + } +} + +/// Configuration loaded from a JSON file. +#[derive(Deserialize, Serialize)] +pub struct JsonConfig { + listening_address: String, + network: Network, + rest_service_address: String, + storage_dir_path: String, + bitcoind_rpc_address: String, + bitcoind_rpc_user: String, + bitcoind_rpc_password: String, +} + +/// Loads the configuration from a JSON file at the given path. +pub fn load_config>(config_path: P) -> io::Result { + let file_contents = fs::read_to_string(config_path.as_ref()).map_err(|e| { + io::Error::new( + e.kind(), + format!("Failed to read config file '{}': {}", config_path.as_ref().display(), e), + ) + })?; + + let json_string = remove_json_comments(file_contents.as_str()); + let json_config: JsonConfig = serde_json::from_str(&json_string).map_err(|e| { + io::Error::new( + io::ErrorKind::InvalidData, + format!("Config file contains invalid JSON format: {}", e), + ) + })?; + Ok(Config::try_from(json_config)?) +} + +fn remove_json_comments(s: &str) -> String { + s.lines() + .map(|line| if let Some(pos) = line.find("//") { &line[..pos] } else { line }) + .collect::>() + .join("\n") +} + +#[cfg(test)] +mod tests { + use super::*; + use ldk_node::{bitcoin::Network, lightning::ln::msgs::SocketAddress}; + use std::str::FromStr; + + #[test] + fn test_read_json_config_from_file() { + let storage_path = std::env::temp_dir(); + let config_file_name = "config.json"; + + let json_config = r#"{ + "listening_address": "localhost:3001", + "network": "regtest", + "rest_service_address": "127.0.0.1:3002", + "storage_dir_path": "/tmp", + "bitcoind_rpc_address":"127.0.0.1:8332", // comment-1 + "bitcoind_rpc_user": "bitcoind-testuser", + "bitcoind_rpc_password": "bitcoind-testpassword", + "unknown_key": "random-value" + // comment-2 + }"#; + + fs::write(storage_path.join(config_file_name), json_config).unwrap(); + + assert_eq!( + load_config(storage_path.join(config_file_name)).unwrap(), + Config { + listening_addr: SocketAddress::from_str("localhost:3001").unwrap(), + network: Network::Regtest, + rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(), + storage_dir_path: "/tmp".to_string(), + bitcoind_rpc_addr: SocketAddr::from_str("127.0.0.1:8332").unwrap(), + bitcoind_rpc_user: "bitcoind-testuser".to_string(), + bitcoind_rpc_password: "bitcoind-testpassword".to_string(), + } + ) + } +} diff --git a/ldk-server/ldk-server/src/util/mod.rs b/ldk-server/ldk-server/src/util/mod.rs index 8f7d1a3d9..02789f03c 100644 --- a/ldk-server/ldk-server/src/util/mod.rs +++ b/ldk-server/ldk-server/src/util/mod.rs @@ -1 +1,2 @@ +pub(crate) mod config; pub(crate) mod proto_adapter; From 73f4abe878a2a82c37f74836df50994f909fd880 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:01:09 -0800 Subject: [PATCH 077/203] Fix PaginatedKVStore interface to account for time ordering in pagination. --- ldk-server/ldk-server/src/io/paginated_kv_store.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ldk-server/ldk-server/src/io/paginated_kv_store.rs b/ldk-server/ldk-server/src/io/paginated_kv_store.rs index f0792d6bf..28c4ad19f 100644 --- a/ldk-server/ldk-server/src/io/paginated_kv_store.rs +++ b/ldk-server/ldk-server/src/io/paginated_kv_store.rs @@ -72,7 +72,7 @@ pub trait PaginatedKVStore { /// `primary_namespace`, ordered in descending order of `time`. /// /// The `list` method returns the latest records first, based on the `time` associated with each key. - /// Pagination is controlled by the `next_page_token`, which is an `Option` + /// Pagination is controlled by the `next_page_token`, which is an `Option<(String, i64)>` /// used to determine the starting point for the next page of results. If `next_page_token` is `None`, /// the listing starts from the most recent entry. The `next_page_token` in the returned /// [`ListResponse`] can be used to fetch the next page of results. @@ -85,7 +85,8 @@ pub trait PaginatedKVStore { /// /// [`ListResponse`]: struct.ListResponse.html fn list( - &self, primary_namespace: &str, secondary_namespace: &str, next_page_token: Option, + &self, primary_namespace: &str, secondary_namespace: &str, + next_page_token: Option<(String, i64)>, ) -> Result; } @@ -98,5 +99,5 @@ pub struct ListResponse { pub keys: Vec, /// A token that can be used to retrieve the next set of keys. - pub next_page_token: Option, + pub next_page_token: Option<(String, i64)>, } From 89c718e3590c27fc6fa10867139605f9b261943f Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 26 Nov 2024 09:52:10 -0800 Subject: [PATCH 078/203] Add Sqlite based PaginatedKVStore impl. --- ldk-server/Cargo.lock | 2 + ldk-server/ldk-server/Cargo.toml | 4 + ldk-server/ldk-server/src/io/mod.rs | 2 + .../ldk-server/src/io/sqlite_store/mod.rs | 440 ++++++++++++++++++ ldk-server/ldk-server/src/io/utils.rs | 99 ++++ 5 files changed, 547 insertions(+) create mode 100644 ldk-server/ldk-server/src/io/sqlite_store/mod.rs create mode 100644 ldk-server/ldk-server/src/io/utils.rs diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 33c213346..507668c34 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -946,6 +946,8 @@ dependencies = [ "ldk-node", "ldk-server-protos", "prost", + "rand", + "rusqlite", "serde", "serde_json", "tokio", diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index 984e207f8..ceebf1caa 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -15,3 +15,7 @@ prost = { version = "0.11.6", default-features = false, features = ["std"] } ldk-server-protos = { path = "../ldk-server-protos" } bytes = "1.4.0" hex = { package = "hex-conservative", version = "0.2.1", default-features = false } +rusqlite = { version = "0.28.0", features = ["bundled"] } + +[dev-dependencies] +rand = "0.8.5" diff --git a/ldk-server/ldk-server/src/io/mod.rs b/ldk-server/ldk-server/src/io/mod.rs index ff65caf67..6cda7ce20 100644 --- a/ldk-server/ldk-server/src/io/mod.rs +++ b/ldk-server/ldk-server/src/io/mod.rs @@ -1 +1,3 @@ pub(crate) mod paginated_kv_store; +pub(crate) mod sqlite_store; +pub(crate) mod utils; diff --git a/ldk-server/ldk-server/src/io/sqlite_store/mod.rs b/ldk-server/ldk-server/src/io/sqlite_store/mod.rs new file mode 100644 index 000000000..cee2baeca --- /dev/null +++ b/ldk-server/ldk-server/src/io/sqlite_store/mod.rs @@ -0,0 +1,440 @@ +use crate::io::paginated_kv_store::{ListResponse, PaginatedKVStore}; +use crate::io::utils::check_namespace_key_validity; +use ldk_node::lightning::types::string::PrintableString; +use rusqlite::{named_params, Connection}; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; +use std::{fs, io}; + +/// The default database file name. +pub const DEFAULT_SQLITE_DB_FILE_NAME: &str = "ldk_server_data.sqlite"; + +/// The default table in which we store all the paginated data. +pub const DEFAULT_PAGINATED_KV_TABLE_NAME: &str = "ldk_paginated_data"; + +// The current SQLite `user_version`, which we can use if we'd ever need to do a schema migration. +const SCHEMA_USER_VERSION: u16 = 1; + +// The maximum number of keys retrieved per page in paginated list operation. +const LIST_KEYS_MAX_PAGE_SIZE: i32 = 100; + +pub struct SqliteStore { + connection: Arc>, + data_dir: PathBuf, + paginated_kv_table_name: String, +} + +impl SqliteStore { + /// Constructs a new [`SqliteStore`]. + /// + /// If not already existing, a new SQLite database will be created in the given `data_dir` under the + /// given `db_file_name` (or the default to [`DEFAULT_SQLITE_DB_FILE_NAME`] if set to `None`). + /// + /// Similarly, the given `paginated_kv_table_name` will be used or default to [`DEFAULT_PAGINATED_KV_TABLE_NAME`]. + pub fn new( + data_dir: PathBuf, db_file_name: Option, paginated_kv_table_name: Option, + ) -> io::Result { + let db_file_name = db_file_name.unwrap_or(DEFAULT_SQLITE_DB_FILE_NAME.to_string()); + let paginated_kv_table_name = + paginated_kv_table_name.unwrap_or(DEFAULT_PAGINATED_KV_TABLE_NAME.to_string()); + + fs::create_dir_all(data_dir.clone()).map_err(|e| { + let msg = format!( + "Failed to create database destination directory {}: {}", + data_dir.display(), + e + ); + io::Error::new(io::ErrorKind::Other, msg) + })?; + let mut db_file_path = data_dir.clone(); + db_file_path.push(db_file_name); + + let connection = Connection::open(db_file_path.clone()).map_err(|e| { + let msg = + format!("Failed to open/create database file {}: {}", db_file_path.display(), e); + io::Error::new(io::ErrorKind::Other, msg) + })?; + + let sql = format!("SELECT user_version FROM pragma_user_version"); + let version_res: u16 = connection.query_row(&sql, [], |row| row.get(0)).unwrap(); + + if version_res == 0 { + // New database, set our SCHEMA_USER_VERSION and continue + connection + .pragma( + Some(rusqlite::DatabaseName::Main), + "user_version", + SCHEMA_USER_VERSION, + |_| Ok(()), + ) + .map_err(|e| { + let msg = format!("Failed to set PRAGMA user_version: {}", e); + io::Error::new(io::ErrorKind::Other, msg) + })?; + } else if version_res > SCHEMA_USER_VERSION { + let msg = format!( + "Failed to open database: incompatible schema version {}. Expected: {}", + version_res, SCHEMA_USER_VERSION + ); + return Err(io::Error::new(io::ErrorKind::Other, msg)); + } + + let create_paginated_kv_table_sql = format!( + "CREATE TABLE IF NOT EXISTS {} ( + primary_namespace TEXT NOT NULL, + secondary_namespace TEXT DEFAULT \"\" NOT NULL, + key TEXT NOT NULL CHECK (key <> ''), + creation_time INTEGER NOT NULL, + value BLOB, PRIMARY KEY ( primary_namespace, secondary_namespace, key ) + );", + paginated_kv_table_name + ); + + connection.execute(&create_paginated_kv_table_sql, []).map_err(|e| { + let msg = format!("Failed to create table {}: {}", paginated_kv_table_name, e); + io::Error::new(io::ErrorKind::Other, msg) + })?; + + let index_creation_time_sql = format!( + "CREATE INDEX idx_creation_time ON {} (creation_time);", + paginated_kv_table_name + ); + + connection.execute(&index_creation_time_sql, []).map_err(|e| { + let msg = format!( + "Failed to create index on creation_time, table {}: {}", + paginated_kv_table_name, e + ); + io::Error::new(io::ErrorKind::Other, msg) + })?; + + let connection = Arc::new(Mutex::new(connection)); + Ok(Self { connection, data_dir, paginated_kv_table_name }) + } + + /// Returns the data directory. + pub fn get_data_dir(&self) -> PathBuf { + self.data_dir.clone() + } + + fn read_internal( + &self, kv_table_name: &str, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> io::Result> { + check_namespace_key_validity(primary_namespace, secondary_namespace, Some(key), "read")?; + + let locked_conn = self.connection.lock().unwrap(); + let sql = + format!("SELECT value FROM {} WHERE primary_namespace=:primary_namespace AND secondary_namespace=:secondary_namespace AND key=:key;", + kv_table_name); + + let mut stmt = locked_conn.prepare_cached(&sql).map_err(|e| { + let msg = format!("Failed to prepare statement: {}", e); + io::Error::new(io::ErrorKind::Other, msg) + })?; + + let res = stmt + .query_row( + named_params! { + ":primary_namespace": primary_namespace, + ":secondary_namespace": secondary_namespace, + ":key": key, + }, + |row| row.get(0), + ) + .map_err(|e| match e { + rusqlite::Error::QueryReturnedNoRows => { + let msg = format!( + "Failed to read as key could not be found: {}/{}/{}", + PrintableString(primary_namespace), + PrintableString(secondary_namespace), + PrintableString(key) + ); + io::Error::new(io::ErrorKind::NotFound, msg) + }, + e => { + let msg = format!( + "Failed to read from key {}/{}/{}: {}", + PrintableString(primary_namespace), + PrintableString(secondary_namespace), + PrintableString(key), + e + ); + io::Error::new(io::ErrorKind::Other, msg) + }, + })?; + Ok(res) + } + + fn remove_internal( + &self, kv_table_name: &str, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> io::Result<()> { + check_namespace_key_validity(primary_namespace, secondary_namespace, Some(key), "remove")?; + + let locked_conn = self.connection.lock().unwrap(); + + let sql = format!("DELETE FROM {} WHERE primary_namespace=:primary_namespace AND secondary_namespace=:secondary_namespace AND key=:key;", kv_table_name); + + let mut stmt = locked_conn.prepare_cached(&sql).map_err(|e| { + let msg = format!("Failed to prepare statement: {}", e); + io::Error::new(io::ErrorKind::Other, msg) + })?; + + stmt.execute(named_params! { + ":primary_namespace": primary_namespace, + ":secondary_namespace": secondary_namespace, + ":key": key, + }) + .map_err(|e| { + let msg = format!( + "Failed to delete key {}/{}/{}: {}", + PrintableString(primary_namespace), + PrintableString(secondary_namespace), + PrintableString(key), + e + ); + io::Error::new(io::ErrorKind::Other, msg) + })?; + Ok(()) + } +} + +impl PaginatedKVStore for SqliteStore { + fn read( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, + ) -> io::Result> { + self.read_internal( + &self.paginated_kv_table_name, + primary_namespace, + secondary_namespace, + key, + ) + } + + fn write( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, time: i64, buf: &[u8], + ) -> io::Result<()> { + check_namespace_key_validity(primary_namespace, secondary_namespace, Some(key), "write")?; + + let locked_conn = self.connection.lock().unwrap(); + + let sql = format!( + "INSERT INTO {} (primary_namespace, secondary_namespace, key, creation_time, value) + VALUES (:primary_namespace, :secondary_namespace, :key, :creation_time, :value) + ON CONFLICT(primary_namespace, secondary_namespace, key) + DO UPDATE SET value = excluded.value;", + self.paginated_kv_table_name + ); + + let mut stmt = locked_conn.prepare_cached(&sql).map_err(|e| { + let msg = format!("Failed to prepare statement: {}", e); + io::Error::new(io::ErrorKind::Other, msg) + })?; + + stmt.execute(named_params! { + ":primary_namespace": primary_namespace, + ":secondary_namespace": secondary_namespace, + ":key": key, + ":creation_time": time, + ":value": buf, + }) + .map(|_| ()) + .map_err(|e| { + let msg = format!( + "Failed to write to key {}/{}/{}: {}", + PrintableString(primary_namespace), + PrintableString(secondary_namespace), + PrintableString(key), + e + ); + io::Error::new(io::ErrorKind::Other, msg) + }) + } + + fn remove( + &self, primary_namespace: &str, secondary_namespace: &str, key: &str, _lazy: bool, + ) -> io::Result<()> { + self.remove_internal( + &self.paginated_kv_table_name, + primary_namespace, + secondary_namespace, + key, + ) + } + + fn list( + &self, primary_namespace: &str, secondary_namespace: &str, + page_token: Option<(String, i64)>, + ) -> io::Result { + check_namespace_key_validity(primary_namespace, secondary_namespace, None, "list")?; + + let locked_conn = self.connection.lock().unwrap(); + + let sql = format!( + "SELECT key, creation_time FROM {} WHERE primary_namespace=:primary_namespace AND secondary_namespace=:secondary_namespace \ + AND ( creation_time < :creation_time_token OR (creation_time = :creation_time_token AND key > :key_token) ) \ + ORDER BY creation_time DESC, key ASC LIMIT :page_size", + self.paginated_kv_table_name + ); + + let mut stmt = locked_conn.prepare_cached(&sql).map_err(|e| { + let msg = format!("Failed to prepare statement: {}", e); + io::Error::new(io::ErrorKind::Other, msg) + })?; + + let mut keys: Vec = Vec::new(); + let page_token = page_token.unwrap_or(("".to_string(), i64::MAX)); + + let rows_iter = stmt + .query_map( + named_params! { + ":primary_namespace": primary_namespace, + ":secondary_namespace": secondary_namespace, + ":key_token": page_token.0, + ":creation_time_token": page_token.1, + ":page_size": LIST_KEYS_MAX_PAGE_SIZE, + }, + |row| { + let key: String = row.get(0)?; + let creation_time: i64 = row.get(1)?; + Ok((key, creation_time)) + }, + ) + .map_err(|e| { + let msg = format!("Failed to retrieve queried rows: {}", e); + io::Error::new(io::ErrorKind::Other, msg) + })?; + + let mut last_creation_time: Option = None; + for r in rows_iter { + let (k, ct) = r.map_err(|e| { + let msg = format!("Failed to retrieve queried rows: {}", e); + io::Error::new(io::ErrorKind::Other, msg) + })?; + keys.push(k); + last_creation_time = Some(ct); + } + + let last_key = keys.last().cloned(); + let next_page_token = if let (Some(k), Some(ct)) = (last_key, last_creation_time) { + Some((k, ct)) + } else { + None + }; + + Ok(ListResponse { keys, next_page_token }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ldk_node::lightning::util::persist::KVSTORE_NAMESPACE_KEY_MAX_LEN; + use rand::distributions::Alphanumeric; + use rand::{thread_rng, Rng}; + use std::panic::RefUnwindSafe; + + impl Drop for SqliteStore { + fn drop(&mut self) { + match fs::remove_dir_all(&self.data_dir) { + Err(e) => println!("Failed to remove test store directory: {}", e), + _ => {}, + } + } + } + + #[test] + fn read_write_remove_list_persist() { + let mut temp_path = random_storage_path(); + temp_path.push("read_write_remove_list_persist"); + let store = SqliteStore::new( + temp_path, + Some("test_db".to_string()), + Some("test_table".to_string()), + ) + .unwrap(); + do_read_write_remove_list_persist(&store); + } + + pub(crate) fn random_storage_path() -> PathBuf { + let mut temp_path = std::env::temp_dir(); + let mut rng = thread_rng(); + let rand_dir: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect(); + temp_path.push(rand_dir); + temp_path + } + + pub(crate) fn do_read_write_remove_list_persist( + kv_store: &K, + ) { + let data = [42u8; 32]; + + let primary_namespace = "testspace"; + let secondary_namespace = "testsubspace"; + let testkey = "testkey_0"; + + let list_all_keys = |primary_namespace: &str, secondary_namespace: &str| -> Vec { + let mut all_keys = Vec::new(); + let mut page_token = None; + loop { + let list_response = + kv_store.list(primary_namespace, secondary_namespace, page_token).unwrap(); + assert!(list_response.keys.len() <= LIST_KEYS_MAX_PAGE_SIZE as usize); + all_keys.extend(list_response.keys); + if list_response.next_page_token.is_none() { + break; + } + page_token = list_response.next_page_token; + } + all_keys + }; + + // Test the basic KVStore operations. + for i in 0..110 { + kv_store + .write(primary_namespace, secondary_namespace, &format!("testkey_{}", i), 0, &data) + .unwrap(); + } + + // Test empty primary/secondary namespaces are allowed, but not empty primary namespace and non-empty + // secondary primary_namespace, and not empty key. + kv_store.write("", "", testkey, 0, &data).unwrap(); + let res = + std::panic::catch_unwind(|| kv_store.write("", secondary_namespace, testkey, 0, &data)); + assert!(res.is_err()); + let res = std::panic::catch_unwind(|| { + kv_store.write(primary_namespace, secondary_namespace, "", 0, &data) + }); + assert!(res.is_err()); + + let listed_keys = list_all_keys(primary_namespace, secondary_namespace); + assert_eq!(listed_keys.len(), 110); + assert_eq!(listed_keys[0], testkey); + + let read_data = kv_store.read(primary_namespace, secondary_namespace, testkey).unwrap(); + assert_eq!(data, &*read_data); + + kv_store.remove(primary_namespace, secondary_namespace, testkey, false).unwrap(); + + let listed_keys = list_all_keys(primary_namespace, secondary_namespace); + assert_eq!(listed_keys.len(), 109); + + // Ensure we have no issue operating with primary_namespace/secondary_namespace/key being KVSTORE_NAMESPACE_KEY_MAX_LEN + let max_chars: String = + std::iter::repeat('A').take(KVSTORE_NAMESPACE_KEY_MAX_LEN).collect(); + kv_store.write(&max_chars, &max_chars, &max_chars, 0, &data).unwrap(); + + println!("{:?}", listed_keys); + + let listed_keys = list_all_keys(&max_chars, &max_chars); + assert_eq!(listed_keys.len(), 1); + assert_eq!(listed_keys[0], max_chars); + + let read_data = kv_store.read(&max_chars, &max_chars, &max_chars).unwrap(); + assert_eq!(data, &*read_data); + + kv_store.remove(&max_chars, &max_chars, &max_chars, false).unwrap(); + + let listed_keys = list_all_keys(&max_chars, &max_chars); + assert_eq!(listed_keys.len(), 0); + } +} diff --git a/ldk-server/ldk-server/src/io/utils.rs b/ldk-server/ldk-server/src/io/utils.rs new file mode 100644 index 000000000..b9bfe59ab --- /dev/null +++ b/ldk-server/ldk-server/src/io/utils.rs @@ -0,0 +1,99 @@ +use ldk_node::lightning::types::string::PrintableString; +use ldk_node::lightning::util::persist::{ + KVSTORE_NAMESPACE_KEY_ALPHABET, KVSTORE_NAMESPACE_KEY_MAX_LEN, +}; + +pub(crate) fn check_namespace_key_validity( + primary_namespace: &str, secondary_namespace: &str, key: Option<&str>, operation: &str, +) -> Result<(), std::io::Error> { + if let Some(key) = key { + if key.is_empty() { + debug_assert!( + false, + "Failed to {} {}/{}/{}: key may not be empty.", + operation, + PrintableString(primary_namespace), + PrintableString(secondary_namespace), + PrintableString(key) + ); + let msg = format!( + "Failed to {} {}/{}/{}: key may not be empty.", + operation, + PrintableString(primary_namespace), + PrintableString(secondary_namespace), + PrintableString(key) + ); + return Err(std::io::Error::new(std::io::ErrorKind::Other, msg)); + } + + if primary_namespace.is_empty() && !secondary_namespace.is_empty() { + debug_assert!(false, + "Failed to {} {}/{}/{}: primary namespace may not be empty if a non-empty secondary namespace is given.", + operation, + PrintableString(primary_namespace), PrintableString(secondary_namespace), PrintableString(key) + ); + let msg = format!( + "Failed to {} {}/{}/{}: primary namespace may not be empty if a non-empty secondary namespace is given.", operation, + PrintableString(primary_namespace), PrintableString(secondary_namespace), PrintableString(key) + ); + return Err(std::io::Error::new(std::io::ErrorKind::Other, msg)); + } + + if !is_valid_kvstore_str(primary_namespace) + || !is_valid_kvstore_str(secondary_namespace) + || !is_valid_kvstore_str(key) + { + debug_assert!( + false, + "Failed to {} {}/{}/{}: primary namespace, secondary namespace, and key must be valid.", + operation, + PrintableString(primary_namespace), + PrintableString(secondary_namespace), + PrintableString(key) + ); + let msg = format!( + "Failed to {} {}/{}/{}: primary namespace, secondary namespace, and key must be valid.", + operation, + PrintableString(primary_namespace), + PrintableString(secondary_namespace), + PrintableString(key) + ); + return Err(std::io::Error::new(std::io::ErrorKind::Other, msg)); + } + } else { + if primary_namespace.is_empty() && !secondary_namespace.is_empty() { + debug_assert!(false, + "Failed to {} {}/{}: primary namespace may not be empty if a non-empty secondary namespace is given.", + operation, PrintableString(primary_namespace), PrintableString(secondary_namespace) + ); + let msg = format!( + "Failed to {} {}/{}: primary namespace may not be empty if a non-empty secondary namespace is given.", + operation, PrintableString(primary_namespace), PrintableString(secondary_namespace) + ); + return Err(std::io::Error::new(std::io::ErrorKind::Other, msg)); + } + if !is_valid_kvstore_str(primary_namespace) || !is_valid_kvstore_str(secondary_namespace) { + debug_assert!( + false, + "Failed to {} {}/{}: primary namespace and secondary namespace must be valid.", + operation, + PrintableString(primary_namespace), + PrintableString(secondary_namespace) + ); + let msg = format!( + "Failed to {} {}/{}: primary namespace and secondary namespace must be valid.", + operation, + PrintableString(primary_namespace), + PrintableString(secondary_namespace) + ); + return Err(std::io::Error::new(std::io::ErrorKind::Other, msg)); + } + } + + Ok(()) +} + +pub(crate) fn is_valid_kvstore_str(key: &str) -> bool { + key.len() <= KVSTORE_NAMESPACE_KEY_MAX_LEN + && key.chars().all(|c| KVSTORE_NAMESPACE_KEY_ALPHABET.contains(c)) +} From 96840c8ff3483494701bfef21012662e89b1a083 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 6 Dec 2024 10:32:56 -0800 Subject: [PATCH 079/203] Easy to have sane defaults with polar. --- ldk-server/ldk-server/ldk-server.config | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ldk-server/ldk-server/ldk-server.config b/ldk-server/ldk-server/ldk-server.config index b44dc4808..d20dd3b4c 100644 --- a/ldk-server/ldk-server/ldk-server.config +++ b/ldk-server/ldk-server/ldk-server.config @@ -9,14 +9,14 @@ "rest_service_address": "127.0.0.1:3002", // The path where the underlying LDK and BDK persist their data. - "storage_dir_path": "/tmp", + "storage_dir_path": "/tmp/ldk-server/", // Bitcoin Core's RPC endpoint. - "bitcoind_rpc_address": "127.0.0.1:8332", + "bitcoind_rpc_address": "127.0.0.1:18444", // Bitcoin Core's RPC user. - "bitcoind_rpc_user": "bitcoind-testuser", + "bitcoind_rpc_user": "polaruser", // Bitcoin Core's RPC password. - "bitcoind_rpc_password": "bitcoind-testpassword" + "bitcoind_rpc_password": "polarpass" } From fdd6bad56c8913ce4274f46dbe21e2f5681a3ba9 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 4 Dec 2024 13:30:15 -0800 Subject: [PATCH 080/203] Add Basic project description and README.md --- ldk-server/README.md | 56 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 ldk-server/README.md diff --git a/ldk-server/README.md b/ldk-server/README.md new file mode 100644 index 000000000..39b764faa --- /dev/null +++ b/ldk-server/README.md @@ -0,0 +1,56 @@ +# LDK Server + +**LDK Server** is a fully-functional Lightning node in daemon form, built on top of +[LDK Node](https://github.com/lightningdevkit/ldk-node), which itself provides a powerful abstraction over the +[Lightning Development Kit (LDK)](https://github.com/lightningdevkit/rust-lightning) and uses a built-in +[Bitcoin Development Kit (BDK)](https://bitcoindevkit.org/) wallet. + +The primary goal of LDK Server is to provide an efficient, stable, and API-first solution for deploying and managing +a Lightning Network node. With its streamlined setup, LDK Server enables users to easily set up, configure, and run +a Lightning node while exposing a robust, language-agnostic API via [Protocol Buffers (Protobuf)](https://protobuf.dev/). + +### Features + +- **Out-of-the-Box Lightning Node**: + - Deploy a Lightning Network node with minimal configuration, no coding required. + +- **API-First Design**: + - Exposes a well-defined API using Protobuf, allowing seamless integration with HTTP-clients or applications. + +- **Powered by LDK**: + - Built on top of LDK-Node, leveraging the modular, reliable, and high-performance architecture of LDK. + +- **Effortless Integration**: + - Ideal for embedding Lightning functionality into payment processors, self-hosted nodes, custodial wallets, or other Lightning-enabled + applications. + +### Project Status + +🚧 **Work in Progress**: +- **APIs Under Development**: Expect breaking changes as the project evolves. +- **Potential Bugs and Inconsistencies**: While progress is being made toward stability, unexpected behavior may occur. +- **Improved Logging and Error Handling Coming Soon**: Current error handling is rudimentary (specially for CLI), and usability improvements are actively being worked on. +- **Pending Testing**: Not tested, hence don't use it for production! + +We welcome your feedback and contributions to help shape the future of LDK Server! + + +### Configuration +Refer `./ldk-server/ldk-server.config to see available configuration options. + +### Building +``` +git clone https://github.com/lightningdevkit/ldk-server.git +cargo build +``` + +### Running +``` +cargo run --bin ldk-server ./ldk-server/ldk-server.config +``` + +Interact with the node using CLI: +``` +./target/debug/ldk-server-cli -b localhost:3002 onchain-receive # To generate onchain-receive address. +./target/debug/ldk-server-cli -b localhost:3002 help # To print help/available commands. +``` From 03d45a00a170cce2491fb04c4e82f42a8b243c3c Mon Sep 17 00:00:00 2001 From: dzdidi Date: Mon, 9 Dec 2024 08:27:29 +0100 Subject: [PATCH 081/203] Add cli missing commands Fix typo in readme Add cli command for GetNodeInfo Add cli command for GetBalance Add cli command for ListChannels Add cli command for ListPayments Co-authored-by: Gursharan Singh <3442979+G8XSU@users.noreply.github.com> --- ldk-server/README.md | 2 +- ldk-server/ldk-server-cli/src/main.rs | 17 ++++++++++ ldk-server/ldk-server-client/src/client.rs | 37 ++++++++++++++++++++-- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/ldk-server/README.md b/ldk-server/README.md index 39b764faa..1d37ee6bc 100644 --- a/ldk-server/README.md +++ b/ldk-server/README.md @@ -36,7 +36,7 @@ We welcome your feedback and contributions to help shape the future of LDK Serve ### Configuration -Refer `./ldk-server/ldk-server.config to see available configuration options. +Refer `./ldk-server/ldk-server.config` to see available configuration options. ### Building ``` diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 42557356f..140df2387 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -3,6 +3,7 @@ use ldk_server_client::client::LdkServerClient; use ldk_server_client::error::LdkServerError; use ldk_server_client::ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, Bolt12SendRequest, + GetBalancesRequest, GetNodeInfoRequest, ListChannelsRequest, ListPaymentsRequest, OnchainReceiveRequest, OnchainSendRequest, OpenChannelRequest, }; @@ -18,6 +19,8 @@ struct Cli { #[derive(Subcommand, Debug)] enum Commands { + GetNodeInfo, + GetBalances, OnchainReceive, OnchainSend { #[arg(short, long)] @@ -73,6 +76,8 @@ enum Commands { #[arg(long)] announce_channel: bool, }, + ListChannels, + ListPayments, } #[tokio::main] @@ -81,6 +86,12 @@ async fn main() { let client = LdkServerClient::new(cli.base_url); match cli.command { + Commands::GetNodeInfo => { + handle_response(client.get_node_info(GetNodeInfoRequest {}).await); + }, + Commands::GetBalances => { + handle_response(client.get_balances(GetBalancesRequest {}).await); + }, Commands::OnchainReceive => { handle_response(client.onchain_receive(OnchainReceiveRequest {}).await); }, @@ -138,6 +149,12 @@ async fn main() { .await, ); }, + Commands::ListChannels => { + handle_response(client.list_channels(ListChannelsRequest {}).await); + }, + Commands::ListPayments => { + handle_response(client.list_payments(ListPaymentsRequest {}).await); + }, } } diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index be9b15a0c..c8f887228 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -4,15 +4,18 @@ use crate::error::LdkServerError; use ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse, Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, - CloseChannelRequest, CloseChannelResponse, ListChannelsRequest, ListChannelsResponse, - OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, - OpenChannelRequest, OpenChannelResponse, + CloseChannelRequest, CloseChannelResponse, GetBalancesRequest, GetBalancesResponse, + GetNodeInfoRequest, GetNodeInfoResponse, ListChannelsRequest, ListChannelsResponse, + ListPaymentsRequest, ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse, + OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, OpenChannelResponse, }; use reqwest::header::CONTENT_TYPE; use reqwest::Client; const APPLICATION_OCTET_STREAM: &str = "application/octet-stream"; +const GET_NODE_INFO_PATH: &str = "GetNodeInfo"; +const GET_BALANCES_PATH: &str = "GetBalances"; const ONCHAIN_RECEIVE_PATH: &str = "OnchainReceive"; const ONCHAIN_SEND_PATH: &str = "OnchainSend"; const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; @@ -22,6 +25,7 @@ const BOLT12_SEND_PATH: &str = "Bolt12Send"; const OPEN_CHANNEL_PATH: &str = "OpenChannel"; const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; const LIST_CHANNELS_PATH: &str = "ListChannels"; +const LIST_PAYMENTS_PATH: &str = "ListPayments"; /// Client to access a hosted instance of LDK Server. #[derive(Clone)] @@ -36,6 +40,24 @@ impl LdkServerClient { Self { base_url, client: Client::new() } } + /// Retrieve the latest node info like `node_id`, `current_best_block` etc. + /// For API contract/usage, refer to docs for [`GetNodeInfoRequest`] and [`GetNodeInfoResponse`]. + pub async fn get_node_info( + &self, request: GetNodeInfoRequest, + ) -> Result { + let url = format!("http://{}/{GET_NODE_INFO_PATH}", self.base_url); + self.post_request(&request, &url).await + } + + /// Retrieves an overview of all known balances. + /// For API contract/usage, refer to docs for [`GetBalancesRequest`] and [`GetBalancesResponse`]. + pub async fn get_balances( + &self, request: GetBalancesRequest, + ) -> Result { + let url = format!("http://{}/{GET_BALANCES_PATH}", self.base_url); + self.post_request(&request, &url).await + } + /// Retrieve a new on-chain funding address. /// For API contract/usage, refer to docs for [`OnchainReceiveRequest`] and [`OnchainReceiveResponse`]. pub async fn onchain_receive( @@ -117,6 +139,15 @@ impl LdkServerClient { self.post_request(&request, &url).await } + /// Retrieves list of all payments sent or received by us. + /// For API contract/usage, refer to docs for [`ListPaymentsRequest`] and [`ListPaymentsResponse`]. + pub async fn list_payments( + &self, request: ListPaymentsRequest, + ) -> Result { + let url = format!("http://{}/{LIST_PAYMENTS_PATH}", self.base_url); + self.post_request(&request, &url).await + } + async fn post_request( &self, request: &Rq, url: &str, ) -> Result { From 831040787d5c05d34aa642faac95ccc187e3e3a6 Mon Sep 17 00:00:00 2001 From: Vincenzo Palazzo Date: Sat, 7 Dec 2024 01:18:39 +0100 Subject: [PATCH 082/203] server: do not panic on --help command This commit is including a simple check and suggest a help string for the user when the command `--help` is used. Without this diff applied the server will panic and the user will not have any clue why. Running `target/debug/ldk-server --help` thread 'main' panicked at ldk-server/src/main.rs:30:56: Invalid configuration file.: Custom { kind: NotFound, error: "Failed to read config file '--help': No such file or directory (os error 2)" } note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace [1] 750067 IOT instruction (core dumped) cargo run --bin ldk-server -- --help Signed-off-by: Vincenzo Palazzo --- ldk-server/ldk-server/src/main.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 6d31341d9..5900b7c66 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -18,16 +18,29 @@ use ldk_node::config::Config; use std::path::Path; use std::sync::Arc; +const USAGE_GUIDE: &str = "Usage: ldk-server "; + fn main() { let args: Vec = std::env::args().collect(); if args.len() < 2 { - eprintln!("Usage: {} config_path", args[0]); + eprintln!("{USAGE_GUIDE}"); + std::process::exit(-1); + } + + let arg = args[1].as_str(); + if arg == "-h" || arg == "--help" { + println!("{}", USAGE_GUIDE); + std::process::exit(0); + } + + if fs::File::open(arg).is_err() { + eprintln!("Unable to access configuration file."); std::process::exit(-1); } let mut ldk_node_config = Config::default(); - let config_file = load_config(Path::new(&args[1])).expect("Invalid configuration file."); + let config_file = load_config(Path::new(arg)).expect("Invalid configuration file."); ldk_node_config.log_level = LogLevel::Trace; ldk_node_config.storage_dir_path = config_file.storage_dir_path; From dfa0e9649e2b6bdb0e8c1dac264376a1e9d74249 Mon Sep 17 00:00:00 2001 From: Vincenzo Palazzo Date: Tue, 10 Dec 2024 21:39:35 +0100 Subject: [PATCH 083/203] core: sanity check about the config file Signed-off-by: Vincenzo Palazzo --- ldk-server/ldk-server/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 5900b7c66..c4d0e8d86 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -15,6 +15,7 @@ use hyper_util::rt::TokioIo; use crate::util::config::load_config; use ldk_node::config::Config; +use std::fs; use std::path::Path; use std::sync::Arc; From 0c18c446902d5c21b32ad1f706399691c0792593 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:30:22 -0800 Subject: [PATCH 084/203] Create index on creation_time only if it doesn't exist. Since index creation will fail if index already exists. --- ldk-server/ldk-server/src/io/sqlite_store/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/io/sqlite_store/mod.rs b/ldk-server/ldk-server/src/io/sqlite_store/mod.rs index cee2baeca..e63f54f13 100644 --- a/ldk-server/ldk-server/src/io/sqlite_store/mod.rs +++ b/ldk-server/ldk-server/src/io/sqlite_store/mod.rs @@ -96,7 +96,7 @@ impl SqliteStore { })?; let index_creation_time_sql = format!( - "CREATE INDEX idx_creation_time ON {} (creation_time);", + "CREATE INDEX IF NOT EXISTS idx_creation_time ON {} (creation_time);", paginated_kv_table_name ); From b9fd98832d4b3aabbb2b9c4a9993701bffd7e333 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 6 Dec 2024 10:42:45 -0800 Subject: [PATCH 085/203] Move ldk-node dependency to github commit version. --- ldk-server/.github/workflows/build.yml | 1 - ldk-server/Cargo.lock | 52 ++++++------------- ldk-server/ldk-server/Cargo.toml | 4 +- ldk-server/ldk-server/src/api/onchain_send.rs | 3 +- 4 files changed, 19 insertions(+), 41 deletions(-) diff --git a/ldk-server/.github/workflows/build.yml b/ldk-server/.github/workflows/build.yml index 3c39bdb3b..44ba9db1a 100644 --- a/ldk-server/.github/workflows/build.yml +++ b/ldk-server/.github/workflows/build.yml @@ -34,7 +34,6 @@ jobs: - name: Pin packages to allow for MSRV if: matrix.msrv run: | - cargo update -p hashlink --precise "0.8.2" --verbose # hashlink 0.8.3 requires hashbrown 0.14, requiring 1.64.0 cargo update -p regex --precise "1.9.6" --verbose # regex 1.10.0 requires rustc 1.65.0 cargo update -p home --precise "0.5.5" --verbose # home v0.5.9 requires rustc 1.70 or newer cargo update -p tokio --precise "1.38.1" --verbose # tokio v1.39.0 requires rustc 1.70 or newer diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 507668c34..71226d6ca 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -253,12 +253,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" -[[package]] -name = "bitcoin-private" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" - [[package]] name = "bitcoin-units" version = "0.1.2" @@ -275,15 +269,6 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" -[[package]] -name = "bitcoin_hashes" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" -dependencies = [ - "bitcoin-private", -] - [[package]] name = "bitcoin_hashes" version = "0.14.0" @@ -447,9 +432,9 @@ dependencies = [ [[package]] name = "fallible-iterator" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fallible-streaming-iterator" @@ -621,26 +606,20 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash 0.8.11", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - [[package]] name = "hashlink" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0761a1b9491c4f2e3d66aa0f62d0fba0af9a0e2852e4d48ea506632a4b56e6aa" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ - "hashbrown 0.13.2", + "hashbrown 0.14.5", ] [[package]] @@ -900,9 +879,8 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "ldk-node" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50eff8ed03ff8847930eba51dc975fc12b10e96619cf9aabd9ab6f50db93ada" +version = "0.4.2" +source = "git+https://github.com/lightningdevkit/ldk-node.git?rev=2095d878be10923845bcdd1dd039ab0e670e723d#2095d878be10923845bcdd1dd039ab0e670e723d" dependencies = [ "base64 0.22.1", "bdk_chain", @@ -989,9 +967,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libsqlite3-sys" -version = "0.25.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" +checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" dependencies = [ "cc", "pkg-config", @@ -1488,11 +1466,11 @@ dependencies = [ [[package]] name = "rusqlite" -version = "0.28.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" +checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -1572,7 +1550,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ - "bitcoin_hashes 0.12.0", + "bitcoin_hashes 0.14.0", "rand", "secp256k1-sys", "serde", diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index ceebf1caa..88bb31603 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -ldk-node = { version = "0.4.0", default-features = false } +ldk-node = { git = "https://github.com/lightningdevkit/ldk-node.git", rev = "2095d878be10923845bcdd1dd039ab0e670e723d" } serde = { version = "1.0.203", default-features = false, features = ["derive"] } serde_json = { version = "1.0.118", default-features = false } hyper = { version = "1", default-features = false, features = ["server", "http1"] } @@ -15,7 +15,7 @@ prost = { version = "0.11.6", default-features = false, features = ["std"] } ldk-server-protos = { path = "../ldk-server-protos" } bytes = "1.4.0" hex = { package = "hex-conservative", version = "0.2.1", default-features = false } -rusqlite = { version = "0.28.0", features = ["bundled"] } +rusqlite = { version = "0.31.0", features = ["bundled"] } [dev-dependencies] rand = "0.8.5" diff --git a/ldk-server/ldk-server/src/api/onchain_send.rs b/ldk-server/ldk-server/src/api/onchain_send.rs index fd1ef5fb4..5ea58fabf 100644 --- a/ldk-server/ldk-server/src/api/onchain_send.rs +++ b/ldk-server/ldk-server/src/api/onchain_send.rs @@ -17,7 +17,8 @@ pub(crate) fn handle_onchain_send_request( (Some(amount_sats), None) => { node.onchain_payment().send_to_address(&address, amount_sats)? }, - (None, Some(true)) => node.onchain_payment().send_all_to_address(&address)?, + // Retain existing api behaviour to not retain reserves on `send_all_to_address`. + (None, Some(true)) => node.onchain_payment().send_all_to_address(&address, false)?, _ => return Err(ldk_node::NodeError::InvalidAmount), }; let response = OnchainSendResponse { txid: txid.to_string() }; From bab8e1b948b38b141dd9ec0c041a3d1d5728bbc6 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 6 Dec 2024 10:47:54 -0800 Subject: [PATCH 086/203] Add proto definition for ListForwardedPayments API. --- ldk-server/ldk-server-protos/src/api.rs | 38 +++++++++++++ .../ldk-server-protos/src/proto/api.proto | 34 ++++++++++++ .../ldk-server-protos/src/proto/types.proto | 51 +++++++++++++++++ ldk-server/ldk-server-protos/src/types.rs | 55 +++++++++++++++++++ 4 files changed, 178 insertions(+) diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index 673734de2..43172d9de 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -337,6 +337,44 @@ pub struct ListPaymentsResponse { #[prost(message, repeated, tag = "1")] pub payments: ::prost::alloc::vec::Vec, } +/// Retrieves list of all forwarded payments. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListForwardedPaymentsRequest { + /// `page_token` is a pagination token. + /// + /// To query for the first page, `page_token` must not be specified. + /// + /// For subsequent pages, use the value that was returned as `next_page_token` in the previous + /// page's response. + #[prost(message, optional, tag = "1")] + pub page_token: ::core::option::Option, +} +/// The response `content` for the `ListForwardedPayments` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListForwardedPaymentsResponse { + /// List of forwarded payments. + #[prost(message, repeated, tag = "1")] + pub forwarded_payments: ::prost::alloc::vec::Vec, + /// `next_page_token` is a pagination token, used to retrieve the next page of results. + /// Use this value to query for next-page of paginated operation, by specifying + /// this value as the `page_token` in the next request. + /// + /// If `next_page_token` is `None`, then the "last page" of results has been processed and + /// there is no more data to be retrieved. + /// + /// If `next_page_token` is not `None`, it does not necessarily mean that there is more data in the + /// result set. The only way to know when you have reached the end of the result set is when + /// `next_page_token` is `None`. + /// + /// **Caution**: Clients must not assume a specific number of records to be present in a page for + /// paginated response. + #[prost(message, optional, tag = "2")] + pub next_page_token: ::core::option::Option, +} /// Retrieves an overview of all known balances. /// See more: #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/ldk-server/ldk-server-protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto index e9a26ba70..69348a244 100644 --- a/ldk-server/ldk-server-protos/src/proto/api.proto +++ b/ldk-server/ldk-server-protos/src/proto/api.proto @@ -319,6 +319,40 @@ message ListPaymentsResponse { repeated types.Payment payments = 1; } +// Retrieves list of all forwarded payments. +// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.Event.html#variant.PaymentForwarded +message ListForwardedPaymentsRequest { + // `page_token` is a pagination token. + // + // To query for the first page, `page_token` must not be specified. + // + // For subsequent pages, use the value that was returned as `next_page_token` in the previous + // page's response. + optional types.PageToken page_token = 1; +} + +// The response `content` for the `ListForwardedPayments` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. +message ListForwardedPaymentsResponse { + // List of forwarded payments. + repeated types.ForwardedPayment forwarded_payments = 1; + + // `next_page_token` is a pagination token, used to retrieve the next page of results. + // Use this value to query for next-page of paginated operation, by specifying + // this value as the `page_token` in the next request. + // + // If `next_page_token` is `None`, then the "last page" of results has been processed and + // there is no more data to be retrieved. + // + // If `next_page_token` is not `None`, it does not necessarily mean that there is more data in the + // result set. The only way to know when you have reached the end of the result set is when + // `next_page_token` is `None`. + // + // **Caution**: Clients must not assume a specific number of records to be present in a page for + // paginated response. + optional types.PageToken next_page_token = 2; +} + // Retrieves an overview of all known balances. // See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_balances message GetBalancesRequest {} diff --git a/ldk-server/ldk-server-protos/src/proto/types.proto b/ldk-server/ldk-server-protos/src/proto/types.proto index cc7433b90..b2ccd573c 100644 --- a/ldk-server/ldk-server-protos/src/proto/types.proto +++ b/ldk-server/ldk-server-protos/src/proto/types.proto @@ -161,6 +161,51 @@ enum PaymentStatus { FAILED = 2; } +// A forwarded payment through our node. +// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.Event.html#variant.PaymentForwarded +message ForwardedPayment{ + // The channel id of the incoming channel between the previous node and us. + string prev_channel_id = 1; + + // The channel id of the outgoing channel between the next node and us. + string next_channel_id = 2; + + // The `user_channel_id` of the incoming channel between the previous node and us. + string prev_user_channel_id = 3; + + // The `user_channel_id` of the outgoing channel between the next node and us. + // This will be `None` if the payment was settled via an on-chain transaction. + // See the caveat described for the `total_fee_earned_msat` field. + optional string next_user_channel_id = 4; + + // The total fee, in milli-satoshis, which was earned as a result of the payment. + // + // Note that if we force-closed the channel over which we forwarded an HTLC while the HTLC was pending, the amount the + // next hop claimed will have been rounded down to the nearest whole satoshi. Thus, the fee calculated here may be + // higher than expected as we still claimed the full value in millisatoshis from the source. + // In this case, `claim_from_onchain_tx` will be set. + // + // If the channel which sent us the payment has been force-closed, we will claim the funds via an on-chain transaction. + // In that case we do not yet know the on-chain transaction fees which we will spend and will instead set this to `None`. + optional uint64 total_fee_earned_msat = 5; + + // The share of the total fee, in milli-satoshis, which was withheld in addition to the forwarding fee. + // This will only be set if we forwarded an intercepted HTLC with less than the expected amount. This means our + // counterparty accepted to receive less than the invoice amount. + // + // The caveat described above the `total_fee_earned_msat` field applies here as well. + optional uint64 skimmed_fee_msat = 6; + + // If this is true, the forwarded HTLC was claimed by our counterparty via an on-chain transaction. + bool claim_from_onchain_tx = 7; + + // The final amount forwarded, in milli-satoshis, after the fee is deducted. + // + // The caveat described above the `total_fee_earned_msat` field applies here as well. + optional uint64 outbound_amount_forwarded_msat = 8; + +} + message Channel { // The channel ID (prior to funding transaction generation, this is a random 32-byte // identifier, afterwards this is the transaction ID of the funding transaction XOR the @@ -579,3 +624,9 @@ message AwaitingThresholdConfirmations { // The amount, in satoshis, of the output being swept. uint64 amount_satoshis = 5; } + +// Token used to determine start of next page in paginated APIs. +message PageToken { + string token = 1; + int64 index = 2; +} diff --git a/ldk-server/ldk-server-protos/src/types.rs b/ldk-server/ldk-server-protos/src/types.rs index 82b7168f9..d7f8874c8 100644 --- a/ldk-server/ldk-server-protos/src/types.rs +++ b/ldk-server/ldk-server-protos/src/types.rs @@ -165,6 +165,52 @@ pub struct LspFeeLimits { #[prost(uint64, optional, tag = "2")] pub max_proportional_opening_fee_ppm_msat: ::core::option::Option, } +/// A forwarded payment through our node. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ForwardedPayment { + /// The channel id of the incoming channel between the previous node and us. + #[prost(string, tag = "1")] + pub prev_channel_id: ::prost::alloc::string::String, + /// The channel id of the outgoing channel between the next node and us. + #[prost(string, tag = "2")] + pub next_channel_id: ::prost::alloc::string::String, + /// The `user_channel_id` of the incoming channel between the previous node and us. + #[prost(string, tag = "3")] + pub prev_user_channel_id: ::prost::alloc::string::String, + /// The `user_channel_id` of the outgoing channel between the next node and us. + /// This will be `None` if the payment was settled via an on-chain transaction. + /// See the caveat described for the `total_fee_earned_msat` field. + #[prost(string, optional, tag = "4")] + pub next_user_channel_id: ::core::option::Option<::prost::alloc::string::String>, + /// The total fee, in milli-satoshis, which was earned as a result of the payment. + /// + /// Note that if we force-closed the channel over which we forwarded an HTLC while the HTLC was pending, the amount the + /// next hop claimed will have been rounded down to the nearest whole satoshi. Thus, the fee calculated here may be + /// higher than expected as we still claimed the full value in millisatoshis from the source. + /// In this case, `claim_from_onchain_tx` will be set. + /// + /// If the channel which sent us the payment has been force-closed, we will claim the funds via an on-chain transaction. + /// In that case we do not yet know the on-chain transaction fees which we will spend and will instead set this to `None`. + #[prost(uint64, optional, tag = "5")] + pub total_fee_earned_msat: ::core::option::Option, + /// The share of the total fee, in milli-satoshis, which was withheld in addition to the forwarding fee. + /// This will only be set if we forwarded an intercepted HTLC with less than the expected amount. This means our + /// counterparty accepted to receive less than the invoice amount. + /// + /// The caveat described above the `total_fee_earned_msat` field applies here as well. + #[prost(uint64, optional, tag = "6")] + pub skimmed_fee_msat: ::core::option::Option, + /// If this is true, the forwarded HTLC was claimed by our counterparty via an on-chain transaction. + #[prost(bool, tag = "7")] + pub claim_from_onchain_tx: bool, + /// The final amount forwarded, in milli-satoshis, after the fee is deducted. + /// + /// The caveat described above the `total_fee_earned_msat` field applies here as well. + #[prost(uint64, optional, tag = "8")] + pub outbound_amount_forwarded_msat: ::core::option::Option, +} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Channel { @@ -647,6 +693,15 @@ pub struct AwaitingThresholdConfirmations { #[prost(uint64, tag = "5")] pub amount_satoshis: u64, } +/// Token used to determine start of next page in paginated APIs. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PageToken { + #[prost(string, tag = "1")] + pub token: ::prost::alloc::string::String, + #[prost(int64, tag = "2")] + pub index: i64, +} /// Represents the direction of a payment. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] From 8629b82f3f35148b5a40dba38b777de23868ee33 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 6 Dec 2024 10:52:20 -0800 Subject: [PATCH 087/203] Start storing ForwardedPayments using PaginatedKVStore. --- ldk-server/ldk-server/Cargo.toml | 2 - ldk-server/ldk-server/src/io/mod.rs | 4 + ldk-server/ldk-server/src/main.rs | 80 ++++++++++++++++++- .../ldk-server/src/util/proto_adapter.rs | 23 +++++- 4 files changed, 101 insertions(+), 8 deletions(-) diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index 88bb31603..f7fd18eb1 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -16,6 +16,4 @@ ldk-server-protos = { path = "../ldk-server-protos" } bytes = "1.4.0" hex = { package = "hex-conservative", version = "0.2.1", default-features = false } rusqlite = { version = "0.31.0", features = ["bundled"] } - -[dev-dependencies] rand = "0.8.5" diff --git a/ldk-server/ldk-server/src/io/mod.rs b/ldk-server/ldk-server/src/io/mod.rs index 6cda7ce20..52975ac1a 100644 --- a/ldk-server/ldk-server/src/io/mod.rs +++ b/ldk-server/ldk-server/src/io/mod.rs @@ -1,3 +1,7 @@ pub(crate) mod paginated_kv_store; pub(crate) mod sqlite_store; pub(crate) mod utils; + +/// The forwarded payments will be persisted under this prefix. +pub(crate) const FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE: &str = "forwarded_payments"; +pub(crate) const FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE: &str = ""; diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index c4d0e8d86..1864441a9 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -13,11 +13,22 @@ use tokio::signal::unix::SignalKind; use hyper::server::conn::http1; use hyper_util::rt::TokioIo; +use crate::io::paginated_kv_store::PaginatedKVStore; +use crate::io::sqlite_store::SqliteStore; +use crate::io::{ + FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, + FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, +}; use crate::util::config::load_config; +use crate::util::proto_adapter::forwarded_payment_to_proto; +use hex::DisplayHex; use ldk_node::config::Config; +use prost::Message; +use rand::Rng; use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; const USAGE_GUIDE: &str = "Usage: ldk-server "; @@ -44,7 +55,7 @@ fn main() { let config_file = load_config(Path::new(arg)).expect("Invalid configuration file."); ldk_node_config.log_level = LogLevel::Trace; - ldk_node_config.storage_dir_path = config_file.storage_dir_path; + ldk_node_config.storage_dir_path = config_file.storage_dir_path.clone(); ldk_node_config.listening_addresses = Some(vec![config_file.listening_addr]); ldk_node_config.network = config_file.network; @@ -75,6 +86,15 @@ fn main() { }, }; + let paginated_store = + Arc::new(match SqliteStore::new(PathBuf::from(config_file.storage_dir_path), None, None) { + Ok(store) => store, + Err(e) => { + eprintln!("Failed to create SqliteStore: {:?}", e); + std::process::exit(-1); + }, + }); + println!("Starting up..."); match node.start_with_runtime(Arc::clone(&runtime)) { Ok(()) => {}, @@ -111,22 +131,74 @@ fn main() { "CHANNEL_PENDING: {} from counterparty {}", channel_id, counterparty_node_id ); + event_node.event_handled(); }, Event::ChannelReady { channel_id, counterparty_node_id, .. } => { println!( "CHANNEL_READY: {} from counterparty {:?}", channel_id, counterparty_node_id ); + event_node.event_handled(); }, Event::PaymentReceived { payment_id, payment_hash, amount_msat } => { println!( "PAYMENT_RECEIVED: with id {:?}, hash {}, amount_msat {}", payment_id, payment_hash, amount_msat ); + event_node.event_handled(); + }, + Event::PaymentForwarded { + prev_channel_id, + next_channel_id, + prev_user_channel_id, + next_user_channel_id, + total_fee_earned_msat, + skimmed_fee_msat, + claim_from_onchain_tx, + outbound_amount_forwarded_msat + } => { + + println!("PAYMENT_FORWARDED: with outbound_amount_forwarded_msat {}, total_fee_earned_msat: {}, inbound channel: {}, outbound channel: {}", + outbound_amount_forwarded_msat.unwrap_or(0), total_fee_earned_msat.unwrap_or(0), prev_channel_id, next_channel_id + ); + + let forwarded_payment = forwarded_payment_to_proto( + prev_channel_id, + next_channel_id, + prev_user_channel_id, + next_user_channel_id, + total_fee_earned_msat, + skimmed_fee_msat, + claim_from_onchain_tx, + outbound_amount_forwarded_msat + ); + + // We don't expose this payment-id to the user, it is a temporary measure to generate + // some unique identifiers until we have forwarded-payment-id available in ldk. + // Currently, this is the expected user handling behaviour for forwarded payments. + let mut forwarded_payment_id = [0u8;32]; + rand::thread_rng().fill(&mut forwarded_payment_id); + + let forwarded_payment_creation_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs() as i64; + + match paginated_store.write(FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE,FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, + &forwarded_payment_id.to_lower_hex_string(), + forwarded_payment_creation_time, + &forwarded_payment.encode_to_vec(), + ) { + Ok(_) => { + event_node.event_handled(); + } + Err(e) => { + println!("Failed to write forwarded payment to persistence: {}", e); + } + } + }, + _ => { + event_node.event_handled(); }, - _ => {}, } - event_node.event_handled(); + }, res = rest_svc_listener.accept() => { match res { diff --git a/ldk-server/ldk-server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs index 5d5b7d5a0..143a4d940 100644 --- a/ldk-server/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -1,8 +1,9 @@ use bytes::Bytes; use hex::prelude::*; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; +use ldk_node::lightning::ln::types::ChannelId; use ldk_node::payment::{PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus}; -use ldk_node::{ChannelDetails, LightningBalance, PendingSweepBalance}; +use ldk_node::{ChannelDetails, Event, LightningBalance, PendingSweepBalance, UserChannelId}; use ldk_server_protos::types::lightning_balance::BalanceType::{ ClaimableAwaitingConfirmations, ClaimableOnChannelClose, ContentiousClaimable, CounterpartyRevokedOutputClaimable, MaybePreimageClaimableHtlc, MaybeTimeoutClaimableHtlc, @@ -13,7 +14,7 @@ use ldk_server_protos::types::payment_kind::Kind::{ use ldk_server_protos::types::pending_sweep_balance::BalanceType::{ AwaitingThresholdConfirmations, BroadcastAwaitingConfirmation, PendingBroadcast, }; -use ldk_server_protos::types::{Channel, LspFeeLimits, OutPoint, Payment}; +use ldk_server_protos::types::{Channel, ForwardedPayment, LspFeeLimits, OutPoint, Payment}; pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { Channel { @@ -320,3 +321,21 @@ pub(crate) fn pending_sweep_balance_to_proto( }, } } + +pub(crate) fn forwarded_payment_to_proto( + prev_channel_id: ChannelId, next_channel_id: ChannelId, + prev_user_channel_id: Option, next_user_channel_id: Option, + total_fee_earned_msat: Option, skimmed_fee_msat: Option, claim_from_onchain_tx: bool, + outbound_amount_forwarded_msat: Option, +) -> ForwardedPayment { + ForwardedPayment { + prev_channel_id: prev_channel_id.to_string(), + next_channel_id: next_channel_id.to_string(), + prev_user_channel_id: prev_user_channel_id.expect("").0.to_string(), + next_user_channel_id: next_user_channel_id.map(|u| u.0.to_string()), + total_fee_earned_msat, + skimmed_fee_msat, + claim_from_onchain_tx, + outbound_amount_forwarded_msat, + } +} From 34e81a90b88b1bde4b93cf98098ca4064a4ff042 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 6 Dec 2024 11:14:18 -0800 Subject: [PATCH 088/203] Move Arc to Context. It will become easier to support multiple members in Context. In future commits, we will add PaginatedKvStore to Context. --- .../ldk-server/src/api/bolt11_receive.rs | 16 +++--- ldk-server/ldk-server/src/api/bolt11_send.rs | 11 ++-- .../ldk-server/src/api/bolt12_receive.rs | 10 ++-- ldk-server/ldk-server/src/api/bolt12_send.rs | 9 ++- .../ldk-server/src/api/close_channel.rs | 10 ++-- ldk-server/ldk-server/src/api/get_balances.rs | 7 +-- .../ldk-server/src/api/get_node_info.rs | 9 ++- .../ldk-server/src/api/get_payment_details.rs | 7 +-- .../ldk-server/src/api/list_channels.rs | 7 +-- .../ldk-server/src/api/list_payments.rs | 7 +-- .../ldk-server/src/api/onchain_receive.rs | 10 ++-- ldk-server/ldk-server/src/api/onchain_send.rs | 13 +++-- ldk-server/ldk-server/src/api/open_channel.rs | 9 ++- .../src/api/update_channel_config.rs | 24 ++++---- ldk-server/ldk-server/src/service.rs | 55 +++++++++++-------- 15 files changed, 108 insertions(+), 96 deletions(-) diff --git a/ldk-server/ldk-server/src/api/bolt11_receive.rs b/ldk-server/ldk-server/src/api/bolt11_receive.rs index ff2c03fca..0f11cd298 100644 --- a/ldk-server/ldk-server/src/api/bolt11_receive.rs +++ b/ldk-server/ldk-server/src/api/bolt11_receive.rs @@ -1,17 +1,19 @@ -use ldk_node::Node; +use crate::service::Context; use ldk_server_protos::api::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; -use std::sync::Arc; pub(crate) const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; pub(crate) fn handle_bolt11_receive_request( - node: Arc, request: Bolt11ReceiveRequest, + context: Context, request: Bolt11ReceiveRequest, ) -> Result { let invoice = match request.amount_msat { - Some(amount_msat) => { - node.bolt11_payment().receive(amount_msat, &request.description, request.expiry_secs)? - }, - None => node + Some(amount_msat) => context.node.bolt11_payment().receive( + amount_msat, + &request.description, + request.expiry_secs, + )?, + None => context + .node .bolt11_payment() .receive_variable_amount(&request.description, request.expiry_secs)?, }; diff --git a/ldk-server/ldk-server/src/api/bolt11_send.rs b/ldk-server/ldk-server/src/api/bolt11_send.rs index 8e12096c8..f73f0dbd2 100644 --- a/ldk-server/ldk-server/src/api/bolt11_send.rs +++ b/ldk-server/ldk-server/src/api/bolt11_send.rs @@ -1,21 +1,22 @@ +use crate::service::Context; use bytes::Bytes; use ldk_node::lightning_invoice::Bolt11Invoice; -use ldk_node::Node; use ldk_server_protos::api::{Bolt11SendRequest, Bolt11SendResponse}; use std::str::FromStr; -use std::sync::Arc; pub(crate) const BOLT11_SEND_PATH: &str = "Bolt11Send"; pub(crate) fn handle_bolt11_send_request( - node: Arc, request: Bolt11SendRequest, + context: Context, request: Bolt11SendRequest, ) -> Result { let invoice = Bolt11Invoice::from_str(&request.invoice.as_str()) .map_err(|_| ldk_node::NodeError::InvalidInvoice)?; let payment_id = match request.amount_msat { - None => node.bolt11_payment().send(&invoice, None), - Some(amount_msat) => node.bolt11_payment().send_using_amount(&invoice, amount_msat, None), + None => context.node.bolt11_payment().send(&invoice, None), + Some(amount_msat) => { + context.node.bolt11_payment().send_using_amount(&invoice, amount_msat, None) + }, }?; let response = Bolt11SendResponse { payment_id: Bytes::from(payment_id.0.to_vec()) }; diff --git a/ldk-server/ldk-server/src/api/bolt12_receive.rs b/ldk-server/ldk-server/src/api/bolt12_receive.rs index 8cac1b74e..25039876f 100644 --- a/ldk-server/ldk-server/src/api/bolt12_receive.rs +++ b/ldk-server/ldk-server/src/api/bolt12_receive.rs @@ -1,20 +1,20 @@ -use ldk_node::Node; +use crate::service::Context; use ldk_server_protos::api::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; -use std::sync::Arc; pub(crate) const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive"; pub(crate) fn handle_bolt12_receive_request( - node: Arc, request: Bolt12ReceiveRequest, + context: Context, request: Bolt12ReceiveRequest, ) -> Result { let offer = match request.amount_msat { - Some(amount_msat) => node.bolt12_payment().receive( + Some(amount_msat) => context.node.bolt12_payment().receive( amount_msat, &request.description, request.expiry_secs, request.quantity, )?, - None => node + None => context + .node .bolt12_payment() .receive_variable_amount(&request.description, request.expiry_secs)?, }; diff --git a/ldk-server/ldk-server/src/api/bolt12_send.rs b/ldk-server/ldk-server/src/api/bolt12_send.rs index ea0f85ce4..95f3a48db 100644 --- a/ldk-server/ldk-server/src/api/bolt12_send.rs +++ b/ldk-server/ldk-server/src/api/bolt12_send.rs @@ -1,21 +1,20 @@ +use crate::service::Context; use bytes::Bytes; use ldk_node::lightning::offers::offer::Offer; -use ldk_node::Node; use ldk_server_protos::api::{Bolt12SendRequest, Bolt12SendResponse}; use std::str::FromStr; -use std::sync::Arc; pub(crate) const BOLT12_SEND_PATH: &str = "Bolt12Send"; pub(crate) fn handle_bolt12_send_request( - node: Arc, request: Bolt12SendRequest, + context: Context, request: Bolt12SendRequest, ) -> Result { let offer = Offer::from_str(&request.offer.as_str()).map_err(|_| ldk_node::NodeError::InvalidOffer)?; let payment_id = match request.amount_msat { - None => node.bolt12_payment().send(&offer, request.quantity, request.payer_note), - Some(amount_msat) => node.bolt12_payment().send_using_amount( + None => context.node.bolt12_payment().send(&offer, request.quantity, request.payer_note), + Some(amount_msat) => context.node.bolt12_payment().send_using_amount( &offer, amount_msat, request.quantity, diff --git a/ldk-server/ldk-server/src/api/close_channel.rs b/ldk-server/ldk-server/src/api/close_channel.rs index d3735352c..b1892d76c 100644 --- a/ldk-server/ldk-server/src/api/close_channel.rs +++ b/ldk-server/ldk-server/src/api/close_channel.rs @@ -1,13 +1,13 @@ +use crate::service::Context; use ldk_node::bitcoin::secp256k1::PublicKey; -use ldk_node::{Node, UserChannelId}; +use ldk_node::UserChannelId; use ldk_server_protos::api::{CloseChannelRequest, CloseChannelResponse}; use std::str::FromStr; -use std::sync::Arc; pub(crate) const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; pub(crate) fn handle_close_channel_request( - node: Arc, request: CloseChannelRequest, + context: Context, request: CloseChannelRequest, ) -> Result { //TODO: Should this be string? let mut user_channel_id_bytes = [0u8; 16]; @@ -17,12 +17,12 @@ pub(crate) fn handle_close_channel_request( .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; match request.force_close { - Some(true) => node.force_close_channel( + Some(true) => context.node.force_close_channel( &user_channel_id, counterparty_node_id, request.force_close_reason, )?, - _ => node.close_channel(&user_channel_id, counterparty_node_id)?, + _ => context.node.close_channel(&user_channel_id, counterparty_node_id)?, }; let response = CloseChannelResponse {}; diff --git a/ldk-server/ldk-server/src/api/get_balances.rs b/ldk-server/ldk-server/src/api/get_balances.rs index 535aa5fca..e236976b5 100644 --- a/ldk-server/ldk-server/src/api/get_balances.rs +++ b/ldk-server/ldk-server/src/api/get_balances.rs @@ -1,14 +1,13 @@ +use crate::service::Context; use crate::util::proto_adapter::{lightning_balance_to_proto, pending_sweep_balance_to_proto}; -use ldk_node::Node; use ldk_server_protos::api::{GetBalancesRequest, GetBalancesResponse}; -use std::sync::Arc; pub(crate) const GET_BALANCES: &str = "GetBalances"; pub(crate) fn handle_get_balances_request( - node: Arc, _request: GetBalancesRequest, + context: Context, _request: GetBalancesRequest, ) -> Result { - let balance_details = node.list_balances(); + let balance_details = context.node.list_balances(); let response = GetBalancesResponse { total_onchain_balance_sats: balance_details.total_onchain_balance_sats, diff --git a/ldk-server/ldk-server/src/api/get_node_info.rs b/ldk-server/ldk-server/src/api/get_node_info.rs index ed612f801..59ace4598 100644 --- a/ldk-server/ldk-server/src/api/get_node_info.rs +++ b/ldk-server/ldk-server/src/api/get_node_info.rs @@ -1,14 +1,13 @@ -use ldk_node::Node; +use crate::service::Context; use ldk_server_protos::api::{GetNodeInfoRequest, GetNodeInfoResponse}; use ldk_server_protos::types::BestBlock; -use std::sync::Arc; pub(crate) const GET_NODE_INFO: &str = "GetNodeInfo"; pub(crate) fn handle_get_node_info_request( - node: Arc, _request: GetNodeInfoRequest, + context: Context, _request: GetNodeInfoRequest, ) -> Result { - let node_status = node.status(); + let node_status = context.node.status(); let best_block = BestBlock { block_hash: node_status.current_best_block.block_hash.to_string(), @@ -16,7 +15,7 @@ pub(crate) fn handle_get_node_info_request( }; let response = GetNodeInfoResponse { - node_id: node.node_id().to_string(), + node_id: context.node.node_id().to_string(), current_best_block: Some(best_block), latest_lightning_wallet_sync_timestamp: node_status.latest_lightning_wallet_sync_timestamp, latest_onchain_wallet_sync_timestamp: node_status.latest_onchain_wallet_sync_timestamp, diff --git a/ldk-server/ldk-server/src/api/get_payment_details.rs b/ldk-server/ldk-server/src/api/get_payment_details.rs index 6a43df2ad..620e7d0d5 100644 --- a/ldk-server/ldk-server/src/api/get_payment_details.rs +++ b/ldk-server/ldk-server/src/api/get_payment_details.rs @@ -1,19 +1,18 @@ +use crate::service::Context; use crate::util::proto_adapter::payment_to_proto; use hex::FromHex; use ldk_node::lightning::ln::channelmanager::PaymentId; -use ldk_node::Node; use ldk_server_protos::api::{GetPaymentDetailsRequest, GetPaymentDetailsResponse}; -use std::sync::Arc; pub(crate) const GET_PAYMENT_DETAILS_PATH: &str = "GetPaymentDetails"; pub(crate) fn handle_get_payment_details_request( - node: Arc, request: GetPaymentDetailsRequest, + context: Context, request: GetPaymentDetailsRequest, ) -> Result { let payment_id_bytes = <[u8; PaymentId::LENGTH]>::from_hex(&request.payment_id) .map_err(|_| ldk_node::NodeError::InvalidPaymentId)?; - let payment_details = node.payment(&PaymentId(payment_id_bytes)); + let payment_details = context.node.payment(&PaymentId(payment_id_bytes)); let response = GetPaymentDetailsResponse { payment: payment_details.map(|payment| payment_to_proto(payment)), diff --git a/ldk-server/ldk-server/src/api/list_channels.rs b/ldk-server/ldk-server/src/api/list_channels.rs index 318eb3801..d55f26ac5 100644 --- a/ldk-server/ldk-server/src/api/list_channels.rs +++ b/ldk-server/ldk-server/src/api/list_channels.rs @@ -1,14 +1,13 @@ +use crate::service::Context; use crate::util::proto_adapter::channel_to_proto; -use ldk_node::Node; use ldk_server_protos::api::{ListChannelsRequest, ListChannelsResponse}; -use std::sync::Arc; pub(crate) const LIST_CHANNELS_PATH: &str = "ListChannels"; pub(crate) fn handle_list_channels_request( - node: Arc, _request: ListChannelsRequest, + context: Context, _request: ListChannelsRequest, ) -> Result { - let channels = node.list_channels().into_iter().map(|c| channel_to_proto(c)).collect(); + let channels = context.node.list_channels().into_iter().map(|c| channel_to_proto(c)).collect(); let response = ListChannelsResponse { channels }; Ok(response) diff --git a/ldk-server/ldk-server/src/api/list_payments.rs b/ldk-server/ldk-server/src/api/list_payments.rs index 89da42d5e..04ef699e1 100644 --- a/ldk-server/ldk-server/src/api/list_payments.rs +++ b/ldk-server/ldk-server/src/api/list_payments.rs @@ -1,14 +1,13 @@ +use crate::service::Context; use crate::util::proto_adapter::payment_to_proto; -use ldk_node::Node; use ldk_server_protos::api::{ListPaymentsRequest, ListPaymentsResponse}; -use std::sync::Arc; pub(crate) const LIST_PAYMENTS_PATH: &str = "ListPayments"; pub(crate) fn handle_list_payments_request( - node: Arc, _request: ListPaymentsRequest, + context: Context, _request: ListPaymentsRequest, ) -> Result { - let payments = node.list_payments().into_iter().map(|p| payment_to_proto(p)).collect(); + let payments = context.node.list_payments().into_iter().map(|p| payment_to_proto(p)).collect(); let response = ListPaymentsResponse { payments }; Ok(response) diff --git a/ldk-server/ldk-server/src/api/onchain_receive.rs b/ldk-server/ldk-server/src/api/onchain_receive.rs index b7d767691..bfc9af6a6 100644 --- a/ldk-server/ldk-server/src/api/onchain_receive.rs +++ b/ldk-server/ldk-server/src/api/onchain_receive.rs @@ -1,12 +1,12 @@ -use ldk_node::Node; +use crate::service::Context; use ldk_server_protos::api::{OnchainReceiveRequest, OnchainReceiveResponse}; -use std::sync::Arc; pub(crate) const ONCHAIN_RECEIVE_PATH: &str = "OnchainReceive"; pub(crate) fn handle_onchain_receive_request( - node: Arc, _request: OnchainReceiveRequest, + context: Context, _request: OnchainReceiveRequest, ) -> Result { - let response = - OnchainReceiveResponse { address: node.onchain_payment().new_address()?.to_string() }; + let response = OnchainReceiveResponse { + address: context.node.onchain_payment().new_address()?.to_string(), + }; Ok(response) } diff --git a/ldk-server/ldk-server/src/api/onchain_send.rs b/ldk-server/ldk-server/src/api/onchain_send.rs index 5ea58fabf..35cd8488d 100644 --- a/ldk-server/ldk-server/src/api/onchain_send.rs +++ b/ldk-server/ldk-server/src/api/onchain_send.rs @@ -1,24 +1,25 @@ +use crate::service::Context; use ldk_node::bitcoin::Address; -use ldk_node::Node; use ldk_server_protos::api::{OnchainSendRequest, OnchainSendResponse}; use std::str::FromStr; -use std::sync::Arc; pub(crate) const ONCHAIN_SEND_PATH: &str = "OnchainSend"; pub(crate) fn handle_onchain_send_request( - node: Arc, request: OnchainSendRequest, + context: Context, request: OnchainSendRequest, ) -> Result { let address = Address::from_str(&request.address) .map_err(|_| ldk_node::NodeError::InvalidAddress)? - .require_network(node.config().network) + .require_network(context.node.config().network) .map_err(|_| ldk_node::NodeError::InvalidAddress)?; let txid = match (request.amount_sats, request.send_all) { (Some(amount_sats), None) => { - node.onchain_payment().send_to_address(&address, amount_sats)? + context.node.onchain_payment().send_to_address(&address, amount_sats)? }, // Retain existing api behaviour to not retain reserves on `send_all_to_address`. - (None, Some(true)) => node.onchain_payment().send_all_to_address(&address, false)?, + (None, Some(true)) => { + context.node.onchain_payment().send_all_to_address(&address, false)? + }, _ => return Err(ldk_node::NodeError::InvalidAmount), }; let response = OnchainSendResponse { txid: txid.to_string() }; diff --git a/ldk-server/ldk-server/src/api/open_channel.rs b/ldk-server/ldk-server/src/api/open_channel.rs index 927ea0b70..d7a002d33 100644 --- a/ldk-server/ldk-server/src/api/open_channel.rs +++ b/ldk-server/ldk-server/src/api/open_channel.rs @@ -1,15 +1,14 @@ +use crate::service::Context; use bytes::Bytes; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::lightning::ln::msgs::SocketAddress; -use ldk_node::Node; use ldk_server_protos::api::{OpenChannelRequest, OpenChannelResponse}; use std::str::FromStr; -use std::sync::Arc; pub(crate) const OPEN_CHANNEL_PATH: &str = "OpenChannel"; pub(crate) fn handle_open_channel( - node: Arc, request: OpenChannelRequest, + context: Context, request: OpenChannelRequest, ) -> Result { let node_id = PublicKey::from_str(&request.node_pubkey) .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; @@ -17,7 +16,7 @@ pub(crate) fn handle_open_channel( .map_err(|_| ldk_node::NodeError::InvalidSocketAddress)?; let user_channel_id = if request.announce_channel { - node.open_announced_channel( + context.node.open_announced_channel( node_id, address, request.channel_amount_sats, @@ -26,7 +25,7 @@ pub(crate) fn handle_open_channel( None, )? } else { - node.open_channel( + context.node.open_channel( node_id, address, request.channel_amount_sats, diff --git a/ldk-server/ldk-server/src/api/update_channel_config.rs b/ldk-server/ldk-server/src/api/update_channel_config.rs index 0d6c51037..c183ebbc6 100644 --- a/ldk-server/ldk-server/src/api/update_channel_config.rs +++ b/ldk-server/ldk-server/src/api/update_channel_config.rs @@ -1,21 +1,22 @@ +use crate::service::Context; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; -use ldk_node::{Node, UserChannelId}; +use ldk_node::UserChannelId; use ldk_server_protos::api::{UpdateChannelConfigRequest, UpdateChannelConfigResponse}; use ldk_server_protos::types::channel_config::MaxDustHtlcExposure; use std::str::FromStr; -use std::sync::Arc; pub(crate) const UPDATE_CHANNEL_CONFIG_PATH: &str = "UpdateChannelConfig"; pub(crate) fn handle_update_channel_config_request( - node: Arc, request: UpdateChannelConfigRequest, + context: Context, request: UpdateChannelConfigRequest, ) -> Result { let user_channel_id: u128 = request.user_channel_id.parse().map_err(|_| ldk_node::NodeError::InvalidChannelId)?; //FIXME: Use ldk/ldk-node's partial config update api. - let current_config = node + let current_config = context + .node .list_channels() .into_iter() .find(|c| c.user_channel_id.0 == user_channel_id) @@ -27,12 +28,15 @@ pub(crate) fn handle_update_channel_config_request( let counterparty_node_id = PublicKey::from_str(&request.counterparty_node_id) .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; - node.update_channel_config( - &UserChannelId(user_channel_id), - counterparty_node_id, - updated_channel_config, - ) - .map_err(ldk_node::NodeError::from)?; + + context + .node + .update_channel_config( + &UserChannelId(user_channel_id), + counterparty_node_id, + updated_channel_config, + ) + .map_err(ldk_node::NodeError::from)?; Ok(UpdateChannelConfigResponse {}) } diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index 1062cbc5a..0ae50229e 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -7,10 +7,6 @@ use hyper::{Request, Response, StatusCode}; use prost::Message; -use std::future::Future; -use std::pin::Pin; -use std::sync::Arc; - use crate::api::bolt11_receive::{handle_bolt11_receive_request, BOLT11_RECEIVE_PATH}; use crate::api::bolt11_send::{handle_bolt11_send_request, BOLT11_SEND_PATH}; use crate::api::bolt12_receive::{handle_bolt12_receive_request, BOLT12_RECEIVE_PATH}; @@ -29,6 +25,9 @@ use crate::api::open_channel::{handle_open_channel, OPEN_CHANNEL_PATH}; use crate::api::update_channel_config::{ handle_update_channel_config_request, UPDATE_CHANNEL_CONFIG_PATH, }; +use std::future::Future; +use std::pin::Pin; +use std::sync::Arc; #[derive(Clone)] pub struct NodeService { @@ -41,39 +40,51 @@ impl NodeService { } } +pub(crate) struct Context { + pub(crate) node: Arc, +} + impl Service> for NodeService { type Response = Response>; type Error = hyper::Error; type Future = Pin> + Send>>; fn call(&self, req: Request) -> Self::Future { - let node = Arc::clone(&self.node); + let context = Context { node: Arc::clone(&self.node) }; // Exclude '/' from path pattern matching. match &req.uri().path()[1..] { - GET_NODE_INFO => Box::pin(handle_request(node, req, handle_get_node_info_request)), - GET_BALANCES => Box::pin(handle_request(node, req, handle_get_balances_request)), + GET_NODE_INFO => Box::pin(handle_request(context, req, handle_get_node_info_request)), + GET_BALANCES => Box::pin(handle_request(context, req, handle_get_balances_request)), ONCHAIN_RECEIVE_PATH => { - Box::pin(handle_request(node, req, handle_onchain_receive_request)) + Box::pin(handle_request(context, req, handle_onchain_receive_request)) + }, + ONCHAIN_SEND_PATH => { + Box::pin(handle_request(context, req, handle_onchain_send_request)) }, - ONCHAIN_SEND_PATH => Box::pin(handle_request(node, req, handle_onchain_send_request)), BOLT11_RECEIVE_PATH => { - Box::pin(handle_request(node, req, handle_bolt11_receive_request)) + Box::pin(handle_request(context, req, handle_bolt11_receive_request)) }, - BOLT11_SEND_PATH => Box::pin(handle_request(node, req, handle_bolt11_send_request)), + BOLT11_SEND_PATH => Box::pin(handle_request(context, req, handle_bolt11_send_request)), BOLT12_RECEIVE_PATH => { - Box::pin(handle_request(node, req, handle_bolt12_receive_request)) + Box::pin(handle_request(context, req, handle_bolt12_receive_request)) + }, + BOLT12_SEND_PATH => Box::pin(handle_request(context, req, handle_bolt12_send_request)), + OPEN_CHANNEL_PATH => Box::pin(handle_request(context, req, handle_open_channel)), + CLOSE_CHANNEL_PATH => { + Box::pin(handle_request(context, req, handle_close_channel_request)) + }, + LIST_CHANNELS_PATH => { + Box::pin(handle_request(context, req, handle_list_channels_request)) }, - BOLT12_SEND_PATH => Box::pin(handle_request(node, req, handle_bolt12_send_request)), - OPEN_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_open_channel)), - CLOSE_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_close_channel_request)), - LIST_CHANNELS_PATH => Box::pin(handle_request(node, req, handle_list_channels_request)), UPDATE_CHANNEL_CONFIG_PATH => { - Box::pin(handle_request(node, req, handle_update_channel_config_request)) + Box::pin(handle_request(context, req, handle_update_channel_config_request)) }, GET_PAYMENT_DETAILS_PATH => { - Box::pin(handle_request(node, req, handle_get_payment_details_request)) + Box::pin(handle_request(context, req, handle_get_payment_details_request)) + }, + LIST_PAYMENTS_PATH => { + Box::pin(handle_request(context, req, handle_list_payments_request)) }, - LIST_PAYMENTS_PATH => Box::pin(handle_request(node, req, handle_list_payments_request)), path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async { @@ -91,14 +102,14 @@ impl Service> for NodeService { async fn handle_request< T: Message + Default, R: Message, - F: Fn(Arc, T) -> Result, + F: Fn(Context, T) -> Result, >( - node: Arc, request: Request, handler: F, + context: Context, request: Request, handler: F, ) -> Result<>>::Response, hyper::Error> { // TODO: we should bound the amount of data we read to avoid allocating too much memory. let bytes = request.into_body().collect().await?.to_bytes(); match T::decode(bytes) { - Ok(request) => match handler(node, request) { + Ok(request) => match handler(context, request) { Ok(response) => Ok(Response::builder() .body(Full::new(Bytes::from(response.encode_to_vec()))) // unwrap safety: body only errors when previous chained calls failed. From f2a792762eb86dbbb741fbfe7cd269d2527443eb Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 6 Dec 2024 11:33:35 -0800 Subject: [PATCH 089/203] Add Api impl for ListForwardedPayments. --- .../src/api/list_forwarded_payments.rs | 47 +++++++++++++++++++ ldk-server/ldk-server/src/api/mod.rs | 1 + ldk-server/ldk-server/src/main.rs | 2 +- ldk-server/ldk-server/src/service.rs | 20 ++++++-- 4 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 ldk-server/ldk-server/src/api/list_forwarded_payments.rs diff --git a/ldk-server/ldk-server/src/api/list_forwarded_payments.rs b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs new file mode 100644 index 000000000..3903f7ce7 --- /dev/null +++ b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs @@ -0,0 +1,47 @@ +use crate::io::{ + FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, + FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, +}; +use crate::service::Context; +use bytes::Bytes; +use ldk_server_protos::api::{ListForwardedPaymentsRequest, ListForwardedPaymentsResponse}; +use ldk_server_protos::types::{ForwardedPayment, PageToken}; +use prost::Message; + +pub(crate) const LIST_FORWARDED_PAYMENTS_PATH: &str = "ListForwardedPayments"; + +pub(crate) fn handle_list_forwarded_payments_request( + context: Context, request: ListForwardedPaymentsRequest, +) -> Result { + let page_token = request.page_token.map(|p| (p.token, p.index)); + let list_response = context + .paginated_kv_store + .list( + FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, + FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, + page_token, + ) + .map_err(|_| ldk_node::NodeError::ConnectionFailed)?; + + let mut forwarded_payments: Vec = vec![]; + for key in list_response.keys { + let forwarded_payment_bytes = context + .paginated_kv_store + .read( + FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, + FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, + &key, + ) + .map_err(|_| ldk_node::NodeError::ConnectionFailed)?; + let forwarded_payment = ForwardedPayment::decode(Bytes::from(forwarded_payment_bytes)) + .map_err(|_| ldk_node::NodeError::ConnectionFailed)?; + forwarded_payments.push(forwarded_payment); + } + let response = ListForwardedPaymentsResponse { + forwarded_payments, + next_page_token: list_response + .next_page_token + .map(|(token, index)| PageToken { token, index }), + }; + Ok(response) +} diff --git a/ldk-server/ldk-server/src/api/mod.rs b/ldk-server/ldk-server/src/api/mod.rs index 7d0770d7d..c1b0fa2ec 100644 --- a/ldk-server/ldk-server/src/api/mod.rs +++ b/ldk-server/ldk-server/src/api/mod.rs @@ -8,6 +8,7 @@ pub(crate) mod get_balances; pub(crate) mod get_node_info; pub(crate) mod get_payment_details; pub(crate) mod list_channels; +pub(crate) mod list_forwarded_payments; pub(crate) mod list_payments; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 1864441a9..4cdd219f8 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -204,7 +204,7 @@ fn main() { match res { Ok((stream, _)) => { let io_stream = TokioIo::new(stream); - let node_service = NodeService::new(Arc::clone(&node)); + let node_service = NodeService::new(Arc::clone(&node), Arc::clone(&paginated_store) as Arc); runtime.spawn(async move { if let Err(err) = http1::Builder::new().serve_connection(io_stream, node_service).await { eprintln!("Failed to serve connection: {}", err); diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index 0ae50229e..16ec58d92 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -18,6 +18,9 @@ use crate::api::get_payment_details::{ handle_get_payment_details_request, GET_PAYMENT_DETAILS_PATH, }; use crate::api::list_channels::{handle_list_channels_request, LIST_CHANNELS_PATH}; +use crate::api::list_forwarded_payments::{ + handle_list_forwarded_payments_request, LIST_FORWARDED_PAYMENTS_PATH, +}; use crate::api::list_payments::{handle_list_payments_request, LIST_PAYMENTS_PATH}; use crate::api::onchain_receive::{handle_onchain_receive_request, ONCHAIN_RECEIVE_PATH}; use crate::api::onchain_send::{handle_onchain_send_request, ONCHAIN_SEND_PATH}; @@ -25,6 +28,7 @@ use crate::api::open_channel::{handle_open_channel, OPEN_CHANNEL_PATH}; use crate::api::update_channel_config::{ handle_update_channel_config_request, UPDATE_CHANNEL_CONFIG_PATH, }; +use crate::io::paginated_kv_store::PaginatedKVStore; use std::future::Future; use std::pin::Pin; use std::sync::Arc; @@ -32,16 +36,20 @@ use std::sync::Arc; #[derive(Clone)] pub struct NodeService { node: Arc, + paginated_kv_store: Arc, } impl NodeService { - pub(crate) fn new(node: Arc) -> Self { - Self { node } + pub(crate) fn new( + node: Arc, paginated_kv_store: Arc, + ) -> Self { + Self { node, paginated_kv_store } } } pub(crate) struct Context { pub(crate) node: Arc, + pub(crate) paginated_kv_store: Arc, } impl Service> for NodeService { @@ -50,7 +58,10 @@ impl Service> for NodeService { type Future = Pin> + Send>>; fn call(&self, req: Request) -> Self::Future { - let context = Context { node: Arc::clone(&self.node) }; + let context = Context { + node: Arc::clone(&self.node), + paginated_kv_store: Arc::clone(&self.paginated_kv_store), + }; // Exclude '/' from path pattern matching. match &req.uri().path()[1..] { GET_NODE_INFO => Box::pin(handle_request(context, req, handle_get_node_info_request)), @@ -85,6 +96,9 @@ impl Service> for NodeService { LIST_PAYMENTS_PATH => { Box::pin(handle_request(context, req, handle_list_payments_request)) }, + LIST_FORWARDED_PAYMENTS_PATH => { + Box::pin(handle_request(context, req, handle_list_forwarded_payments_request)) + }, path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async { From 9f6ac77cdbd7eae467608f72ec1afc2d5d6e9c48 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 19 Feb 2025 15:57:24 -0800 Subject: [PATCH 090/203] Upgrade LDK Node version. --- ldk-server/ldk-server/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index f7fd18eb1..a7344684a 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -ldk-node = { git = "https://github.com/lightningdevkit/ldk-node.git", rev = "2095d878be10923845bcdd1dd039ab0e670e723d" } +ldk-node = { git = "https://github.com/lightningdevkit/ldk-node.git", rev = "6de350040e0fc5eb9cfcd15fad3919f5a79b82b9" } serde = { version = "1.0.203", default-features = false, features = ["derive"] } serde_json = { version = "1.0.118", default-features = false } hyper = { version = "1", default-features = false, features = ["server", "http1"] } From 3393e9d87f557f2bd224312dfe11d5bf86ad6f31 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 19 Feb 2025 15:57:42 -0800 Subject: [PATCH 091/203] Update Cargo.lock --- ldk-server/Cargo.lock | 1045 +++++++++++++++++++++++++++-------------- 1 file changed, 687 insertions(+), 358 deletions(-) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 71226d6ca..19d9aa728 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -4,24 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "ahash" -version = "0.4.8" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0453232ace82dee0dd0b4c87a59bd90f7b53b314f3e0f61fe2ee7c8a16482289" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" @@ -59,11 +53,17 @@ dependencies = [ "libc", ] +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "arrayvec" @@ -73,34 +73,34 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.98", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -109,7 +109,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" dependencies = [ - "bitcoin-internals", + "bitcoin-internals 0.3.0", "bitcoin_hashes 0.14.0", ] @@ -125,22 +125,11 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bdk-macros" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81c1980e50ae23bb6efa9283ae8679d6ea2c6fa6a99fe62533f65f4a25a1a56c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "bdk_chain" -version = "0.19.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e553c45ffed860aa7e0c6998c3a827fcdc039a2df76307563208ecfcae2f750" +checksum = "4955734f97b2baed3f36d16ae7c203fdde31ae85391ac44ee3cbcaf0886db5ce" dependencies = [ "bdk_core", "bitcoin", @@ -150,20 +139,20 @@ dependencies = [ [[package]] name = "bdk_core" -version = "0.2.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0b45300422611971b0bbe84b04d18e38e81a056a66860c9dd3434f6d0f5396" +checksum = "b545aea1efc090e4f71f1dd5468090d9f54c3de48002064c04895ef811fbe0b2" dependencies = [ "bitcoin", - "hashbrown 0.9.1", + "hashbrown 0.14.5", "serde", ] [[package]] name = "bdk_esplora" -version = "0.18.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cc9b320b2042e9729739eed66c6fc47b208554c8c6e393785cd56d257045e9f" +checksum = "3d7fdf5efbebabc0c0bb46c0348ef0d4db505856c7d6c5d50cebba1e5eda5fe4" dependencies = [ "async-trait", "bdk_core", @@ -173,9 +162,9 @@ dependencies = [ [[package]] name = "bdk_wallet" -version = "1.0.0-beta.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeb48cd8e0a15d0bf7351fc8c30e44c474be01f4f98eb29f20ab59b645bd29c" +checksum = "6a13c947be940d32a91b876fc5223a6d839a40bc219496c5c78af74714b1b3f7" dependencies = [ "bdk_chain", "bip39", @@ -186,12 +175,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - [[package]] name = "bech32" version = "0.11.0" @@ -210,34 +193,40 @@ dependencies = [ [[package]] name = "bip39" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" +checksum = "33415e24172c1b7d6066f6d999545375ab8e1d95421d6784bdfff9496f292387" dependencies = [ - "bitcoin_hashes 0.11.0", + "bitcoin_hashes 0.13.0", "serde", "unicode-normalization", ] [[package]] name = "bitcoin" -version = "0.32.3" +version = "0.32.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0032b0e8ead7074cda7fc4f034409607e3f03a6f71d66ade8a307f79b4d99e73" +checksum = "ce6bc65742dea50536e35ad42492b234c27904a27f0abdcbce605015cb4ea026" dependencies = [ "base58ck", "base64 0.21.7", - "bech32 0.11.0", - "bitcoin-internals", + "bech32", + "bitcoin-internals 0.3.0", "bitcoin-io", "bitcoin-units", "bitcoin_hashes 0.14.0", - "hex-conservative", + "hex-conservative 0.2.1", "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" @@ -249,9 +238,9 @@ dependencies = [ [[package]] name = "bitcoin-io" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" [[package]] name = "bitcoin-units" @@ -259,15 +248,19 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" dependencies = [ - "bitcoin-internals", + "bitcoin-internals 0.3.0", "serde", ] [[package]] name = "bitcoin_hashes" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals 0.2.0", + "hex-conservative 0.1.2", +] [[package]] name = "bitcoin_hashes" @@ -276,7 +269,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" dependencies = [ "bitcoin-io", - "hex-conservative", + "hex-conservative 0.2.1", "serde", ] @@ -288,27 +281,36 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" [[package]] name = "cc" -version = "1.1.5" +version = "1.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" +checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -318,9 +320,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -337,38 +339,42 @@ checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" [[package]] name = "clap" -version = "4.0.5" +version = "4.5.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5e0d0fdd7dc774d433c78c9de5695ca04724beaec6a7d4d13ac6014608f3eaf" +checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d" dependencies = [ - "bitflags 1.3.2", + "clap_builder", "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c" +dependencies = [ + "anstyle", "clap_lex", - "once_cell", "strsim", ] [[package]] name = "clap_derive" -version = "4.0.1" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca689d7434ce44517a12a89456b2be4d1ea1cafcd8f581978c03d45f5a5c12a7" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" dependencies = [ - "heck", - "proc-macro-error", + "heck 0.5.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.98", ] [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" -dependencies = [ - "os_str_bytes", -] +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "core-foundation" @@ -382,9 +388,26 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "dnssec-prover" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96487aad690d45a83f2b9876828ba856c5430bbb143cb5730d8a5d04a4805179" [[package]] name = "either" @@ -394,40 +417,41 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "esplora-client" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b546e91283ebfc56337de34e0cf814e3ad98083afde593b8e58495ee5355d0e" +checksum = "d0da3c186d286e046253ccdc4bb71aa87ef872e4eff2045947c0c4fe3d2b2efc" dependencies = [ "bitcoin", - "hex-conservative", + "hex-conservative 0.2.1", "log", "reqwest", "serde", + "tokio", ] [[package]] @@ -444,9 +468,9 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fixedbitset" @@ -471,9 +495,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -486,9 +510,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -496,15 +520,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -513,38 +537,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.98", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -566,14 +590,26 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", ] [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "h2" @@ -596,13 +632,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.9.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" -dependencies = [ - "ahash 0.4.8", - "serde", -] +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" [[package]] name = "hashbrown" @@ -610,9 +642,16 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash 0.8.11", + "ahash", + "serde", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "hashlink" version = "0.9.1" @@ -629,10 +668,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] -name = "hermit-abi" -version = "0.3.9" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex-conservative" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" [[package]] name = "hex-conservative" @@ -651,11 +696,11 @@ checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" [[package]] name = "home" -version = "0.5.5" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -671,9 +716,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -698,7 +743,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", ] [[package]] @@ -709,16 +754,16 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.9.4" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" [[package]] name = "httpdate" @@ -728,9 +773,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", @@ -752,14 +797,14 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "httparse", "httpdate", @@ -777,7 +822,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.32", "rustls", "tokio", "tokio-rustls", @@ -785,24 +830,24 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.6.0", "pin-project-lite", "tokio", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -821,31 +866,160 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] name = "indexmap" -version = "2.2.6" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.2", ] [[package]] name = "ipnet" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "itertools" @@ -858,16 +1032,17 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -879,8 +1054,8 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "ldk-node" -version = "0.4.2" -source = "git+https://github.com/lightningdevkit/ldk-node.git?rev=2095d878be10923845bcdd1dd039ab0e670e723d#2095d878be10923845bcdd1dd039ab0e670e723d" +version = "0.5.0+git" +source = "git+https://github.com/lightningdevkit/ldk-node.git?rev=6de350040e0fc5eb9cfcd15fad3919f5a79b82b9#6de350040e0fc5eb9cfcd15fad3919f5a79b82b9" dependencies = [ "base64 0.22.1", "bdk_chain", @@ -901,6 +1076,8 @@ dependencies = [ "lightning-persister", "lightning-rapid-gossip-sync", "lightning-transaction-sync", + "lightning-types", + "log", "prost", "rand", "reqwest", @@ -917,9 +1094,9 @@ name = "ldk-server" version = "0.1.0" dependencies = [ "bytes", - "hex-conservative", + "hex-conservative 0.2.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.6.0", "hyper-util", "ldk-node", "ldk-server-protos", @@ -961,9 +1138,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "libm" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libsqlite3-sys" @@ -978,32 +1161,38 @@ dependencies = [ [[package]] name = "lightning" -version = "0.0.125" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "767f388e50251da71f95a3737d6db32c9729f9de6427a54fa92bb994d04d793f" +checksum = "b3224b577def19c2bb3dcf2c35a95d94909183204c061746d1245ecc6e889e8e" dependencies = [ - "bech32 0.9.1", + "bech32", "bitcoin", + "dnssec-prover", + "hashbrown 0.13.2", + "libm", "lightning-invoice", "lightning-types", + "possiblyrandom", ] [[package]] name = "lightning-background-processor" -version = "0.0.125" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4734caab73611a2c725f15392565150e4f5a531dd1f239365d01311f7de65d2d" +checksum = "04231b97fd7509d73ce9857a416eb1477a55d076d4e22cbf26c649a772bde909" dependencies = [ "bitcoin", + "bitcoin-io", + "bitcoin_hashes 0.14.0", "lightning", "lightning-rapid-gossip-sync", ] [[package]] name = "lightning-block-sync" -version = "0.0.125" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea041135bad736b075ad1123ef0a4793e78da8041386aa7887779fc5c540b94b" +checksum = "baab5bdee174a2047d939a4ca0dc2e1c23caa0f8cab0b4380aed77a20e116f1e" dependencies = [ "bitcoin", "chunked_transfer", @@ -1014,11 +1203,11 @@ dependencies = [ [[package]] name = "lightning-invoice" -version = "0.32.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ab9f6ea77e20e3129235e62a2e6bd64ed932363df104e864ee65ccffb54a8f" +checksum = "d4254e7d05961a3728bc90737c522e7091735ba6f2f71014096d4b3eb4ee5d89" dependencies = [ - "bech32 0.9.1", + "bech32", "bitcoin", "lightning-types", "serde", @@ -1026,9 +1215,9 @@ dependencies = [ [[package]] name = "lightning-liquidity" -version = "0.1.0-alpha.6" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175cff5d30b8d3f94ae9772b59f9ca576b1927a6ab60dd773e8c4e0593cd4e95" +checksum = "bfbed71e656557185f25e006c1bcd8773c5c83387c727166666d3b0bce0f0ca5" dependencies = [ "bitcoin", "chrono", @@ -1039,11 +1228,22 @@ dependencies = [ "serde_json", ] +[[package]] +name = "lightning-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d44a6fb8c698180c758fd391ae9631be92a4dbf0a82121e7dd8b1a28d0cfa75" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "lightning-net-tokio" -version = "0.0.125" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af2847a19f892f32b9ab5075af25c70370b4cc5842b4f5b53c57092e52a49498" +checksum = "cb6a6c93b1e592f1d46bb24233cac4a33b4015c99488ee229927a81d16226e45" dependencies = [ "bitcoin", "lightning", @@ -1052,9 +1252,9 @@ dependencies = [ [[package]] name = "lightning-persister" -version = "0.0.125" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d06283d41eb8e6d4af883cd602d91ab0c5f9e0c9a6be1c944b10e6f47176f20" +checksum = "d80558dc398eb4609b1079044d8eb5760a58724627ff57c6d7c194c78906e026" dependencies = [ "bitcoin", "lightning", @@ -1063,49 +1263,55 @@ dependencies = [ [[package]] name = "lightning-rapid-gossip-sync" -version = "0.0.125" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92185313db1075495e5efa3dd6a3b5d4dee63e1496059f58cf65074994718f05" +checksum = "78dacdef3e2f5d727754f902f4e6bbc43bfc886fec8e71f36757711060916ebe" dependencies = [ "bitcoin", + "bitcoin-io", + "bitcoin_hashes 0.14.0", "lightning", ] [[package]] name = "lightning-transaction-sync" -version = "0.0.125" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f023cb8dcd9c8b83b9b0c673ed6ca2e9afb57791119d3fa3224db2787b717e" +checksum = "031493ff20f40c9bbf80dde70ca5bb5ce86f65d6fda939bfecb5a2d59dc54767" dependencies = [ - "bdk-macros", "bitcoin", "esplora-client", "futures", "lightning", + "lightning-macros", ] [[package]] name = "lightning-types" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1083b8d9137000edf3bfcb1ff011c0d25e0cdd2feb98cc21d6765e64a494148f" +checksum = "f2cd84d4e71472035903e43caded8ecc123066ce466329ccd5ae537a8d5488c7" dependencies = [ - "bech32 0.9.1", "bitcoin", - "hex-conservative", ] [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "litemap" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "memchr" @@ -1121,33 +1327,33 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniscript" -version = "12.2.0" +version = "12.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add2d4aee30e4291ce5cffa3a322e441ff4d4bc57b38c8d9bf0e94faa50ab626" +checksum = "5bd3c9608217b0d6fa9c9c8ddd875b85ab72bd4311cfc8db35e1b5a08fc11f4d" dependencies = [ - "bech32 0.11.0", + "bech32", "bitcoin", "serde", ] [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi", - "windows-sys 0.48.0", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", ] [[package]] @@ -1165,36 +1371,20 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" -version = "0.36.1" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "os_str_bytes" -version = "6.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "percent-encoding" @@ -1220,9 +1410,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -1232,55 +1422,43 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] -name = "prettyplease" -version = "0.1.25" +name = "possiblyrandom" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +checksum = "1b122a615d72104fb3d8b26523fdf9232cd8ee06949fb37e4ce3ff964d15dffd" dependencies = [ - "proc-macro2", - "syn 1.0.109", + "getrandom 0.2.15", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "ppv-lite86" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", + "zerocopy", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "prettyplease" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" dependencies = [ "proc-macro2", - "quote", - "version_check", + "syn 1.0.109", ] [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -1302,7 +1480,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" dependencies = [ "bytes", - "heck", + "heck 0.4.1", "itertools", "lazy_static", "log", @@ -1341,9 +1519,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -1375,14 +1553,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] name = "regex" -version = "1.9.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -1392,9 +1570,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.9" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1403,9 +1581,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" @@ -1421,7 +1599,7 @@ dependencies = [ "h2", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.32", "hyper-rustls", "ipnet", "js-sys", @@ -1451,15 +1629,14 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.8" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", - "spin", "untrusted", "windows-sys 0.52.0", ] @@ -1470,7 +1647,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -1486,15 +1663,15 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1528,11 +1705,17 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "sct" @@ -1567,29 +1750,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.98", ] [[package]] name = "serde_json" -version = "1.0.130" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "610f75ff4a8e3cb29b85da56eabdd1bff5b06739059a4b8e2967fef32e5d9944" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" dependencies = [ "itoa", "memchr", @@ -1609,6 +1792,12 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -1629,31 +1818,31 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] -name = "spin" -version = "0.9.8" +name = "stable_deref_trait" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" @@ -1668,9 +1857,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.71" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", @@ -1683,6 +1872,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -1706,41 +1906,53 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" dependencies = [ "cfg-if", "fastrand", + "getrandom 0.3.1", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.98", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", ] [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] @@ -1753,31 +1965,30 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.1" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.98", ] [[package]] @@ -1792,9 +2003,9 @@ dependencies = [ [[package]] name = "tokio-socks" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" +checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" dependencies = [ "either", "futures-util", @@ -1804,9 +2015,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -1817,15 +2028,15 @@ dependencies = [ [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-core", @@ -1833,9 +2044,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", ] @@ -1846,17 +2057,11 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" [[package]] name = "unicode-normalization" @@ -1875,15 +2080,27 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "vcpkg" version = "0.2.15" @@ -1892,9 +2109,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vss-client" @@ -1931,48 +2148,59 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", + "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.98", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1980,28 +2208,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.98", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -2074,6 +2305,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -2205,12 +2445,58 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.8.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -2222,5 +2508,48 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.98", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", ] From dd247cfad56c60db2fef35d9f8ac4db357f39e59 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 20 Feb 2025 11:52:14 -0800 Subject: [PATCH 092/203] Bump MSRV to 1.75.0 LDK Node MSRV has changed to 1.75.0, hence we update our MSRV as well. --- ldk-server/.github/workflows/build.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ldk-server/.github/workflows/build.yml b/ldk-server/.github/workflows/build.yml index 44ba9db1a..630435fbc 100644 --- a/ldk-server/.github/workflows/build.yml +++ b/ldk-server/.github/workflows/build.yml @@ -13,12 +13,12 @@ jobs: toolchain: [ stable, beta, - 1.63.0, # MSRV + 1.75.0, # MSRV ] include: - toolchain: stable check-fmt: true - - toolchain: 1.63.0 + - toolchain: 1.75.0 msrv: true runs-on: ${{ matrix.platform }} steps: @@ -34,9 +34,7 @@ jobs: - name: Pin packages to allow for MSRV if: matrix.msrv run: | - cargo update -p regex --precise "1.9.6" --verbose # regex 1.10.0 requires rustc 1.65.0 - cargo update -p home --precise "0.5.5" --verbose # home v0.5.9 requires rustc 1.70 or newer - cargo update -p tokio --precise "1.38.1" --verbose # tokio v1.39.0 requires rustc 1.70 or newer + cargo update -p home --precise "0.5.9" --verbose # home v0.5.11 requires rustc 1.81 or newer - name: Build on Rust ${{ matrix.toolchain }} run: cargo build --verbose --color always - name: Test on Rust ${{ matrix.toolchain }} From d3c0fa493c47862598b351aa2c0f71a6fad780e3 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 12 Feb 2025 14:32:48 -0800 Subject: [PATCH 093/203] Add prev_node_id and next_node_id in PaymentForwarded proto. In PaymentForwarded events, we now have access to prev_node_id and next_node_id. --- ldk-server/ldk-server-protos/src/proto/types.proto | 6 ++++++ ldk-server/ldk-server-protos/src/types.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/ldk-server/ldk-server-protos/src/proto/types.proto b/ldk-server/ldk-server-protos/src/proto/types.proto index b2ccd573c..87a8d0c4b 100644 --- a/ldk-server/ldk-server-protos/src/proto/types.proto +++ b/ldk-server/ldk-server-protos/src/proto/types.proto @@ -173,6 +173,12 @@ message ForwardedPayment{ // The `user_channel_id` of the incoming channel between the previous node and us. string prev_user_channel_id = 3; + // The node id of the previous node. + string prev_node_id = 9; + + // The node id of the next node. + string next_node_id = 10; + // The `user_channel_id` of the outgoing channel between the next node and us. // This will be `None` if the payment was settled via an on-chain transaction. // See the caveat described for the `total_fee_earned_msat` field. diff --git a/ldk-server/ldk-server-protos/src/types.rs b/ldk-server/ldk-server-protos/src/types.rs index d7f8874c8..f167fffc1 100644 --- a/ldk-server/ldk-server-protos/src/types.rs +++ b/ldk-server/ldk-server-protos/src/types.rs @@ -179,6 +179,12 @@ pub struct ForwardedPayment { /// The `user_channel_id` of the incoming channel between the previous node and us. #[prost(string, tag = "3")] pub prev_user_channel_id: ::prost::alloc::string::String, + /// The node id of the previous node. + #[prost(string, tag = "9")] + pub prev_node_id: ::prost::alloc::string::String, + /// The node id of the next node. + #[prost(string, tag = "10")] + pub next_node_id: ::prost::alloc::string::String, /// The `user_channel_id` of the outgoing channel between the next node and us. /// This will be `None` if the payment was settled via an on-chain transaction. /// See the caveat described for the `total_fee_earned_msat` field. From 2afc5cbeaf67e59586d12076ac92f7527a56e938 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 12 Feb 2025 14:40:22 -0800 Subject: [PATCH 094/203] Start storing prev_node_id and next_node_id for PaymentForwardedEvents. In PaymentForwarded events, we now have access to prev_node_id and next_node_id. --- ldk-server/ldk-server/src/main.rs | 4 ++++ ldk-server/ldk-server/src/util/proto_adapter.rs | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 4cdd219f8..d59c9180d 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -152,6 +152,8 @@ fn main() { next_channel_id, prev_user_channel_id, next_user_channel_id, + prev_node_id, + next_node_id, total_fee_earned_msat, skimmed_fee_msat, claim_from_onchain_tx, @@ -167,6 +169,8 @@ fn main() { next_channel_id, prev_user_channel_id, next_user_channel_id, + prev_node_id, + next_node_id, total_fee_earned_msat, skimmed_fee_msat, claim_from_onchain_tx, diff --git a/ldk-server/ldk-server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs index 143a4d940..cd5d828f2 100644 --- a/ldk-server/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -1,5 +1,6 @@ use bytes::Bytes; use hex::prelude::*; +use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; use ldk_node::lightning::ln::types::ChannelId; use ldk_node::payment::{PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus}; @@ -325,14 +326,20 @@ pub(crate) fn pending_sweep_balance_to_proto( pub(crate) fn forwarded_payment_to_proto( prev_channel_id: ChannelId, next_channel_id: ChannelId, prev_user_channel_id: Option, next_user_channel_id: Option, + prev_node_id: Option, next_node_id: Option, total_fee_earned_msat: Option, skimmed_fee_msat: Option, claim_from_onchain_tx: bool, outbound_amount_forwarded_msat: Option, ) -> ForwardedPayment { ForwardedPayment { prev_channel_id: prev_channel_id.to_string(), next_channel_id: next_channel_id.to_string(), - prev_user_channel_id: prev_user_channel_id.expect("").0.to_string(), + prev_user_channel_id: prev_user_channel_id + .expect("prev_user_channel_id expected for ldk-server >=0.1") + .0 + .to_string(), next_user_channel_id: next_user_channel_id.map(|u| u.0.to_string()), + prev_node_id: prev_node_id.expect("prev_node_id expected for ldk-server >=0.1").to_string(), + next_node_id: next_node_id.expect("next_node_id expected for ldk-node >=0.1").to_string(), total_fee_earned_msat, skimmed_fee_msat, claim_from_onchain_tx, From 31af8990e08663caf768358ef9a5c5fe42fcc66e Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 20 Feb 2025 15:15:41 -0800 Subject: [PATCH 095/203] Ignore new fields for PaymentReceived event. Since they are not required for existing logging. --- ldk-server/ldk-server/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index d59c9180d..3a91261d1 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -140,7 +140,7 @@ fn main() { ); event_node.event_handled(); }, - Event::PaymentReceived { payment_id, payment_hash, amount_msat } => { + Event::PaymentReceived { payment_id, payment_hash, amount_msat, .. } => { println!( "PAYMENT_RECEIVED: with id {:?}, hash {}, amount_msat {}", payment_id, payment_hash, amount_msat From e1291a51848d1b6409677f644521ac18fc0fb2d3 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 13 Feb 2025 16:04:20 -0800 Subject: [PATCH 096/203] Account for Bolt11InvoiceDescription. Bolt11 Send API now supports setting description_hash instead of description, account for this api change in ldk. --- ldk-server/ldk-server-cli/src/main.rs | 65 +++++++++++++------ ldk-server/ldk-server-protos/src/api.rs | 4 +- .../ldk-server-protos/src/proto/api.proto | 2 +- .../ldk-server-protos/src/proto/types.proto | 7 ++ ldk-server/ldk-server-protos/src/types.rs | 17 +++++ .../ldk-server/src/api/bolt11_receive.rs | 12 ++-- .../ldk-server/src/util/proto_adapter.rs | 23 ++++++- 7 files changed, 99 insertions(+), 31 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 140df2387..a2899b2cc 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -6,6 +6,9 @@ use ldk_server_client::ldk_server_protos::api::{ GetBalancesRequest, GetNodeInfoRequest, ListChannelsRequest, ListPaymentsRequest, OnchainReceiveRequest, OnchainSendRequest, OpenChannelRequest, }; +use ldk_server_client::ldk_server_protos::types::{ + bolt11_invoice_description, Bolt11InvoiceDescription, +}; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -32,7 +35,9 @@ enum Commands { }, Bolt11Receive { #[arg(short, long)] - description: String, + description: Option, + #[arg(short, long)] + description_hash: Option, #[arg(short, long)] expiry_secs: u32, #[arg(long)] @@ -87,31 +92,47 @@ async fn main() { match cli.command { Commands::GetNodeInfo => { - handle_response(client.get_node_info(GetNodeInfoRequest {}).await); + handle_response_result(client.get_node_info(GetNodeInfoRequest {}).await); }, Commands::GetBalances => { - handle_response(client.get_balances(GetBalancesRequest {}).await); + handle_response_result(client.get_balances(GetBalancesRequest {}).await); }, Commands::OnchainReceive => { - handle_response(client.onchain_receive(OnchainReceiveRequest {}).await); + handle_response_result(client.onchain_receive(OnchainReceiveRequest {}).await); }, Commands::OnchainSend { address, amount_sats, send_all } => { - handle_response( + handle_response_result( client.onchain_send(OnchainSendRequest { address, amount_sats, send_all }).await, ); }, - Commands::Bolt11Receive { description, expiry_secs, amount_msat } => { - handle_response( - client - .bolt11_receive(Bolt11ReceiveRequest { description, expiry_secs, amount_msat }) - .await, - ); + Commands::Bolt11Receive { description, description_hash, expiry_secs, amount_msat } => { + let invoice_description = match (description, description_hash) { + (Some(desc), None) => Some(Bolt11InvoiceDescription { + kind: Some(bolt11_invoice_description::Kind::Direct(desc)), + }), + (None, Some(hash)) => Some(Bolt11InvoiceDescription { + kind: Some(bolt11_invoice_description::Kind::Hash(hash)), + }), + (Some(_), Some(_)) => { + handle_error(LdkServerError::InternalError( + "Only one of description or description_hash can be set.".to_string(), + )); + }, + (None, None) => None, + }; + + let request = + Bolt11ReceiveRequest { description: invoice_description, expiry_secs, amount_msat }; + + handle_response_result(client.bolt11_receive(request).await); }, Commands::Bolt11Send { invoice, amount_msat } => { - handle_response(client.bolt11_send(Bolt11SendRequest { invoice, amount_msat }).await); + handle_response_result( + client.bolt11_send(Bolt11SendRequest { invoice, amount_msat }).await, + ); }, Commands::Bolt12Receive { description, amount_msat, expiry_secs, quantity } => { - handle_response( + handle_response_result( client .bolt12_receive(Bolt12ReceiveRequest { description, @@ -123,7 +144,7 @@ async fn main() { ); }, Commands::Bolt12Send { offer, amount_msat, quantity, payer_note } => { - handle_response( + handle_response_result( client .bolt12_send(Bolt12SendRequest { offer, amount_msat, quantity, payer_note }) .await, @@ -136,7 +157,7 @@ async fn main() { push_to_counterparty_msat, announce_channel, } => { - handle_response( + handle_response_result( client .open_channel(OpenChannelRequest { node_pubkey, @@ -150,22 +171,26 @@ async fn main() { ); }, Commands::ListChannels => { - handle_response(client.list_channels(ListChannelsRequest {}).await); + handle_response_result(client.list_channels(ListChannelsRequest {}).await); }, Commands::ListPayments => { - handle_response(client.list_payments(ListPaymentsRequest {}).await); + handle_response_result(client.list_payments(ListPaymentsRequest {}).await); }, } } -fn handle_response(response: Result) { +fn handle_response_result(response: Result) { match response { Ok(response) => { println!("{:?}", response); }, Err(e) => { - eprintln!("Error executing command: {:?}", e); - std::process::exit(1); // Exit with status code 1 on error. + handle_error(e); }, }; } + +fn handle_error(e: LdkServerError) -> ! { + eprintln!("Error executing command: {:?}", e); + std::process::exit(1); // Exit with status code 1 on error. +} diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index 43172d9de..66bda1880 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -107,8 +107,8 @@ pub struct Bolt11ReceiveRequest { pub amount_msat: ::core::option::Option, /// An optional description to attach along with the invoice. /// Will be set in the description field of the encoded payment request. - #[prost(string, tag = "2")] - pub description: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub description: ::core::option::Option, /// Invoice expiry time in seconds. #[prost(uint32, tag = "3")] pub expiry_secs: u32, diff --git a/ldk-server/ldk-server-protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto index 69348a244..9d1f757d6 100644 --- a/ldk-server/ldk-server-protos/src/proto/api.proto +++ b/ldk-server/ldk-server-protos/src/proto/api.proto @@ -107,7 +107,7 @@ message Bolt11ReceiveRequest { // An optional description to attach along with the invoice. // Will be set in the description field of the encoded payment request. - string description = 2; + types.Bolt11InvoiceDescription description = 2; // Invoice expiry time in seconds. uint32 expiry_secs = 3; diff --git a/ldk-server/ldk-server-protos/src/proto/types.proto b/ldk-server/ldk-server-protos/src/proto/types.proto index 87a8d0c4b..adad13d0b 100644 --- a/ldk-server/ldk-server-protos/src/proto/types.proto +++ b/ldk-server/ldk-server-protos/src/proto/types.proto @@ -636,3 +636,10 @@ message PageToken { string token = 1; int64 index = 2; } + +message Bolt11InvoiceDescription { + oneof kind { + string direct = 1; + string hash = 2; + } +} diff --git a/ldk-server/ldk-server-protos/src/types.rs b/ldk-server/ldk-server-protos/src/types.rs index f167fffc1..e5183c90b 100644 --- a/ldk-server/ldk-server-protos/src/types.rs +++ b/ldk-server/ldk-server-protos/src/types.rs @@ -708,6 +708,23 @@ pub struct PageToken { #[prost(int64, tag = "2")] pub index: i64, } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11InvoiceDescription { + #[prost(oneof = "bolt11_invoice_description::Kind", tags = "1, 2")] + pub kind: ::core::option::Option, +} +/// Nested message and enum types in `Bolt11InvoiceDescription`. +pub mod bolt11_invoice_description { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Kind { + #[prost(string, tag = "1")] + Direct(::prost::alloc::string::String), + #[prost(string, tag = "2")] + Hash(::prost::alloc::string::String), + } +} /// Represents the direction of a payment. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] diff --git a/ldk-server/ldk-server/src/api/bolt11_receive.rs b/ldk-server/ldk-server/src/api/bolt11_receive.rs index 0f11cd298..f6bab7fb5 100644 --- a/ldk-server/ldk-server/src/api/bolt11_receive.rs +++ b/ldk-server/ldk-server/src/api/bolt11_receive.rs @@ -1,4 +1,5 @@ use crate::service::Context; +use crate::util::proto_adapter::proto_to_bolt11_description; use ldk_server_protos::api::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; pub(crate) const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; @@ -6,16 +7,15 @@ pub(crate) const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; pub(crate) fn handle_bolt11_receive_request( context: Context, request: Bolt11ReceiveRequest, ) -> Result { + let description = proto_to_bolt11_description(request.description)?; let invoice = match request.amount_msat { - Some(amount_msat) => context.node.bolt11_payment().receive( - amount_msat, - &request.description, - request.expiry_secs, - )?, + Some(amount_msat) => { + context.node.bolt11_payment().receive(amount_msat, &description, request.expiry_secs)? + }, None => context .node .bolt11_payment() - .receive_variable_amount(&request.description, request.expiry_secs)?, + .receive_variable_amount(&description, request.expiry_secs)?, }; let response = Bolt11ReceiveResponse { invoice: invoice.to_string() }; diff --git a/ldk-server/ldk-server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs index cd5d828f2..039249615 100644 --- a/ldk-server/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -1,10 +1,12 @@ use bytes::Bytes; use hex::prelude::*; +use ldk_node::bitcoin::hashes::sha256; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; use ldk_node::lightning::ln::types::ChannelId; +use ldk_node::lightning_invoice::{Bolt11InvoiceDescription, Description, Sha256}; use ldk_node::payment::{PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus}; -use ldk_node::{ChannelDetails, Event, LightningBalance, PendingSweepBalance, UserChannelId}; +use ldk_node::{ChannelDetails, LightningBalance, NodeError, PendingSweepBalance, UserChannelId}; use ldk_server_protos::types::lightning_balance::BalanceType::{ ClaimableAwaitingConfirmations, ClaimableOnChannelClose, ContentiousClaimable, CounterpartyRevokedOutputClaimable, MaybePreimageClaimableHtlc, MaybeTimeoutClaimableHtlc, @@ -15,7 +17,9 @@ use ldk_server_protos::types::payment_kind::Kind::{ use ldk_server_protos::types::pending_sweep_balance::BalanceType::{ AwaitingThresholdConfirmations, BroadcastAwaitingConfirmation, PendingBroadcast, }; -use ldk_server_protos::types::{Channel, ForwardedPayment, LspFeeLimits, OutPoint, Payment}; +use ldk_server_protos::types::{ + bolt11_invoice_description, Channel, ForwardedPayment, LspFeeLimits, OutPoint, Payment, +}; pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { Channel { @@ -346,3 +350,18 @@ pub(crate) fn forwarded_payment_to_proto( outbound_amount_forwarded_msat, } } + +pub(crate) fn proto_to_bolt11_description( + description: Option, +) -> Result { + Ok(match description.and_then(|d| d.kind) { + Some(bolt11_invoice_description::Kind::Direct(s)) => { + Bolt11InvoiceDescription::Direct(Description::new(s).unwrap()) + }, + Some(bolt11_invoice_description::Kind::Hash(h)) => { + let hash_bytes = <[u8; 32]>::from_hex(&h).map_err(|_| NodeError::InvalidInvoice)?; + Bolt11InvoiceDescription::Hash(Sha256(*sha256::Hash::from_bytes_ref(&hash_bytes))) + }, + None => Bolt11InvoiceDescription::Direct(Description::new("".to_string()).unwrap()), + }) +} From c1fb517745d20c9c3999fac377af5ebd40bdfcb3 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:02:23 -0800 Subject: [PATCH 097/203] Account for FeeRate in OnchainSend. Onchain sends now support setting a custom fee-rate, account for this api change in ldk. --- ldk-server/ldk-server-cli/src/main.rs | 13 +++++++++++-- ldk-server/ldk-server-protos/src/api.rs | 4 ++++ ldk-server/ldk-server-protos/src/proto/api.proto | 4 ++++ ldk-server/ldk-server/src/api/onchain_send.rs | 8 +++++--- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index a2899b2cc..9f17b1ace 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -32,6 +32,8 @@ enum Commands { amount_sats: Option, #[arg(long)] send_all: Option, + #[arg(long)] + fee_rate_sat_per_vb: Option, }, Bolt11Receive { #[arg(short, long)] @@ -100,9 +102,16 @@ async fn main() { Commands::OnchainReceive => { handle_response_result(client.onchain_receive(OnchainReceiveRequest {}).await); }, - Commands::OnchainSend { address, amount_sats, send_all } => { + Commands::OnchainSend { address, amount_sats, send_all, fee_rate_sat_per_vb } => { handle_response_result( - client.onchain_send(OnchainSendRequest { address, amount_sats, send_all }).await, + client + .onchain_send(OnchainSendRequest { + address, + amount_sats, + send_all, + fee_rate_sat_per_vb, + }) + .await, ); }, Commands::Bolt11Receive { description, description_hash, expiry_secs, amount_msat } => { diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index 66bda1880..8f2a0c451 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -83,6 +83,10 @@ pub struct OnchainSendRequest { /// See more: #[prost(bool, optional, tag = "3")] pub send_all: ::core::option::Option, + /// If `fee_rate_sat_per_vb` is set it will be used on the resulting transaction. Otherwise we'll retrieve + /// a reasonable estimate from BitcoinD. + #[prost(uint64, optional, tag = "4")] + pub fee_rate_sat_per_vb: ::core::option::Option, } /// The response `content` for the `OnchainSend` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. diff --git a/ldk-server/ldk-server-protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto index 9d1f757d6..30aa70299 100644 --- a/ldk-server/ldk-server-protos/src/proto/api.proto +++ b/ldk-server/ldk-server-protos/src/proto/api.proto @@ -84,6 +84,10 @@ message OnchainSendRequest { // the counterparty to spend the Anchor output after channel closure. // See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.send_all_to_address optional bool send_all = 3; + + // If `fee_rate_sat_per_vb` is set it will be used on the resulting transaction. Otherwise we'll retrieve + // a reasonable estimate from BitcoinD. + optional uint64 fee_rate_sat_per_vb = 4; } // The response `content` for the `OnchainSend` API, when HttpStatusCode is OK (200). diff --git a/ldk-server/ldk-server/src/api/onchain_send.rs b/ldk-server/ldk-server/src/api/onchain_send.rs index 35cd8488d..a3af974bc 100644 --- a/ldk-server/ldk-server/src/api/onchain_send.rs +++ b/ldk-server/ldk-server/src/api/onchain_send.rs @@ -1,5 +1,5 @@ use crate::service::Context; -use ldk_node::bitcoin::Address; +use ldk_node::bitcoin::{Address, FeeRate}; use ldk_server_protos::api::{OnchainSendRequest, OnchainSendResponse}; use std::str::FromStr; @@ -12,13 +12,15 @@ pub(crate) fn handle_onchain_send_request( .map_err(|_| ldk_node::NodeError::InvalidAddress)? .require_network(context.node.config().network) .map_err(|_| ldk_node::NodeError::InvalidAddress)?; + + let fee_rate = request.fee_rate_sat_per_vb.map(FeeRate::from_sat_per_vb).flatten(); let txid = match (request.amount_sats, request.send_all) { (Some(amount_sats), None) => { - context.node.onchain_payment().send_to_address(&address, amount_sats)? + context.node.onchain_payment().send_to_address(&address, amount_sats, fee_rate)? }, // Retain existing api behaviour to not retain reserves on `send_all_to_address`. (None, Some(true)) => { - context.node.onchain_payment().send_all_to_address(&address, false)? + context.node.onchain_payment().send_all_to_address(&address, false, fee_rate)? }, _ => return Err(ldk_node::NodeError::InvalidAmount), }; From 7afeef89b4ef17fec1c3d90fa2646e75fb6cfe0c Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 19 Feb 2025 13:09:50 -0800 Subject: [PATCH 098/203] Configure logging using new LDK Node api. LDK Node now supports logging through log facade and there are minor associated api changes. --- ldk-server/ldk-server/src/main.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 3a91261d1..20c138528 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -5,7 +5,7 @@ mod util; use crate::service::NodeService; -use ldk_node::{Builder, Event, LogLevel}; +use ldk_node::{Builder, Event}; use tokio::net::TcpListener; use tokio::signal::unix::SignalKind; @@ -23,6 +23,7 @@ use crate::util::config::load_config; use crate::util::proto_adapter::forwarded_payment_to_proto; use hex::DisplayHex; use ldk_node::config::Config; +use ldk_node::logger::LogLevel; use prost::Message; use rand::Rng; use std::fs; @@ -54,12 +55,12 @@ fn main() { let mut ldk_node_config = Config::default(); let config_file = load_config(Path::new(arg)).expect("Invalid configuration file."); - ldk_node_config.log_level = LogLevel::Trace; ldk_node_config.storage_dir_path = config_file.storage_dir_path.clone(); ldk_node_config.listening_addresses = Some(vec![config_file.listening_addr]); ldk_node_config.network = config_file.network; let mut builder = Builder::from_config(ldk_node_config); + builder.set_log_facade_logger(Some(LogLevel::Trace)); let bitcoind_rpc_addr = config_file.bitcoind_rpc_addr; From 91b1e8548c4eba65a13f175fb4b38d00e0b33321 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 19 Feb 2025 15:43:52 -0800 Subject: [PATCH 099/203] Expose txid and confirmation_status for onchain payments. Onchain payments now provide additional information such as transaction_id and confirmation_status. --- .../ldk-server-protos/src/proto/types.proto | 30 ++++++++++++- ldk-server/ldk-server-protos/src/types.rs | 44 ++++++++++++++++++- .../ldk-server/src/util/proto_adapter.rs | 31 +++++++++++-- 3 files changed, 100 insertions(+), 5 deletions(-) diff --git a/ldk-server/ldk-server-protos/src/proto/types.proto b/ldk-server/ldk-server-protos/src/proto/types.proto index adad13d0b..fef697492 100644 --- a/ldk-server/ldk-server-protos/src/proto/types.proto +++ b/ldk-server/ldk-server-protos/src/proto/types.proto @@ -35,7 +35,35 @@ message PaymentKind { } // Represents an on-chain payment. -message Onchain {} +message Onchain { + // The transaction identifier of this payment. + string txid = 1; + + // The confirmation status of this payment. + ConfirmationStatus status = 2; +} + +message ConfirmationStatus { + oneof status { + Confirmed confirmed = 1; + Unconfirmed unconfirmed = 2; + } +} + +// The on-chain transaction is confirmed in the best chain. +message Confirmed { + // The hex representation of hash of the block in which the transaction was confirmed. + string block_hash = 1; + + // The height under which the block was confirmed. + uint32 height = 2; + + // The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. + uint64 timestamp = 3; +} + +// The on-chain transaction is unconfirmed. +message Unconfirmed {} // Represents a BOLT 11 payment. message Bolt11 { diff --git a/ldk-server/ldk-server-protos/src/types.rs b/ldk-server/ldk-server-protos/src/types.rs index e5183c90b..20f2c6952 100644 --- a/ldk-server/ldk-server-protos/src/types.rs +++ b/ldk-server/ldk-server-protos/src/types.rs @@ -50,7 +50,49 @@ pub mod payment_kind { /// Represents an on-chain payment. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Onchain {} +pub struct Onchain { + /// The transaction identifier of this payment. + #[prost(string, tag = "1")] + pub txid: ::prost::alloc::string::String, + /// The confirmation status of this payment. + #[prost(message, optional, tag = "2")] + pub status: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ConfirmationStatus { + #[prost(oneof = "confirmation_status::Status", tags = "1, 2")] + pub status: ::core::option::Option, +} +/// Nested message and enum types in `ConfirmationStatus`. +pub mod confirmation_status { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Status { + #[prost(message, tag = "1")] + Confirmed(super::Confirmed), + #[prost(message, tag = "2")] + Unconfirmed(super::Unconfirmed), + } +} +/// The on-chain transaction is confirmed in the best chain. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Confirmed { + /// The hex representation of hash of the block in which the transaction was confirmed. + #[prost(string, tag = "1")] + pub block_hash: ::prost::alloc::string::String, + /// The height under which the block was confirmed. + #[prost(uint32, tag = "2")] + pub height: u32, + /// The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. + #[prost(uint64, tag = "3")] + pub timestamp: u64, +} +/// The on-chain transaction is unconfirmed. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Unconfirmed {} /// Represents a BOLT 11 payment. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/ldk-server/ldk-server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs index 039249615..82f405271 100644 --- a/ldk-server/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -5,8 +5,11 @@ use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; use ldk_node::lightning::ln::types::ChannelId; use ldk_node::lightning_invoice::{Bolt11InvoiceDescription, Description, Sha256}; -use ldk_node::payment::{PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus}; +use ldk_node::payment::{ + ConfirmationStatus, PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus, +}; use ldk_node::{ChannelDetails, LightningBalance, NodeError, PendingSweepBalance, UserChannelId}; +use ldk_server_protos::types::confirmation_status::Status::{Confirmed, Unconfirmed}; use ldk_server_protos::types::lightning_balance::BalanceType::{ ClaimableAwaitingConfirmations, ClaimableOnChannelClose, ContentiousClaimable, CounterpartyRevokedOutputClaimable, MaybePreimageClaimableHtlc, MaybeTimeoutClaimableHtlc, @@ -110,8 +113,11 @@ pub(crate) fn payment_kind_to_proto( payment_kind: PaymentKind, ) -> ldk_server_protos::types::PaymentKind { match payment_kind { - PaymentKind::Onchain => ldk_server_protos::types::PaymentKind { - kind: Some(Onchain(ldk_server_protos::types::Onchain {})), + PaymentKind::Onchain { txid, status } => ldk_server_protos::types::PaymentKind { + kind: Some(Onchain(ldk_server_protos::types::Onchain { + txid: txid.to_string(), + status: Some(confirmation_status_to_proto(status)), + })), }, PaymentKind::Bolt11 { hash, preimage, secret } => ldk_server_protos::types::PaymentKind { kind: Some(Bolt11(ldk_server_protos::types::Bolt11 { @@ -166,6 +172,25 @@ pub(crate) fn payment_kind_to_proto( } } +pub(crate) fn confirmation_status_to_proto( + confirmation_status: ConfirmationStatus, +) -> ldk_server_protos::types::ConfirmationStatus { + match confirmation_status { + ConfirmationStatus::Confirmed { block_hash, height, timestamp } => { + ldk_server_protos::types::ConfirmationStatus { + status: Some(Confirmed(ldk_server_protos::types::Confirmed { + block_hash: block_hash.to_string(), + height, + timestamp, + })), + } + }, + ConfirmationStatus::Unconfirmed => ldk_server_protos::types::ConfirmationStatus { + status: Some(Unconfirmed(ldk_server_protos::types::Unconfirmed {})), + }, + } +} + pub(crate) fn lightning_balance_to_proto( lightning_balance: LightningBalance, ) -> ldk_server_protos::types::LightningBalance { From f4c1692debda41a7cd888fa4ce0c7ebb6abcadaf Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:11:17 -0800 Subject: [PATCH 100/203] Derive traits for LdkServerError. --- ldk-server/ldk-server/src/api/error.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ldk-server/ldk-server/src/api/error.rs b/ldk-server/ldk-server/src/api/error.rs index d7ad95fef..ca41f9832 100644 --- a/ldk-server/ldk-server/src/api/error.rs +++ b/ldk-server/ldk-server/src/api/error.rs @@ -1,3 +1,4 @@ +#[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct LdkServerError { // The error message containing a generic description of the error condition in English. // It is intended for a human audience only and should not be parsed to extract any information @@ -10,6 +11,7 @@ pub(crate) struct LdkServerError { pub(crate) error_code: LdkServerErrorCode, } +#[derive(Clone, Debug, PartialEq, Eq)] pub(crate) enum LdkServerErrorCode { /// Please refer to [`protos::error::ErrorCode::InvalidRequestError`]. InvalidRequestError, From 31a8d13181ffb636e4842f67ee5c695f42bd58bf Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:12:09 -0800 Subject: [PATCH 101/203] Implement Display & std::Error for LdkServerError. --- ldk-server/ldk-server/src/api/error.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ldk-server/ldk-server/src/api/error.rs b/ldk-server/ldk-server/src/api/error.rs index ca41f9832..1ac18e824 100644 --- a/ldk-server/ldk-server/src/api/error.rs +++ b/ldk-server/ldk-server/src/api/error.rs @@ -1,3 +1,5 @@ +use std::fmt; + #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct LdkServerError { // The error message containing a generic description of the error condition in English. @@ -11,6 +13,14 @@ pub(crate) struct LdkServerError { pub(crate) error_code: LdkServerErrorCode, } +impl std::error::Error for LdkServerError {} + +impl fmt::Display for LdkServerError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Error: [{}]: {}", self.error_code, self.message) + } +} + #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) enum LdkServerErrorCode { /// Please refer to [`protos::error::ErrorCode::InvalidRequestError`]. @@ -25,3 +35,14 @@ pub(crate) enum LdkServerErrorCode { /// Please refer to [`protos::error::ErrorCode::InternalServerError`]. InternalServerError, } + +impl fmt::Display for LdkServerErrorCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + LdkServerErrorCode::InvalidRequestError => write!(f, "InvalidRequestError"), + LdkServerErrorCode::AuthError => write!(f, "AuthError"), + LdkServerErrorCode::LightningError => write!(f, "LightningError"), + LdkServerErrorCode::InternalServerError => write!(f, "InternalServerError"), + } + } +} From a74afa5f06dda307a4350fa4807a07a295724fbe Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:16:20 -0800 Subject: [PATCH 102/203] Add constructor for LdkServerError. --- ldk-server/ldk-server/src/api/error.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ldk-server/ldk-server/src/api/error.rs b/ldk-server/ldk-server/src/api/error.rs index 1ac18e824..4c203220b 100644 --- a/ldk-server/ldk-server/src/api/error.rs +++ b/ldk-server/ldk-server/src/api/error.rs @@ -13,6 +13,12 @@ pub(crate) struct LdkServerError { pub(crate) error_code: LdkServerErrorCode, } +impl LdkServerError { + pub(crate) fn new(error_code: LdkServerErrorCode, message: impl Into) -> Self { + Self { error_code, message: message.into() } + } +} + impl std::error::Error for LdkServerError {} impl fmt::Display for LdkServerError { From e4decbad3a98bb66dc205363646cc6ea62f9e7b9 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:18:52 -0800 Subject: [PATCH 103/203] Return LdkServerError from NodeService. --- ldk-server/ldk-server/src/service.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index 16ec58d92..7e6f91a70 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -12,6 +12,7 @@ use crate::api::bolt11_send::{handle_bolt11_send_request, BOLT11_SEND_PATH}; use crate::api::bolt12_receive::{handle_bolt12_receive_request, BOLT12_RECEIVE_PATH}; use crate::api::bolt12_send::{handle_bolt12_send_request, BOLT12_SEND_PATH}; use crate::api::close_channel::{handle_close_channel_request, CLOSE_CHANNEL_PATH}; +use crate::api::error::LdkServerError; use crate::api::get_balances::{handle_get_balances_request, GET_BALANCES}; use crate::api::get_node_info::{handle_get_node_info_request, GET_NODE_INFO}; use crate::api::get_payment_details::{ @@ -116,7 +117,7 @@ impl Service> for NodeService { async fn handle_request< T: Message + Default, R: Message, - F: Fn(Context, T) -> Result, + F: Fn(Context, T) -> Result, >( context: Context, request: Request, handler: F, ) -> Result<>>::Response, hyper::Error> { From 8f318a65efc79271a150093079b51f1613abe2ad Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:20:10 -0800 Subject: [PATCH 104/203] Return LdkServerError from GetNodeInfo API. --- ldk-server/ldk-server/src/api/get_node_info.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/api/get_node_info.rs b/ldk-server/ldk-server/src/api/get_node_info.rs index 59ace4598..52dff388b 100644 --- a/ldk-server/ldk-server/src/api/get_node_info.rs +++ b/ldk-server/ldk-server/src/api/get_node_info.rs @@ -1,3 +1,4 @@ +use crate::api::error::LdkServerError; use crate::service::Context; use ldk_server_protos::api::{GetNodeInfoRequest, GetNodeInfoResponse}; use ldk_server_protos::types::BestBlock; @@ -6,7 +7,7 @@ pub(crate) const GET_NODE_INFO: &str = "GetNodeInfo"; pub(crate) fn handle_get_node_info_request( context: Context, _request: GetNodeInfoRequest, -) -> Result { +) -> Result { let node_status = context.node.status(); let best_block = BestBlock { From 027436e12cc87ca9b3eb9ebcbb39e62deb041e33 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:21:20 -0800 Subject: [PATCH 105/203] Return LdkServerError from GetBalances API. --- ldk-server/ldk-server/src/api/get_balances.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/api/get_balances.rs b/ldk-server/ldk-server/src/api/get_balances.rs index e236976b5..5516fed9e 100644 --- a/ldk-server/ldk-server/src/api/get_balances.rs +++ b/ldk-server/ldk-server/src/api/get_balances.rs @@ -1,3 +1,4 @@ +use crate::api::error::LdkServerError; use crate::service::Context; use crate::util::proto_adapter::{lightning_balance_to_proto, pending_sweep_balance_to_proto}; use ldk_server_protos::api::{GetBalancesRequest, GetBalancesResponse}; @@ -6,7 +7,7 @@ pub(crate) const GET_BALANCES: &str = "GetBalances"; pub(crate) fn handle_get_balances_request( context: Context, _request: GetBalancesRequest, -) -> Result { +) -> Result { let balance_details = context.node.list_balances(); let response = GetBalancesResponse { From b96be729ba922d978ab93b78797b084c78833b85 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:36:35 -0800 Subject: [PATCH 106/203] Impl from for LdkServerError. --- ldk-server/ldk-server/src/api/error.rs | 65 ++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/ldk-server/ldk-server/src/api/error.rs b/ldk-server/ldk-server/src/api/error.rs index 4c203220b..4fa365f9b 100644 --- a/ldk-server/ldk-server/src/api/error.rs +++ b/ldk-server/ldk-server/src/api/error.rs @@ -1,3 +1,4 @@ +use ldk_node::NodeError; use std::fmt; #[derive(Clone, Debug, PartialEq, Eq)] @@ -52,3 +53,67 @@ impl fmt::Display for LdkServerErrorCode { } } } + +impl From for LdkServerError { + fn from(error: NodeError) -> Self { + let (message, error_code) = match error { + NodeError::InvalidAddress + | NodeError::InvalidSocketAddress + | NodeError::InvalidPublicKey + | NodeError::InvalidSecretKey + | NodeError::InvalidOfferId + | NodeError::InvalidNodeId + | NodeError::InvalidPaymentId + | NodeError::InvalidPaymentHash + | NodeError::InvalidPaymentPreimage + | NodeError::InvalidPaymentSecret + | NodeError::InvalidAmount + | NodeError::InvalidInvoice + | NodeError::InvalidOffer + | NodeError::InvalidRefund + | NodeError::InvalidChannelId + | NodeError::InvalidNetwork + | NodeError::InvalidUri + | NodeError::InvalidQuantity + | NodeError::InvalidNodeAlias + | NodeError::InvalidDateTime + | NodeError::InvalidFeeRate + | NodeError::UriParameterParsingFailed => { + (error.to_string(), LdkServerErrorCode::InvalidRequestError) + }, + + NodeError::ConnectionFailed + | NodeError::InvoiceCreationFailed + | NodeError::InvoiceRequestCreationFailed + | NodeError::OfferCreationFailed + | NodeError::RefundCreationFailed + | NodeError::PaymentSendingFailed + | NodeError::InvalidCustomTlvs + | NodeError::ProbeSendingFailed + | NodeError::ChannelCreationFailed + | NodeError::ChannelClosingFailed + | NodeError::ChannelConfigUpdateFailed + | NodeError::DuplicatePayment + | NodeError::InsufficientFunds + | NodeError::UnsupportedCurrency + | NodeError::LiquidityFeeTooHigh => (error.to_string(), LdkServerErrorCode::LightningError), + + NodeError::AlreadyRunning + | NodeError::NotRunning + | NodeError::PersistenceFailed + | NodeError::FeerateEstimationUpdateFailed + | NodeError::FeerateEstimationUpdateTimeout + | NodeError::WalletOperationFailed + | NodeError::WalletOperationTimeout + | NodeError::GossipUpdateFailed + | NodeError::GossipUpdateTimeout + | NodeError::LiquiditySourceUnavailable + | NodeError::LiquidityRequestFailed + | NodeError::OnchainTxCreationFailed + | NodeError::OnchainTxSigningFailed + | NodeError::TxSyncFailed + | NodeError::TxSyncTimeout => (error.to_string(), LdkServerErrorCode::InternalServerError), + }; + LdkServerError::new(error_code, message) + } +} From 57ea1d274fa794d1f276a6934e2242c0012e09c1 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:38:29 -0800 Subject: [PATCH 107/203] Return LdkServerError from OnchainReceive API. --- ldk-server/ldk-server/src/api/onchain_receive.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/api/onchain_receive.rs b/ldk-server/ldk-server/src/api/onchain_receive.rs index bfc9af6a6..2c8a9d45a 100644 --- a/ldk-server/ldk-server/src/api/onchain_receive.rs +++ b/ldk-server/ldk-server/src/api/onchain_receive.rs @@ -1,10 +1,11 @@ +use crate::api::error::LdkServerError; use crate::service::Context; use ldk_server_protos::api::{OnchainReceiveRequest, OnchainReceiveResponse}; pub(crate) const ONCHAIN_RECEIVE_PATH: &str = "OnchainReceive"; pub(crate) fn handle_onchain_receive_request( context: Context, _request: OnchainReceiveRequest, -) -> Result { +) -> Result { let response = OnchainReceiveResponse { address: context.node.onchain_payment().new_address()?.to_string(), }; From f2dc683edcb4f5078c1f536a833a931ae3929e93 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:46:09 -0800 Subject: [PATCH 108/203] Return LdkServerError from OnchainSend API. --- ldk-server/ldk-server/src/api/onchain_send.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ldk-server/ldk-server/src/api/onchain_send.rs b/ldk-server/ldk-server/src/api/onchain_send.rs index a3af974bc..be9b2e0de 100644 --- a/ldk-server/ldk-server/src/api/onchain_send.rs +++ b/ldk-server/ldk-server/src/api/onchain_send.rs @@ -1,3 +1,5 @@ +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; use ldk_node::bitcoin::{Address, FeeRate}; use ldk_server_protos::api::{OnchainSendRequest, OnchainSendResponse}; @@ -7,11 +9,16 @@ pub(crate) const ONCHAIN_SEND_PATH: &str = "OnchainSend"; pub(crate) fn handle_onchain_send_request( context: Context, request: OnchainSendRequest, -) -> Result { +) -> Result { let address = Address::from_str(&request.address) .map_err(|_| ldk_node::NodeError::InvalidAddress)? .require_network(context.node.config().network) - .map_err(|_| ldk_node::NodeError::InvalidAddress)?; + .map_err(|_| { + LdkServerError::new( + InvalidRequestError, + "Address is not valid for LdkServer's configured network.".to_string(), + ) + })?; let fee_rate = request.fee_rate_sat_per_vb.map(FeeRate::from_sat_per_vb).flatten(); let txid = match (request.amount_sats, request.send_all) { @@ -22,7 +29,12 @@ pub(crate) fn handle_onchain_send_request( (None, Some(true)) => { context.node.onchain_payment().send_all_to_address(&address, false, fee_rate)? }, - _ => return Err(ldk_node::NodeError::InvalidAmount), + _ => { + return Err(LdkServerError::new( + InvalidRequestError, + "Must specify either `send_all` or `amount_sats`, but not both or neither", + )) + }, }; let response = OnchainSendResponse { txid: txid.to_string() }; Ok(response) From 33756737e35ed8cd1bc4808f5ee062b48e10af29 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:55:38 -0800 Subject: [PATCH 109/203] Return LdkServerError from Bolt11Receive API. --- .../ldk-server/src/api/bolt11_receive.rs | 3 +- .../ldk-server/src/util/proto_adapter.rs | 29 +++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/ldk-server/ldk-server/src/api/bolt11_receive.rs b/ldk-server/ldk-server/src/api/bolt11_receive.rs index f6bab7fb5..c81b94c4e 100644 --- a/ldk-server/ldk-server/src/api/bolt11_receive.rs +++ b/ldk-server/ldk-server/src/api/bolt11_receive.rs @@ -1,3 +1,4 @@ +use crate::api::error::LdkServerError; use crate::service::Context; use crate::util::proto_adapter::proto_to_bolt11_description; use ldk_server_protos::api::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; @@ -6,7 +7,7 @@ pub(crate) const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; pub(crate) fn handle_bolt11_receive_request( context: Context, request: Bolt11ReceiveRequest, -) -> Result { +) -> Result { let description = proto_to_bolt11_description(request.description)?; let invoice = match request.amount_msat { Some(amount_msat) => { diff --git a/ldk-server/ldk-server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs index 82f405271..e8aba09f0 100644 --- a/ldk-server/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -1,3 +1,5 @@ +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; use bytes::Bytes; use hex::prelude::*; use ldk_node::bitcoin::hashes::sha256; @@ -8,7 +10,7 @@ use ldk_node::lightning_invoice::{Bolt11InvoiceDescription, Description, Sha256} use ldk_node::payment::{ ConfirmationStatus, PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus, }; -use ldk_node::{ChannelDetails, LightningBalance, NodeError, PendingSweepBalance, UserChannelId}; +use ldk_node::{ChannelDetails, LightningBalance, PendingSweepBalance, UserChannelId}; use ldk_server_protos::types::confirmation_status::Status::{Confirmed, Unconfirmed}; use ldk_server_protos::types::lightning_balance::BalanceType::{ ClaimableAwaitingConfirmations, ClaimableOnChannelClose, ContentiousClaimable, @@ -378,15 +380,32 @@ pub(crate) fn forwarded_payment_to_proto( pub(crate) fn proto_to_bolt11_description( description: Option, -) -> Result { +) -> Result { Ok(match description.and_then(|d| d.kind) { Some(bolt11_invoice_description::Kind::Direct(s)) => { - Bolt11InvoiceDescription::Direct(Description::new(s).unwrap()) + Bolt11InvoiceDescription::Direct(Description::new(s).map_err(|e| { + LdkServerError::new( + InvalidRequestError, + format!("Invalid invoice description: {}", e), + ) + })?) }, Some(bolt11_invoice_description::Kind::Hash(h)) => { - let hash_bytes = <[u8; 32]>::from_hex(&h).map_err(|_| NodeError::InvalidInvoice)?; + let hash_bytes = <[u8; 32]>::from_hex(&h).map_err(|_| { + LdkServerError::new( + InvalidRequestError, + "Invalid invoice description_hash, must be 32-byte hex string".to_string(), + ) + })?; Bolt11InvoiceDescription::Hash(Sha256(*sha256::Hash::from_bytes_ref(&hash_bytes))) }, - None => Bolt11InvoiceDescription::Direct(Description::new("".to_string()).unwrap()), + None => { + Bolt11InvoiceDescription::Direct(Description::new("".to_string()).map_err(|e| { + LdkServerError::new( + InvalidRequestError, + format!("Invalid invoice description: {}", e), + ) + })?) + }, }) } From ca62635373dd09623006894a843b4b80a5672118 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:56:45 -0800 Subject: [PATCH 110/203] Return LdkServerError from Bolt11Send API. --- ldk-server/ldk-server/src/api/bolt11_send.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/api/bolt11_send.rs b/ldk-server/ldk-server/src/api/bolt11_send.rs index f73f0dbd2..7b12483dc 100644 --- a/ldk-server/ldk-server/src/api/bolt11_send.rs +++ b/ldk-server/ldk-server/src/api/bolt11_send.rs @@ -1,3 +1,4 @@ +use crate::api::error::LdkServerError; use crate::service::Context; use bytes::Bytes; use ldk_node::lightning_invoice::Bolt11Invoice; @@ -8,7 +9,7 @@ pub(crate) const BOLT11_SEND_PATH: &str = "Bolt11Send"; pub(crate) fn handle_bolt11_send_request( context: Context, request: Bolt11SendRequest, -) -> Result { +) -> Result { let invoice = Bolt11Invoice::from_str(&request.invoice.as_str()) .map_err(|_| ldk_node::NodeError::InvalidInvoice)?; From 5c2c2e651085de301a0114d9af500e17cade10e3 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:58:06 -0800 Subject: [PATCH 111/203] Return LdkServerError from Bolt12Receive API. --- ldk-server/ldk-server/src/api/bolt12_receive.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/api/bolt12_receive.rs b/ldk-server/ldk-server/src/api/bolt12_receive.rs index 25039876f..cb1ee502d 100644 --- a/ldk-server/ldk-server/src/api/bolt12_receive.rs +++ b/ldk-server/ldk-server/src/api/bolt12_receive.rs @@ -1,3 +1,4 @@ +use crate::api::error::LdkServerError; use crate::service::Context; use ldk_server_protos::api::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; @@ -5,7 +6,7 @@ pub(crate) const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive"; pub(crate) fn handle_bolt12_receive_request( context: Context, request: Bolt12ReceiveRequest, -) -> Result { +) -> Result { let offer = match request.amount_msat { Some(amount_msat) => context.node.bolt12_payment().receive( amount_msat, From 321da5f9a11ed5fd188ea095dc1c419ed3d7e5cb Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:59:39 -0800 Subject: [PATCH 112/203] Return LdkServerError from Bolt12Send API. --- ldk-server/ldk-server/src/api/bolt12_send.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/api/bolt12_send.rs b/ldk-server/ldk-server/src/api/bolt12_send.rs index 95f3a48db..d3ff75483 100644 --- a/ldk-server/ldk-server/src/api/bolt12_send.rs +++ b/ldk-server/ldk-server/src/api/bolt12_send.rs @@ -1,3 +1,4 @@ +use crate::api::error::LdkServerError; use crate::service::Context; use bytes::Bytes; use ldk_node::lightning::offers::offer::Offer; @@ -8,7 +9,7 @@ pub(crate) const BOLT12_SEND_PATH: &str = "Bolt12Send"; pub(crate) fn handle_bolt12_send_request( context: Context, request: Bolt12SendRequest, -) -> Result { +) -> Result { let offer = Offer::from_str(&request.offer.as_str()).map_err(|_| ldk_node::NodeError::InvalidOffer)?; From 0f366dbcf43741c3213731f079c071584cbd6ff4 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 15:00:41 -0800 Subject: [PATCH 113/203] Return LdkServerError from OpenChannel API. --- ldk-server/ldk-server/src/api/open_channel.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/api/open_channel.rs b/ldk-server/ldk-server/src/api/open_channel.rs index d7a002d33..3258d61a4 100644 --- a/ldk-server/ldk-server/src/api/open_channel.rs +++ b/ldk-server/ldk-server/src/api/open_channel.rs @@ -1,3 +1,4 @@ +use crate::api::error::LdkServerError; use crate::service::Context; use bytes::Bytes; use ldk_node::bitcoin::secp256k1::PublicKey; @@ -9,7 +10,7 @@ pub(crate) const OPEN_CHANNEL_PATH: &str = "OpenChannel"; pub(crate) fn handle_open_channel( context: Context, request: OpenChannelRequest, -) -> Result { +) -> Result { let node_id = PublicKey::from_str(&request.node_pubkey) .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; let address = SocketAddress::from_str(&request.address) From 5231a9b4f8559ab0aea3ad79a4f7ef06afd02a48 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 15:08:18 -0800 Subject: [PATCH 114/203] Return LdkServerError from CloseChannel API. --- ldk-server/ldk-server/src/api/close_channel.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ldk-server/ldk-server/src/api/close_channel.rs b/ldk-server/ldk-server/src/api/close_channel.rs index b1892d76c..6d7436e42 100644 --- a/ldk-server/ldk-server/src/api/close_channel.rs +++ b/ldk-server/ldk-server/src/api/close_channel.rs @@ -1,3 +1,5 @@ +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::UserChannelId; @@ -8,13 +10,17 @@ pub(crate) const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; pub(crate) fn handle_close_channel_request( context: Context, request: CloseChannelRequest, -) -> Result { +) -> Result { //TODO: Should this be string? let mut user_channel_id_bytes = [0u8; 16]; user_channel_id_bytes.copy_from_slice(&request.user_channel_id); let user_channel_id = UserChannelId(u128::from_be_bytes(user_channel_id_bytes)); - let counterparty_node_id = PublicKey::from_str(&request.counterparty_node_id) - .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; + let counterparty_node_id = PublicKey::from_str(&request.counterparty_node_id).map_err(|e| { + LdkServerError::new( + InvalidRequestError, + format!("Invalid counterparty node ID, error: {}", e), + ) + })?; match request.force_close { Some(true) => context.node.force_close_channel( From a63c1da90746a3850a8d0b20900ccd2806ec5038 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 15:10:14 -0800 Subject: [PATCH 115/203] Return LdkServerError from ListChannels API. --- ldk-server/ldk-server/src/api/list_channels.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/api/list_channels.rs b/ldk-server/ldk-server/src/api/list_channels.rs index d55f26ac5..712eee770 100644 --- a/ldk-server/ldk-server/src/api/list_channels.rs +++ b/ldk-server/ldk-server/src/api/list_channels.rs @@ -1,3 +1,4 @@ +use crate::api::error::LdkServerError; use crate::service::Context; use crate::util::proto_adapter::channel_to_proto; use ldk_server_protos::api::{ListChannelsRequest, ListChannelsResponse}; @@ -6,7 +7,7 @@ pub(crate) const LIST_CHANNELS_PATH: &str = "ListChannels"; pub(crate) fn handle_list_channels_request( context: Context, _request: ListChannelsRequest, -) -> Result { +) -> Result { let channels = context.node.list_channels().into_iter().map(|c| channel_to_proto(c)).collect(); let response = ListChannelsResponse { channels }; From 093eb8b51ef59d180b43e5e6711c6a07af9a92c7 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 15:26:30 -0800 Subject: [PATCH 116/203] Return LdkServerError from UpdateChannelConfig API. --- .../src/api/update_channel_config.rs | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/ldk-server/ldk-server/src/api/update_channel_config.rs b/ldk-server/ldk-server/src/api/update_channel_config.rs index c183ebbc6..73f278664 100644 --- a/ldk-server/ldk-server/src/api/update_channel_config.rs +++ b/ldk-server/ldk-server/src/api/update_channel_config.rs @@ -1,3 +1,5 @@ +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::{InvalidRequestError, LightningError}; use crate::service::Context; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; @@ -10,9 +12,10 @@ pub(crate) const UPDATE_CHANNEL_CONFIG_PATH: &str = "UpdateChannelConfig"; pub(crate) fn handle_update_channel_config_request( context: Context, request: UpdateChannelConfigRequest, -) -> Result { - let user_channel_id: u128 = - request.user_channel_id.parse().map_err(|_| ldk_node::NodeError::InvalidChannelId)?; +) -> Result { + let user_channel_id: u128 = request.user_channel_id.parse().map_err(|_| { + LdkServerError::new(InvalidRequestError, "Failed to parse user_channel_id: invalid format.") + })?; //FIXME: Use ldk/ldk-node's partial config update api. let current_config = context @@ -20,14 +23,24 @@ pub(crate) fn handle_update_channel_config_request( .list_channels() .into_iter() .find(|c| c.user_channel_id.0 == user_channel_id) - .ok_or_else(|| ldk_node::NodeError::InvalidChannelId)? + .ok_or_else(|| { + LdkServerError::new(InvalidRequestError, "Channel not found for given user_channel_id.") + })? .config; - let updated_channel_config = - build_updated_channel_config(current_config, request.channel_config.unwrap()); + let updated_channel_config = build_updated_channel_config( + current_config, + request.channel_config.ok_or_else(|| { + LdkServerError::new(InvalidRequestError, "Channel config must be provided.") + })?, + )?; - let counterparty_node_id = PublicKey::from_str(&request.counterparty_node_id) - .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; + let counterparty_node_id = PublicKey::from_str(&request.counterparty_node_id).map_err(|e| { + LdkServerError::new( + InvalidRequestError, + format!("Invalid counterparty node id, error {}", e), + ) + })?; context .node @@ -36,14 +49,16 @@ pub(crate) fn handle_update_channel_config_request( counterparty_node_id, updated_channel_config, ) - .map_err(ldk_node::NodeError::from)?; + .map_err(|e| { + LdkServerError::new(LightningError, format!("Failed to update channel config: {}", e)) + })?; Ok(UpdateChannelConfigResponse {}) } fn build_updated_channel_config( current_config: ChannelConfig, proto_channel_config: ldk_server_protos::types::ChannelConfig, -) -> ChannelConfig { +) -> Result { let max_dust_htlc_exposure = proto_channel_config .max_dust_htlc_exposure .map(|max_dust_htlc_exposure| match max_dust_htlc_exposure { @@ -56,12 +71,18 @@ fn build_updated_channel_config( }) .unwrap_or(current_config.max_dust_htlc_exposure); - let cltv_expiry_delta = proto_channel_config - .cltv_expiry_delta - .map(|c| u16::try_from(c).unwrap()) - .unwrap_or(current_config.cltv_expiry_delta); + let cltv_expiry_delta = match proto_channel_config.cltv_expiry_delta { + Some(c) => Some(u16::try_from(c).map_err(|_| { + LdkServerError::new( + InvalidRequestError, + format!("Invalid cltv_expiry_delta, must be between 0 and {}", u16::MAX), + ) + })?), + None => None, + } + .unwrap_or_else(|| current_config.cltv_expiry_delta); - ChannelConfig { + Ok(ChannelConfig { forwarding_fee_proportional_millionths: proto_channel_config .forwarding_fee_proportional_millionths .unwrap_or(current_config.forwarding_fee_proportional_millionths), @@ -76,5 +97,5 @@ fn build_updated_channel_config( accept_underpaying_htlcs: proto_channel_config .accept_underpaying_htlcs .unwrap_or(current_config.accept_underpaying_htlcs), - } + }) } From 88929c153fd4e3a969ced6c5caa81dcb8139d1a4 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 15:30:15 -0800 Subject: [PATCH 117/203] Return LdkServerError from GetPaymentDetails API. --- .../ldk-server/src/api/get_payment_details.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/ldk-server/ldk-server/src/api/get_payment_details.rs b/ldk-server/ldk-server/src/api/get_payment_details.rs index 620e7d0d5..033f5f8cf 100644 --- a/ldk-server/ldk-server/src/api/get_payment_details.rs +++ b/ldk-server/ldk-server/src/api/get_payment_details.rs @@ -1,3 +1,5 @@ +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; use crate::util::proto_adapter::payment_to_proto; use hex::FromHex; @@ -8,9 +10,14 @@ pub(crate) const GET_PAYMENT_DETAILS_PATH: &str = "GetPaymentDetails"; pub(crate) fn handle_get_payment_details_request( context: Context, request: GetPaymentDetailsRequest, -) -> Result { - let payment_id_bytes = <[u8; PaymentId::LENGTH]>::from_hex(&request.payment_id) - .map_err(|_| ldk_node::NodeError::InvalidPaymentId)?; +) -> Result { + let payment_id_bytes = + <[u8; PaymentId::LENGTH]>::from_hex(&request.payment_id).map_err(|_| { + LdkServerError::new( + InvalidRequestError, + format!("Invalid payment_id, must be a {}-byte hex-string.", PaymentId::LENGTH), + ) + })?; let payment_details = context.node.payment(&PaymentId(payment_id_bytes)); From 68ecb297d2a98db997dba284ff1448aacddb9e85 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 15:30:53 -0800 Subject: [PATCH 118/203] Return LdkServerError from ListPayments API. --- ldk-server/ldk-server/src/api/list_payments.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/api/list_payments.rs b/ldk-server/ldk-server/src/api/list_payments.rs index 04ef699e1..6aaed7a98 100644 --- a/ldk-server/ldk-server/src/api/list_payments.rs +++ b/ldk-server/ldk-server/src/api/list_payments.rs @@ -1,3 +1,4 @@ +use crate::api::error::LdkServerError; use crate::service::Context; use crate::util::proto_adapter::payment_to_proto; use ldk_server_protos::api::{ListPaymentsRequest, ListPaymentsResponse}; @@ -6,7 +7,7 @@ pub(crate) const LIST_PAYMENTS_PATH: &str = "ListPayments"; pub(crate) fn handle_list_payments_request( context: Context, _request: ListPaymentsRequest, -) -> Result { +) -> Result { let payments = context.node.list_payments().into_iter().map(|p| payment_to_proto(p)).collect(); let response = ListPaymentsResponse { payments }; From 2cd8435519ae1994a59806bb84d5c3fd33e04f94 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 15:33:14 -0800 Subject: [PATCH 119/203] Return LdkServerError from ListForwardedPayments API. --- .../src/api/list_forwarded_payments.rs | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/ldk-server/ldk-server/src/api/list_forwarded_payments.rs b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs index 3903f7ce7..8d14d7676 100644 --- a/ldk-server/ldk-server/src/api/list_forwarded_payments.rs +++ b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs @@ -1,3 +1,5 @@ +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InternalServerError; use crate::io::{ FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, @@ -12,7 +14,7 @@ pub(crate) const LIST_FORWARDED_PAYMENTS_PATH: &str = "ListForwardedPayments"; pub(crate) fn handle_list_forwarded_payments_request( context: Context, request: ListForwardedPaymentsRequest, -) -> Result { +) -> Result { let page_token = request.page_token.map(|p| (p.token, p.index)); let list_response = context .paginated_kv_store @@ -21,7 +23,12 @@ pub(crate) fn handle_list_forwarded_payments_request( FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, page_token, ) - .map_err(|_| ldk_node::NodeError::ConnectionFailed)?; + .map_err(|e| { + LdkServerError::new( + InternalServerError, + format!("Failed to list forwarded payments: {}", e), + ) + })?; let mut forwarded_payments: Vec = vec![]; for key in list_response.keys { @@ -32,9 +39,19 @@ pub(crate) fn handle_list_forwarded_payments_request( FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, &key, ) - .map_err(|_| ldk_node::NodeError::ConnectionFailed)?; + .map_err(|e| { + LdkServerError::new( + InternalServerError, + format!("Failed to read forwarded payment data: {}", e), + ) + })?; let forwarded_payment = ForwardedPayment::decode(Bytes::from(forwarded_payment_bytes)) - .map_err(|_| ldk_node::NodeError::ConnectionFailed)?; + .map_err(|e| { + LdkServerError::new( + InternalServerError, + format!("Failed to decode forwarded payment: {}", e), + ) + })?; forwarded_payments.push(forwarded_payment); } let response = ListForwardedPaymentsResponse { From fd6a5d470dc08a2daca523392cbcd8feab8a863d Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 15:37:30 -0800 Subject: [PATCH 120/203] Initialize vec with capacity, to pre-allocate space. --- ldk-server/ldk-server/src/api/list_forwarded_payments.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/api/list_forwarded_payments.rs b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs index 8d14d7676..539616158 100644 --- a/ldk-server/ldk-server/src/api/list_forwarded_payments.rs +++ b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs @@ -30,7 +30,8 @@ pub(crate) fn handle_list_forwarded_payments_request( ) })?; - let mut forwarded_payments: Vec = vec![]; + let mut forwarded_payments: Vec = + Vec::with_capacity(list_response.keys.len()); for key in list_response.keys { let forwarded_payment_bytes = context .paginated_kv_store From d75ffcecea2724252b57293e7f8d056520cc5de0 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 16:37:50 -0800 Subject: [PATCH 121/203] Return protobuf serialized ErrorResponse from APIs. --- ldk-server/ldk-server/src/service.rs | 27 ++++++++++++------- .../ldk-server/src/util/proto_adapter.rs | 26 +++++++++++++++++- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index 7e6f91a70..b3719ee2c 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -13,6 +13,7 @@ use crate::api::bolt12_receive::{handle_bolt12_receive_request, BOLT12_RECEIVE_P use crate::api::bolt12_send::{handle_bolt12_send_request, BOLT12_SEND_PATH}; use crate::api::close_channel::{handle_close_channel_request, CLOSE_CHANNEL_PATH}; use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::api::get_balances::{handle_get_balances_request, GET_BALANCES}; use crate::api::get_node_info::{handle_get_node_info_request, GET_NODE_INFO}; use crate::api::get_payment_details::{ @@ -30,6 +31,7 @@ use crate::api::update_channel_config::{ handle_update_channel_config_request, UPDATE_CHANNEL_CONFIG_PATH, }; use crate::io::paginated_kv_store::PaginatedKVStore; +use crate::util::proto_adapter::to_error_response; use std::future::Future; use std::pin::Pin; use std::sync::Arc; @@ -129,16 +131,23 @@ async fn handle_request< .body(Full::new(Bytes::from(response.encode_to_vec()))) // unwrap safety: body only errors when previous chained calls failed. .unwrap()), - Err(e) => Ok(Response::builder() - .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Full::new(Bytes::from(e.to_string().into_bytes()))) + Err(e) => { + let (error_response, status_code) = to_error_response(e); + Ok(Response::builder() + .status(status_code) + .body(Full::new(Bytes::from(error_response.encode_to_vec()))) + // unwrap safety: body only errors when previous chained calls failed. + .unwrap()) + }, + }, + Err(_) => { + let (error_response, status_code) = + to_error_response(LdkServerError::new(InvalidRequestError, "Malformed request.")); + Ok(Response::builder() + .status(status_code) + .body(Full::new(Bytes::from(error_response.encode_to_vec()))) // unwrap safety: body only errors when previous chained calls failed. - .unwrap()), + .unwrap()) }, - Err(_) => Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Full::new(Bytes::from(b"Error parsing request".to_vec()))) - // unwrap safety: body only errors when previous chained calls failed. - .unwrap()), } } diff --git a/ldk-server/ldk-server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs index e8aba09f0..6aa2c356f 100644 --- a/ldk-server/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -1,7 +1,10 @@ use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::InvalidRequestError; +use crate::api::error::LdkServerErrorCode::{ + AuthError, InternalServerError, InvalidRequestError, LightningError, +}; use bytes::Bytes; use hex::prelude::*; +use hyper::StatusCode; use ldk_node::bitcoin::hashes::sha256; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; @@ -11,6 +14,7 @@ use ldk_node::payment::{ ConfirmationStatus, PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus, }; use ldk_node::{ChannelDetails, LightningBalance, PendingSweepBalance, UserChannelId}; +use ldk_server_protos::error::{ErrorCode, ErrorResponse}; use ldk_server_protos::types::confirmation_status::Status::{Confirmed, Unconfirmed}; use ldk_server_protos::types::lightning_balance::BalanceType::{ ClaimableAwaitingConfirmations, ClaimableOnChannelClose, ContentiousClaimable, @@ -409,3 +413,23 @@ pub(crate) fn proto_to_bolt11_description( }, }) } + +pub(crate) fn to_error_response(ldk_error: LdkServerError) -> (ErrorResponse, StatusCode) { + let error_code = match ldk_error.error_code { + InvalidRequestError => ErrorCode::InvalidRequestError, + AuthError => ErrorCode::AuthError, + LightningError => ErrorCode::LightningError, + InternalServerError => ErrorCode::InternalServerError, + } as i32; + + let status = match ldk_error.error_code { + InvalidRequestError => StatusCode::BAD_REQUEST, + AuthError => StatusCode::UNAUTHORIZED, + LightningError => StatusCode::INTERNAL_SERVER_ERROR, + InternalServerError => StatusCode::INTERNAL_SERVER_ERROR, + }; + + let error_response = ErrorResponse { message: ldk_error.message, error_code }; + + (error_response, status) +} From 5dd656d903b744912769183f6508cb1604decfbe Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 17:36:52 -0800 Subject: [PATCH 122/203] Add ErrorResponse handling in client. --- ldk-server/ldk-server-client/src/client.rs | 45 +++++++++++---- ldk-server/ldk-server-client/src/error.rs | 66 ++++++++++++++++++---- 2 files changed, 88 insertions(+), 23 deletions(-) diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index c8f887228..e4a519bbb 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -1,6 +1,9 @@ use prost::Message; use crate::error::LdkServerError; +use crate::error::LdkServerErrorCode::{ + AuthError, InternalError, InternalServerError, InvalidRequestError, LightningError, +}; use ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse, Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, @@ -9,6 +12,7 @@ use ldk_server_protos::api::{ ListPaymentsRequest, ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, OpenChannelResponse, }; +use ldk_server_protos::error::{ErrorCode, ErrorResponse}; use reqwest::header::CONTENT_TYPE; use reqwest::Client; @@ -152,27 +156,46 @@ impl LdkServerClient { &self, request: &Rq, url: &str, ) -> Result { let request_body = request.encode_to_vec(); - let response_raw = match self + let response_raw = self .client .post(url) .header(CONTENT_TYPE, APPLICATION_OCTET_STREAM) .body(request_body) .send() .await - { - Ok(response) => response, - Err(e) => { - return Err(LdkServerError::InternalError(e.to_string())); - }, - }; + .map_err(|e| { + LdkServerError::new(InternalError, format!("HTTP request failed: {}", e)) + })?; + let status = response_raw.status(); - let payload = response_raw.bytes().await?; + let payload = response_raw.bytes().await.map_err(|e| { + LdkServerError::new(InternalError, format!("Failed to read response body: {}", e)) + })?; if status.is_success() { - Ok(Rs::decode(&payload[..])?) + Ok(Rs::decode(&payload[..]).map_err(|e| { + LdkServerError::new( + InternalError, + format!("Failed to decode success response: {}", e), + ) + })?) } else { - //TODO: Error handling and error response parsing. - Err(LdkServerError::InternalError("Unknown Error".to_string())) + let error_response = ErrorResponse::decode(&payload[..]).map_err(|e| { + LdkServerError::new( + InternalError, + format!("Failed to decode error response (status {}): {}", status, e), + ) + })?; + + let error_code = match ErrorCode::from_i32(error_response.error_code) { + Some(ErrorCode::InvalidRequestError) => InvalidRequestError, + Some(ErrorCode::AuthError) => AuthError, + Some(ErrorCode::LightningError) => LightningError, + Some(ErrorCode::InternalServerError) => InternalServerError, + Some(ErrorCode::UnknownError) | None => InternalError, + }; + + Err(LdkServerError::new(error_code, error_response.message)) } } } diff --git a/ldk-server/ldk-server-client/src/error.rs b/ldk-server/ldk-server-client/src/error.rs index 37f916e59..8dc16f665 100644 --- a/ldk-server/ldk-server-client/src/error.rs +++ b/ldk-server/ldk-server-client/src/error.rs @@ -1,20 +1,62 @@ -use prost::DecodeError; +use std::fmt; -/// When there is an error in request to LDK Server, the response contains a relevant error code. -#[derive(Debug)] -pub enum LdkServerError { - /// There is an unknown error. (Placeholder until error handling is done.) - InternalError(String), +/// Represents an error returned by the LDK server. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct LdkServerError { + /// The error message containing a generic description of the error condition in English. + /// It is intended for a human audience only and should not be parsed to extract any information + /// programmatically. Client-side code may use it for logging only. + pub message: String, + + /// The error code uniquely identifying an error condition. + /// It is meant to be read and understood programmatically by code that detects/handles errors by + /// type. + pub error_code: LdkServerErrorCode, +} + +impl LdkServerError { + /// Creates a new [`LdkServerError`] with the given error code and message. + pub fn new(error_code: LdkServerErrorCode, message: impl Into) -> Self { + Self { error_code, message: message.into() } + } } -impl From for LdkServerError { - fn from(err: DecodeError) -> Self { - LdkServerError::InternalError(err.to_string()) +impl std::error::Error for LdkServerError {} + +impl fmt::Display for LdkServerError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Error: [{}]: {}", self.error_code, self.message) } } -impl From for LdkServerError { - fn from(err: reqwest::Error) -> Self { - LdkServerError::InternalError(err.to_string()) +/// Defines error codes for categorizing LDK server errors. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum LdkServerErrorCode { + /// Please refer to [`ldk_server_protos::error::ErrorCode::InvalidRequestError`]. + InvalidRequestError, + + /// Please refer to [`ldk_server_protos::error::ErrorCode::AuthError`]. + AuthError, + + /// Please refer to [`ldk_server_protos::error::ErrorCode::LightningError`]. + LightningError, + + /// Please refer to [`ldk_server_protos::error::ErrorCode::InternalServerError`]. + InternalServerError, + + /// There is an unknown error, it could be a client-side bug, unrecognized error-code, network error + /// or something else. + InternalError, +} + +impl fmt::Display for LdkServerErrorCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + LdkServerErrorCode::InvalidRequestError => write!(f, "InvalidRequestError"), + LdkServerErrorCode::AuthError => write!(f, "AuthError"), + LdkServerErrorCode::LightningError => write!(f, "LightningError"), + LdkServerErrorCode::InternalServerError => write!(f, "InternalServerError"), + LdkServerErrorCode::InternalError => write!(f, "InternalError"), + } } } From df7d3765f7ea5e02476a3d232413e41225a0f916 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 26 Feb 2025 17:44:52 -0800 Subject: [PATCH 123/203] Add ErrorResponse handling in cli. --- ldk-server/ldk-server-cli/src/main.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 9f17b1ace..5dc616f2c 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -1,6 +1,9 @@ use clap::{Parser, Subcommand}; use ldk_server_client::client::LdkServerClient; use ldk_server_client::error::LdkServerError; +use ldk_server_client::error::LdkServerErrorCode::{ + AuthError, InternalError, InternalServerError, InvalidRequestError, LightningError, +}; use ldk_server_client::ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, Bolt12SendRequest, GetBalancesRequest, GetNodeInfoRequest, ListChannelsRequest, ListPaymentsRequest, @@ -123,7 +126,8 @@ async fn main() { kind: Some(bolt11_invoice_description::Kind::Hash(hash)), }), (Some(_), Some(_)) => { - handle_error(LdkServerError::InternalError( + handle_error(LdkServerError::new( + InternalError, "Only one of description or description_hash can be set.".to_string(), )); }, @@ -191,15 +195,22 @@ async fn main() { fn handle_response_result(response: Result) { match response { Ok(response) => { - println!("{:?}", response); + println!("Success: {:?}", response); }, Err(e) => { handle_error(e); }, - }; + } } fn handle_error(e: LdkServerError) -> ! { - eprintln!("Error executing command: {:?}", e); + let error_type = match e.error_code { + InvalidRequestError => "Invalid Request", + AuthError => "Authentication Error", + LightningError => "Lightning Error", + InternalServerError => "Internal Server Error", + InternalError => "Internal Error", + }; + eprintln!("Error ({}): {}", error_type, e.message); std::process::exit(1); // Exit with status code 1 on error. } From 4811d19f92c79818e7eafe4762fa3d2430b40724 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 5 Mar 2025 14:23:38 -0800 Subject: [PATCH 124/203] Start storing payments using PaginatedKVStore. --- ldk-server/ldk-server/src/io/mod.rs | 4 +++ ldk-server/ldk-server/src/main.rs | 52 +++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/ldk-server/ldk-server/src/io/mod.rs b/ldk-server/ldk-server/src/io/mod.rs index 52975ac1a..c5c4a1fd9 100644 --- a/ldk-server/ldk-server/src/io/mod.rs +++ b/ldk-server/ldk-server/src/io/mod.rs @@ -5,3 +5,7 @@ pub(crate) mod utils; /// The forwarded payments will be persisted under this prefix. pub(crate) const FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE: &str = "forwarded_payments"; pub(crate) const FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE: &str = ""; + +/// The payments will be persisted under this prefix. +pub(crate) const PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE: &str = "payments"; +pub(crate) const PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE: &str = ""; diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 20c138528..dd3e8b9da 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -17,12 +17,14 @@ use crate::io::paginated_kv_store::PaginatedKVStore; use crate::io::sqlite_store::SqliteStore; use crate::io::{ FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, - FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, + FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, + PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, }; use crate::util::config::load_config; -use crate::util::proto_adapter::forwarded_payment_to_proto; +use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto}; use hex::DisplayHex; use ldk_node::config::Config; +use ldk_node::lightning::util::persist::KVStore; use ldk_node::logger::LogLevel; use prost::Message; use rand::Rng; @@ -33,6 +35,38 @@ use std::time::{SystemTime, UNIX_EPOCH}; const USAGE_GUIDE: &str = "Usage: ldk-server "; +macro_rules! upsert_payment_details { + ($event_node:expr, $paginated_store:expr, $payment_id:expr) => {{ + if let Some(payment_details) = $event_node.payment($payment_id) { + let payment = payment_to_proto(payment_details); + let time = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time must be > 1970") + .as_secs() as i64; + + match $paginated_store.write( + PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, + PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, + &$payment_id.0.to_lower_hex_string(), + time, + &payment.encode_to_vec(), + ) { + Ok(_) => { + $event_node.event_handled(); + }, + Err(e) => { + eprintln!("Failed to write payment to persistence: {}", e); + }, + } + } else { + eprintln!( + "Unable to find payment with paymentId: {}", + $payment_id.0.to_lower_hex_string() + ); + } + }}; +} + fn main() { let args: Vec = std::env::args().collect(); @@ -146,7 +180,19 @@ fn main() { "PAYMENT_RECEIVED: with id {:?}, hash {}, amount_msat {}", payment_id, payment_hash, amount_msat ); - event_node.event_handled(); + let payment_id = payment_id.expect("PaymentId expected for ldk-server >=0.1"); + upsert_payment_details!(event_node, &paginated_store, &payment_id); + }, + Event::PaymentSuccessful {payment_id, ..} => { + let payment_id = payment_id.expect("PaymentId expected for ldk-server >=0.1"); + upsert_payment_details!(event_node, &paginated_store, &payment_id); + }, + Event::PaymentFailed {payment_id, ..} => { + let payment_id = payment_id.expect("PaymentId expected for ldk-server >=0.1"); + upsert_payment_details!(event_node, &paginated_store, &payment_id); + }, + Event::PaymentClaimable {payment_id, ..} => { + upsert_payment_details!(event_node, &paginated_store, &payment_id); }, Event::PaymentForwarded { prev_channel_id, From 1e4f0c020ca8b6b90d04e41a7b281f66a859fc7d Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 5 Mar 2025 14:27:29 -0800 Subject: [PATCH 125/203] API changes to support pagination in ListPayments. --- ldk-server/ldk-server-protos/src/api.rs | 26 ++++++++++++++++++- .../ldk-server-protos/src/proto/api.proto | 25 +++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index 8f2a0c451..795ce9e66 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -331,7 +331,16 @@ pub struct GetPaymentDetailsResponse { /// See more: #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct ListPaymentsRequest {} +pub struct ListPaymentsRequest { + /// `page_token` is a pagination token. + /// + /// To query for the first page, `page_token` must not be specified. + /// + /// For subsequent pages, use the value that was returned as `next_page_token` in the previous + /// page's response. + #[prost(message, optional, tag = "1")] + pub page_token: ::core::option::Option, +} /// The response `content` for the `ListPayments` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. #[allow(clippy::derive_partial_eq_without_eq)] @@ -340,6 +349,21 @@ pub struct ListPaymentsResponse { /// List of payments. #[prost(message, repeated, tag = "1")] pub payments: ::prost::alloc::vec::Vec, + /// `next_page_token` is a pagination token, used to retrieve the next page of results. + /// Use this value to query for next-page of paginated operation, by specifying + /// this value as the `page_token` in the next request. + /// + /// If `next_page_token` is `None`, then the "last page" of results has been processed and + /// there is no more data to be retrieved. + /// + /// If `next_page_token` is not `None`, it does not necessarily mean that there is more data in the + /// result set. The only way to know when you have reached the end of the result set is when + /// `next_page_token` is `None`. + /// + /// **Caution**: Clients must not assume a specific number of records to be present in a page for + /// paginated response. + #[prost(message, optional, tag = "2")] + pub next_page_token: ::core::option::Option, } /// Retrieves list of all forwarded payments. /// See more: diff --git a/ldk-server/ldk-server-protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto index 30aa70299..f0f523e21 100644 --- a/ldk-server/ldk-server-protos/src/proto/api.proto +++ b/ldk-server/ldk-server-protos/src/proto/api.proto @@ -314,13 +314,36 @@ message GetPaymentDetailsResponse { // Retrieves list of all payments. // See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_payments -message ListPaymentsRequest {} +message ListPaymentsRequest { + // `page_token` is a pagination token. + // + // To query for the first page, `page_token` must not be specified. + // + // For subsequent pages, use the value that was returned as `next_page_token` in the previous + // page's response. + optional types.PageToken page_token = 1; +} // The response `content` for the `ListPayments` API, when HttpStatusCode is OK (200). // When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message ListPaymentsResponse { // List of payments. repeated types.Payment payments = 1; + + // `next_page_token` is a pagination token, used to retrieve the next page of results. + // Use this value to query for next-page of paginated operation, by specifying + // this value as the `page_token` in the next request. + // + // If `next_page_token` is `None`, then the "last page" of results has been processed and + // there is no more data to be retrieved. + // + // If `next_page_token` is not `None`, it does not necessarily mean that there is more data in the + // result set. The only way to know when you have reached the end of the result set is when + // `next_page_token` is `None`. + // + // **Caution**: Clients must not assume a specific number of records to be present in a page for + // paginated response. + optional types.PageToken next_page_token = 2; } // Retrieves list of all forwarded payments. From c90d13f4d2639da28e7aef87a45bdbb978cca037 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 6 Mar 2025 12:16:48 -0800 Subject: [PATCH 126/203] Remove unused tokio dependency. --- ldk-server/ldk-server-client/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/ldk-server/ldk-server-client/Cargo.toml b/ldk-server/ldk-server-client/Cargo.toml index 616cc2d93..9db5fc2fc 100644 --- a/ldk-server/ldk-server-client/Cargo.toml +++ b/ldk-server/ldk-server-client/Cargo.toml @@ -6,5 +6,4 @@ edition = "2021" [dependencies] ldk-server-protos = { path = "../ldk-server-protos" } reqwest = { version = "0.11.13", default-features = false, features = ["rustls-tls"] } -tokio = { version = "1.38.0", default-features = false } prost = { version = "0.11.6", default-features = false, features = ["std", "prost-derive"] } From 274fbf3e4a45429c5a20bd51344613c17f368837 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 6 Mar 2025 12:17:20 -0800 Subject: [PATCH 127/203] Disable default features for bytes and rand crates. --- ldk-server/ldk-server/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index a7344684a..e7705f6bc 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -13,7 +13,7 @@ hyper-util = { version = "0.1", default-features = false, features = ["server-gr tokio = { version = "1.38.0", default-features = false, features = ["time", "signal", "rt-multi-thread"] } prost = { version = "0.11.6", default-features = false, features = ["std"] } ldk-server-protos = { path = "../ldk-server-protos" } -bytes = "1.4.0" +bytes = { version = "1.4.0", default-features = false } hex = { package = "hex-conservative", version = "0.2.1", default-features = false } rusqlite = { version = "0.31.0", features = ["bundled"] } -rand = "0.8.5" +rand = { version = "0.8.5", default-features = false } From f4eaf7a2ff665dd49e265b7ab0ce56c6d46d3aa3 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 6 Mar 2025 12:20:06 -0800 Subject: [PATCH 128/203] Update Cargo.lock --- ldk-server/Cargo.lock | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 19d9aa728..0d862daf3 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -437,7 +437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -696,11 +696,11 @@ checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" [[package]] name = "home" -version = "0.5.11" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1125,7 +1125,6 @@ dependencies = [ "ldk-server-protos", "prost", "reqwest", - "tokio", ] [[package]] @@ -1671,7 +1670,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1915,7 +1914,7 @@ dependencies = [ "getrandom 0.3.1", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -2305,15 +2304,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-targets" version = "0.48.5" From 9d8736c7d1a8327c2f7a015b1476d649cc74c725 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 5 Mar 2025 14:31:20 -0800 Subject: [PATCH 129/203] Support pagination in ListPayments API. --- .../ldk-server/src/api/list_payments.rs | 47 ++++++++++-- ldk-server/ldk-server/src/main.rs | 72 +++++++++---------- 2 files changed, 77 insertions(+), 42 deletions(-) diff --git a/ldk-server/ldk-server/src/api/list_payments.rs b/ldk-server/ldk-server/src/api/list_payments.rs index 6aaed7a98..769dd718a 100644 --- a/ldk-server/ldk-server/src/api/list_payments.rs +++ b/ldk-server/ldk-server/src/api/list_payments.rs @@ -1,15 +1,54 @@ use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InternalServerError; +use crate::io::{PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE}; use crate::service::Context; -use crate::util::proto_adapter::payment_to_proto; +use bytes::Bytes; use ldk_server_protos::api::{ListPaymentsRequest, ListPaymentsResponse}; +use ldk_server_protos::types::{PageToken, Payment}; +use prost::Message; pub(crate) const LIST_PAYMENTS_PATH: &str = "ListPayments"; pub(crate) fn handle_list_payments_request( - context: Context, _request: ListPaymentsRequest, + context: Context, request: ListPaymentsRequest, ) -> Result { - let payments = context.node.list_payments().into_iter().map(|p| payment_to_proto(p)).collect(); + let page_token = request.page_token.map(|p| (p.token, p.index)); + let list_response = context + .paginated_kv_store + .list( + PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, + PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, + page_token, + ) + .map_err(|e| { + LdkServerError::new(InternalServerError, format!("Failed to list payments: {}", e)) + })?; - let response = ListPaymentsResponse { payments }; + let mut payments: Vec = Vec::with_capacity(list_response.keys.len()); + for key in list_response.keys { + let payment_bytes = context + .paginated_kv_store + .read( + PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, + PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, + &key, + ) + .map_err(|e| { + LdkServerError::new( + InternalServerError, + format!("Failed to read payment data: {}", e), + ) + })?; + let payment = Payment::decode(Bytes::from(payment_bytes)).map_err(|e| { + LdkServerError::new(InternalServerError, format!("Failed to decode payment: {}", e)) + })?; + payments.push(payment); + } + let response = ListPaymentsResponse { + payments, + next_page_token: list_response + .next_page_token + .map(|(token, index)| PageToken { token, index }), + }; Ok(response) } diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index dd3e8b9da..819ff5071 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -5,7 +5,7 @@ mod util; use crate::service::NodeService; -use ldk_node::{Builder, Event}; +use ldk_node::{Builder, Event, Node}; use tokio::net::TcpListener; use tokio::signal::unix::SignalKind; @@ -24,7 +24,7 @@ use crate::util::config::load_config; use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto}; use hex::DisplayHex; use ldk_node::config::Config; -use ldk_node::lightning::util::persist::KVStore; +use ldk_node::lightning::ln::channelmanager::PaymentId; use ldk_node::logger::LogLevel; use prost::Message; use rand::Rng; @@ -35,38 +35,6 @@ use std::time::{SystemTime, UNIX_EPOCH}; const USAGE_GUIDE: &str = "Usage: ldk-server "; -macro_rules! upsert_payment_details { - ($event_node:expr, $paginated_store:expr, $payment_id:expr) => {{ - if let Some(payment_details) = $event_node.payment($payment_id) { - let payment = payment_to_proto(payment_details); - let time = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Time must be > 1970") - .as_secs() as i64; - - match $paginated_store.write( - PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, - PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, - &$payment_id.0.to_lower_hex_string(), - time, - &payment.encode_to_vec(), - ) { - Ok(_) => { - $event_node.event_handled(); - }, - Err(e) => { - eprintln!("Failed to write payment to persistence: {}", e); - }, - } - } else { - eprintln!( - "Unable to find payment with paymentId: {}", - $payment_id.0.to_lower_hex_string() - ); - } - }}; -} - fn main() { let args: Vec = std::env::args().collect(); @@ -181,18 +149,18 @@ fn main() { payment_id, payment_hash, amount_msat ); let payment_id = payment_id.expect("PaymentId expected for ldk-server >=0.1"); - upsert_payment_details!(event_node, &paginated_store, &payment_id); + upsert_payment_details(&event_node, Arc::clone(&paginated_store) as Arc, &payment_id); }, Event::PaymentSuccessful {payment_id, ..} => { let payment_id = payment_id.expect("PaymentId expected for ldk-server >=0.1"); - upsert_payment_details!(event_node, &paginated_store, &payment_id); + upsert_payment_details(&event_node, Arc::clone(&paginated_store) as Arc, &payment_id); }, Event::PaymentFailed {payment_id, ..} => { let payment_id = payment_id.expect("PaymentId expected for ldk-server >=0.1"); - upsert_payment_details!(event_node, &paginated_store, &payment_id); + upsert_payment_details(&event_node, Arc::clone(&paginated_store) as Arc, &payment_id); }, Event::PaymentClaimable {payment_id, ..} => { - upsert_payment_details!(event_node, &paginated_store, &payment_id); + upsert_payment_details(&event_node, Arc::clone(&paginated_store) as Arc, &payment_id); }, Event::PaymentForwarded { prev_channel_id, @@ -280,3 +248,31 @@ fn main() { node.stop().expect("Shutdown should always succeed."); println!("Shutdown complete.."); } + +fn upsert_payment_details( + event_node: &Node, paginated_store: Arc, payment_id: &PaymentId, +) { + if let Some(payment_details) = event_node.payment(payment_id) { + let payment = payment_to_proto(payment_details); + let time = + SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs() + as i64; + + match paginated_store.write( + PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, + PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, + &payment_id.0.to_lower_hex_string(), + time, + &payment.encode_to_vec(), + ) { + Ok(_) => { + event_node.event_handled(); + }, + Err(e) => { + eprintln!("Failed to write payment to persistence: {}", e); + }, + } + } else { + eprintln!("Unable to find payment with paymentId: {}", payment_id.0.to_lower_hex_string()); + } +} From 9aa4e4b9d8024ac0e1a41f0a4a07d9431efe44b5 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 6 Mar 2025 10:59:24 -0800 Subject: [PATCH 130/203] Support pagination in CLI for ListPayments API. --- ldk-server/ldk-server-cli/src/main.rs | 37 +++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 5dc616f2c..d76ba8820 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -10,8 +10,9 @@ use ldk_server_client::ldk_server_protos::api::{ OnchainReceiveRequest, OnchainSendRequest, OpenChannelRequest, }; use ldk_server_client::ldk_server_protos::types::{ - bolt11_invoice_description, Bolt11InvoiceDescription, + bolt11_invoice_description, Bolt11InvoiceDescription, PageToken, Payment, }; +use std::fmt::Debug; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -87,7 +88,13 @@ enum Commands { announce_channel: bool, }, ListChannels, - ListPayments, + ListPayments { + #[arg(short, long)] + #[arg( + help = "Minimum number of payments to return. If not provided, only the first page of the paginated list is returned." + )] + number_of_payments: Option, + }, } #[tokio::main] @@ -186,13 +193,33 @@ async fn main() { Commands::ListChannels => { handle_response_result(client.list_channels(ListChannelsRequest {}).await); }, - Commands::ListPayments => { - handle_response_result(client.list_payments(ListPaymentsRequest {}).await); + Commands::ListPayments { number_of_payments } => { + handle_response_result(list_n_payments(client, number_of_payments).await); }, } } -fn handle_response_result(response: Result) { +async fn list_n_payments( + client: LdkServerClient, number_of_payments: Option, +) -> Result, LdkServerError> { + let mut payments = Vec::new(); + let mut page_token: Option = None; + // If no count is specified, just list the first page. + let target_count = number_of_payments.unwrap_or(0); + + loop { + let response = client.list_payments(ListPaymentsRequest { page_token }).await?; + + payments.extend(response.payments); + if payments.len() >= target_count as usize || response.next_page_token.is_none() { + break; + } + page_token = response.next_page_token; + } + Ok(payments) +} + +fn handle_response_result(response: Result) { match response { Ok(response) => { println!("Success: {:?}", response); From c2706450c88bfd299baacf2d0f372fb754d8e13a Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 12 Mar 2025 12:06:28 -0700 Subject: [PATCH 131/203] Refactor persistance related IO to separate module. --- .../ldk-server/src/api/list_forwarded_payments.rs | 2 +- ldk-server/ldk-server/src/api/list_payments.rs | 4 +++- ldk-server/ldk-server/src/io/mod.rs | 11 +---------- ldk-server/ldk-server/src/io/persist/mod.rs | 10 ++++++++++ .../src/io/{ => persist}/paginated_kv_store.rs | 0 .../src/io/{ => persist}/sqlite_store/mod.rs | 2 +- ldk-server/ldk-server/src/main.rs | 6 +++--- ldk-server/ldk-server/src/service.rs | 2 +- 8 files changed, 20 insertions(+), 17 deletions(-) create mode 100644 ldk-server/ldk-server/src/io/persist/mod.rs rename ldk-server/ldk-server/src/io/{ => persist}/paginated_kv_store.rs (100%) rename ldk-server/ldk-server/src/io/{ => persist}/sqlite_store/mod.rs (99%) diff --git a/ldk-server/ldk-server/src/api/list_forwarded_payments.rs b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs index 539616158..c6762e0f4 100644 --- a/ldk-server/ldk-server/src/api/list_forwarded_payments.rs +++ b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs @@ -1,6 +1,6 @@ use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InternalServerError; -use crate::io::{ +use crate::io::persist::{ FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, }; diff --git a/ldk-server/ldk-server/src/api/list_payments.rs b/ldk-server/ldk-server/src/api/list_payments.rs index 769dd718a..0e9d53525 100644 --- a/ldk-server/ldk-server/src/api/list_payments.rs +++ b/ldk-server/ldk-server/src/api/list_payments.rs @@ -1,6 +1,8 @@ use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InternalServerError; -use crate::io::{PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE}; +use crate::io::persist::{ + PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, +}; use crate::service::Context; use bytes::Bytes; use ldk_server_protos::api::{ListPaymentsRequest, ListPaymentsResponse}; diff --git a/ldk-server/ldk-server/src/io/mod.rs b/ldk-server/ldk-server/src/io/mod.rs index c5c4a1fd9..22c58bb74 100644 --- a/ldk-server/ldk-server/src/io/mod.rs +++ b/ldk-server/ldk-server/src/io/mod.rs @@ -1,11 +1,2 @@ -pub(crate) mod paginated_kv_store; -pub(crate) mod sqlite_store; +pub(crate) mod persist; pub(crate) mod utils; - -/// The forwarded payments will be persisted under this prefix. -pub(crate) const FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE: &str = "forwarded_payments"; -pub(crate) const FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE: &str = ""; - -/// The payments will be persisted under this prefix. -pub(crate) const PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE: &str = "payments"; -pub(crate) const PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE: &str = ""; diff --git a/ldk-server/ldk-server/src/io/persist/mod.rs b/ldk-server/ldk-server/src/io/persist/mod.rs new file mode 100644 index 000000000..da342acc4 --- /dev/null +++ b/ldk-server/ldk-server/src/io/persist/mod.rs @@ -0,0 +1,10 @@ +pub(crate) mod paginated_kv_store; +pub(crate) mod sqlite_store; + +/// The forwarded payments will be persisted under this prefix. +pub(crate) const FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE: &str = "forwarded_payments"; +pub(crate) const FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE: &str = ""; + +/// The payments will be persisted under this prefix. +pub(crate) const PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE: &str = "payments"; +pub(crate) const PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE: &str = ""; diff --git a/ldk-server/ldk-server/src/io/paginated_kv_store.rs b/ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs similarity index 100% rename from ldk-server/ldk-server/src/io/paginated_kv_store.rs rename to ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs diff --git a/ldk-server/ldk-server/src/io/sqlite_store/mod.rs b/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs similarity index 99% rename from ldk-server/ldk-server/src/io/sqlite_store/mod.rs rename to ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs index e63f54f13..9e53db3a5 100644 --- a/ldk-server/ldk-server/src/io/sqlite_store/mod.rs +++ b/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs @@ -1,4 +1,4 @@ -use crate::io::paginated_kv_store::{ListResponse, PaginatedKVStore}; +use crate::io::persist::paginated_kv_store::{ListResponse, PaginatedKVStore}; use crate::io::utils::check_namespace_key_validity; use ldk_node::lightning::types::string::PrintableString; use rusqlite::{named_params, Connection}; diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 819ff5071..c084cdf3f 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -13,9 +13,9 @@ use tokio::signal::unix::SignalKind; use hyper::server::conn::http1; use hyper_util::rt::TokioIo; -use crate::io::paginated_kv_store::PaginatedKVStore; -use crate::io::sqlite_store::SqliteStore; -use crate::io::{ +use crate::io::persist::paginated_kv_store::PaginatedKVStore; +use crate::io::persist::sqlite_store::SqliteStore; +use crate::io::persist::{ FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index b3719ee2c..3543f9f30 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -30,7 +30,7 @@ use crate::api::open_channel::{handle_open_channel, OPEN_CHANNEL_PATH}; use crate::api::update_channel_config::{ handle_update_channel_config_request, UPDATE_CHANNEL_CONFIG_PATH, }; -use crate::io::paginated_kv_store::PaginatedKVStore; +use crate::io::persist::paginated_kv_store::PaginatedKVStore; use crate::util::proto_adapter::to_error_response; use std::future::Future; use std::pin::Pin; From 699f592874d6a053f38a15f41cda2d72b63fc878 Mon Sep 17 00:00:00 2001 From: elnosh Date: Sat, 15 Mar 2025 10:33:18 -0500 Subject: [PATCH 132/203] Remove description_hash short arg in CLI receive command --- ldk-server/ldk-server-cli/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index d76ba8820..7ebd5e94b 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -42,7 +42,7 @@ enum Commands { Bolt11Receive { #[arg(short, long)] description: Option, - #[arg(short, long)] + #[arg(long)] description_hash: Option, #[arg(short, long)] expiry_secs: u32, From 22d63250277a857a771813194a8bf164b24dac82 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:45:02 -0700 Subject: [PATCH 133/203] Add basic structure for defining different events. --- ldk-server/ldk-server-protos/build.rs | 9 +++++++- ldk-server/ldk-server-protos/src/events.rs | 23 +++++++++++++++++++ ldk-server/ldk-server-protos/src/lib.rs | 1 + .../ldk-server-protos/src/proto/events.proto | 15 ++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 ldk-server/ldk-server-protos/src/events.rs create mode 100644 ldk-server/ldk-server-protos/src/proto/events.proto diff --git a/ldk-server/ldk-server-protos/build.rs b/ldk-server/ldk-server-protos/build.rs index 3d8ce462a..76eb77a2e 100644 --- a/ldk-server/ldk-server-protos/build.rs +++ b/ldk-server/ldk-server-protos/build.rs @@ -15,7 +15,12 @@ fn generate_protos() { prost_build::Config::new() .bytes(&["."]) .compile_protos( - &["src/proto/api.proto", "src/proto/types.proto", "src/proto/error.proto"], + &[ + "src/proto/api.proto", + "src/proto/types.proto", + "src/proto/events.proto", + "src/proto/error.proto", + ], &["src/proto/"], ) .expect("protobuf compilation failed"); @@ -24,6 +29,8 @@ fn generate_protos() { fs::copy(from_path, "src/api.rs").unwrap(); let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("types.rs"); fs::copy(from_path, "src/types.rs").unwrap(); + let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("events.rs"); + fs::copy(from_path, "src/events.rs").unwrap(); let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("error.rs"); fs::copy(from_path, "src/error.rs").unwrap(); } diff --git a/ldk-server/ldk-server-protos/src/events.rs b/ldk-server/ldk-server-protos/src/events.rs new file mode 100644 index 000000000..d2202e7d0 --- /dev/null +++ b/ldk-server/ldk-server-protos/src/events.rs @@ -0,0 +1,23 @@ +/// EventEnvelope wraps different event types in a single message to be used by EventPublisher. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EventEnvelope { + #[prost(oneof = "event_envelope::Event", tags = "2")] + pub event: ::core::option::Option, +} +/// Nested message and enum types in `EventEnvelope`. +pub mod event_envelope { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Event { + #[prost(message, tag = "2")] + PaymentForwarded(super::PaymentForwarded), + } +} +/// PaymentForwarded indicates a payment was forwarded through the node. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PaymentForwarded { + #[prost(message, optional, tag = "1")] + pub forwarded_payment: ::core::option::Option, +} diff --git a/ldk-server/ldk-server-protos/src/lib.rs b/ldk-server/ldk-server-protos/src/lib.rs index d66938372..e69faeaf7 100644 --- a/ldk-server/ldk-server-protos/src/lib.rs +++ b/ldk-server/ldk-server-protos/src/lib.rs @@ -1,3 +1,4 @@ pub mod api; pub mod error; +pub mod events; pub mod types; diff --git a/ldk-server/ldk-server-protos/src/proto/events.proto b/ldk-server/ldk-server-protos/src/proto/events.proto new file mode 100644 index 000000000..30dafe47a --- /dev/null +++ b/ldk-server/ldk-server-protos/src/proto/events.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; +import "types.proto"; +package events; + +// EventEnvelope wraps different event types in a single message to be used by EventPublisher. +message EventEnvelope { + oneof event { + PaymentForwarded payment_forwarded = 2; + } +} + +// PaymentForwarded indicates a payment was forwarded through the node. +message PaymentForwarded { + types.ForwardedPayment forwarded_payment = 1; +} From 703dbeebf54fdf3a3301cbaa0f201e6efce0e571 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 12 Mar 2025 12:59:11 -0700 Subject: [PATCH 134/203] Introduce EventPublisher trait. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LDK Server needs a flexible and reliable mechanism to publish informational events (e.g., transaction updates, channel status changes) to external messaging systems to integration with other external services in a decoupled manner. To achieve this, we introduce the EventPublisher trait, which defines a consistent, asynchronous interface for event publishing. This allows the daemon to support multiple messaging backends (e.g., RabbitMQ, Kafka, AWS SQS) via feature flags. Since underlying messaging systems are expected to support durable buffering, this keeps the LDK Server decoupled from event storage and handling, while enabling multiple consumers to process events independently. This is in contrast with in-memory event queues, polling, or WebSockets, since they either lack durability, tightly couple the daemon to consumers, or require constant connectivity. In-memory queues risk losing events on restart, polling burdens the daemon with service calls from each consumer, and WebSockets demand real-time client availability—none of which support multiple consumers efficiently. --- ldk-server/Cargo.lock | 1 + ldk-server/ldk-server/Cargo.toml | 1 + .../src/io/events/event_publisher.rs | 42 +++++++++++++++++++ ldk-server/ldk-server/src/io/events/mod.rs | 1 + ldk-server/ldk-server/src/io/mod.rs | 1 + 5 files changed, 46 insertions(+) create mode 100644 ldk-server/ldk-server/src/io/events/event_publisher.rs create mode 100644 ldk-server/ldk-server/src/io/events/mod.rs diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 0d862daf3..b8798a971 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -1093,6 +1093,7 @@ dependencies = [ name = "ldk-server" version = "0.1.0" dependencies = [ + "async-trait", "bytes", "hex-conservative 0.2.1", "http-body-util", diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index e7705f6bc..25ad7f9cb 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -17,3 +17,4 @@ bytes = { version = "1.4.0", default-features = false } hex = { package = "hex-conservative", version = "0.2.1", default-features = false } rusqlite = { version = "0.31.0", features = ["bundled"] } rand = { version = "0.8.5", default-features = false } +async-trait = { version = "0.1.85", default-features = false } diff --git a/ldk-server/ldk-server/src/io/events/event_publisher.rs b/ldk-server/ldk-server/src/io/events/event_publisher.rs new file mode 100644 index 000000000..2ba6c6e89 --- /dev/null +++ b/ldk-server/ldk-server/src/io/events/event_publisher.rs @@ -0,0 +1,42 @@ +use crate::api::error::LdkServerError; +use async_trait::async_trait; +use ldk_server_protos::events::EventEnvelope; + +/// A trait for publishing events or notifications from the LDK Server. +/// +/// Implementors of this trait define how events are sent to various messaging +/// systems. It provides a consistent, asynchronous interface for event publishing, while allowing +/// each implementation to manage its own initialization and configuration, typically sourced from +/// the `ldk-server.config` file. A no-op implementation is included by default, +/// with specific implementations enabled via feature flags. +/// +/// Events are represented as [`EventEnvelope`] messages, which are Protocol Buffers +/// ([protobuf](https://protobuf.dev/)) objects defined in [`ldk_server_protos::events`]. +/// These events are serialized to bytes by the publisher before transmission, and consumers can +/// deserialize them using the protobuf definitions. +/// +/// The underlying messaging system is expected to support durably buffered events, +/// enabling easy decoupling between the LDK Server and event consumers. +#[async_trait] +pub trait EventPublisher { + /// Publishes an event to the underlying messaging system. + /// + /// # Arguments + /// * `event` - The event message to publish, provided as an [`EventEnvelope`] + /// defined in [`ldk_server_protos::events`]. Implementors must serialize + /// the whole [`EventEnvelope`] to bytes before publishing. + /// + /// In order to ensure no events are lost, implementors of this trait must publish events + /// durably to underlying messaging system. An event is considered published when + /// [`EventPublisher::publish`] returns `Ok(())`, thus implementors MUST durably persist/publish events *before* + /// returning `Ok(())`. + /// + /// # Errors + /// May return an [`LdkServerErrorCode::InternalServerError`] if the event cannot be published, + /// such as due to network failures, misconfiguration, or transport-specific issues. + /// If event publishing fails, the LDK Server will retry publishing the event indefinitely, which + /// may degrade performance until the underlying messaging system is operational again. + /// + /// [`LdkServerErrorCode::InternalServerError`]: crate::api::error::LdkServerErrorCode + async fn publish(&self, event: EventEnvelope) -> Result<(), LdkServerError>; +} diff --git a/ldk-server/ldk-server/src/io/events/mod.rs b/ldk-server/ldk-server/src/io/events/mod.rs new file mode 100644 index 000000000..33eb8c5e5 --- /dev/null +++ b/ldk-server/ldk-server/src/io/events/mod.rs @@ -0,0 +1 @@ +pub(crate) mod event_publisher; diff --git a/ldk-server/ldk-server/src/io/mod.rs b/ldk-server/ldk-server/src/io/mod.rs index 22c58bb74..8b022008e 100644 --- a/ldk-server/ldk-server/src/io/mod.rs +++ b/ldk-server/ldk-server/src/io/mod.rs @@ -1,2 +1,3 @@ +pub(crate) mod events; pub(crate) mod persist; pub(crate) mod utils; From 7bd1221907a2f1436f25a268360640205f192950 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 12 Mar 2025 13:00:07 -0700 Subject: [PATCH 135/203] Add NoopEventPublisher, which will be used as default impl. Introduces a NoopEventPublisher that implements the EventPublisher trait, but performs no actions when publishing events. It will serve as a convenient default implementation for scenarios where no real event publishing mechanism is required, reducing the burden on developers to provide an explicit publisher in all cases. --- .../ldk-server/src/io/events/event_publisher.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ldk-server/ldk-server/src/io/events/event_publisher.rs b/ldk-server/ldk-server/src/io/events/event_publisher.rs index 2ba6c6e89..83ba90380 100644 --- a/ldk-server/ldk-server/src/io/events/event_publisher.rs +++ b/ldk-server/ldk-server/src/io/events/event_publisher.rs @@ -40,3 +40,16 @@ pub trait EventPublisher { /// [`LdkServerErrorCode::InternalServerError`]: crate::api::error::LdkServerErrorCode async fn publish(&self, event: EventEnvelope) -> Result<(), LdkServerError>; } + +pub(crate) struct NoopEventPublisher; + +#[async_trait] +impl EventPublisher for NoopEventPublisher { + /// Publishes an event to a no-op sink, effectively discarding it. + /// + /// This implementation does nothing and always returns `Ok(())`, serving as a + /// default when no messaging system is configured. + async fn publish(&self, _event: EventEnvelope) -> Result<(), LdkServerError> { + Ok(()) + } +} From 73bb8420707dc11f049beffbcba08bd652821195 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Wed, 12 Mar 2025 15:07:02 -0700 Subject: [PATCH 136/203] Start publishing events using EventPublisher. For now, we publish only `PaymentForwarded` event, but similar mechanism will be used to publish other event types. --- ldk-server/ldk-server/src/main.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index c084cdf3f..abea93569 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -13,6 +13,7 @@ use tokio::signal::unix::SignalKind; use hyper::server::conn::http1; use hyper_util::rt::TokioIo; +use crate::io::events::event_publisher::{EventPublisher, NoopEventPublisher}; use crate::io::persist::paginated_kv_store::PaginatedKVStore; use crate::io::persist::sqlite_store::SqliteStore; use crate::io::persist::{ @@ -26,6 +27,8 @@ use hex::DisplayHex; use ldk_node::config::Config; use ldk_node::lightning::ln::channelmanager::PaymentId; use ldk_node::logger::LogLevel; +use ldk_server_protos::events; +use ldk_server_protos::events::{event_envelope, EventEnvelope}; use prost::Message; use rand::Rng; use std::fs; @@ -98,6 +101,8 @@ fn main() { }, }); + let event_publisher: Arc = Arc::new(NoopEventPublisher); + println!("Starting up..."); match node.start_with_runtime(Arc::clone(&runtime)) { Ok(()) => {}, @@ -200,6 +205,18 @@ fn main() { let forwarded_payment_creation_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs() as i64; + match event_publisher.publish(EventEnvelope { + event: Some(event_envelope::Event::PaymentForwarded(events::PaymentForwarded { + forwarded_payment: Some(forwarded_payment.clone()), + })), + }).await { + Ok(_) => {}, + Err(e) => { + println!("Failed to publish 'PaymentForwarded' event: {}", e); + continue; + } + }; + match paginated_store.write(FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE,FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, &forwarded_payment_id.to_lower_hex_string(), forwarded_payment_creation_time, From 52980044e41d6672ca6ccd41e62bdf48436bd860 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 18 Mar 2025 13:00:02 -0700 Subject: [PATCH 137/203] Consistently use UserChannelId as String. --- ldk-server/ldk-server-protos/src/api.rs | 14 +++++++------- ldk-server/ldk-server-protos/src/proto/api.proto | 10 +++++----- ldk-server/ldk-server/src/api/close_channel.rs | 8 ++++---- ldk-server/ldk-server/src/api/open_channel.rs | 5 +---- .../ldk-server/src/api/update_channel_config.rs | 7 ++++--- 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index 795ce9e66..c19249c60 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -245,16 +245,16 @@ pub struct OpenChannelRequest { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OpenChannelResponse { - /// The channel id of the created channel that user can use to refer to channel. - #[prost(bytes = "bytes", tag = "1")] - pub user_channel_id: ::prost::bytes::Bytes, + /// The local channel id of the created channel that user can use to refer to channel. + #[prost(string, tag = "1")] + pub user_channel_id: ::prost::alloc::string::String, } /// Update the config for a previously opened channel. /// See more: #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct UpdateChannelConfigRequest { - /// The hex-encoded local `user_channel_id` of this channel. + /// The local `user_channel_id` of this channel. #[prost(string, tag = "1")] pub user_channel_id: ::prost::alloc::string::String, /// The hex-encoded public key of the counterparty node to update channel config with. @@ -276,9 +276,9 @@ pub struct UpdateChannelConfigResponse {} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CloseChannelRequest { - /// The channel id of the created channel that user can use to refer to channel. - #[prost(bytes = "bytes", tag = "1")] - pub user_channel_id: ::prost::bytes::Bytes, + /// The local `user_channel_id` of this channel. + #[prost(string, tag = "1")] + pub user_channel_id: ::prost::alloc::string::String, /// The hex-encoded public key of the node to close a channel with. #[prost(string, tag = "2")] pub counterparty_node_id: ::prost::alloc::string::String, diff --git a/ldk-server/ldk-server-protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto index f0f523e21..62f8151f3 100644 --- a/ldk-server/ldk-server-protos/src/proto/api.proto +++ b/ldk-server/ldk-server-protos/src/proto/api.proto @@ -237,15 +237,15 @@ message OpenChannelRequest { // When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message OpenChannelResponse { - // The channel id of the created channel that user can use to refer to channel. - bytes user_channel_id = 1; + // The local channel id of the created channel that user can use to refer to channel. + string user_channel_id = 1; } // Update the config for a previously opened channel. // See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.update_channel_config message UpdateChannelConfigRequest { - // The hex-encoded local `user_channel_id` of this channel. + // The local `user_channel_id` of this channel. string user_channel_id = 1; // The hex-encoded public key of the counterparty node to update channel config with. @@ -266,8 +266,8 @@ message UpdateChannelConfigResponse { // - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.force_close_channel message CloseChannelRequest { - // The channel id of the created channel that user can use to refer to channel. - bytes user_channel_id = 1; + // The local `user_channel_id` of this channel. + string user_channel_id = 1; // The hex-encoded public key of the node to close a channel with. string counterparty_node_id = 2; diff --git a/ldk-server/ldk-server/src/api/close_channel.rs b/ldk-server/ldk-server/src/api/close_channel.rs index 6d7436e42..95054a454 100644 --- a/ldk-server/ldk-server/src/api/close_channel.rs +++ b/ldk-server/ldk-server/src/api/close_channel.rs @@ -11,10 +11,10 @@ pub(crate) const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; pub(crate) fn handle_close_channel_request( context: Context, request: CloseChannelRequest, ) -> Result { - //TODO: Should this be string? - let mut user_channel_id_bytes = [0u8; 16]; - user_channel_id_bytes.copy_from_slice(&request.user_channel_id); - let user_channel_id = UserChannelId(u128::from_be_bytes(user_channel_id_bytes)); + let user_channel_id = + UserChannelId((&request.user_channel_id).parse::().map_err(|_| { + LdkServerError::new(InvalidRequestError, "Invalid UserChannelId.".to_string()) + })?); let counterparty_node_id = PublicKey::from_str(&request.counterparty_node_id).map_err(|e| { LdkServerError::new( InvalidRequestError, diff --git a/ldk-server/ldk-server/src/api/open_channel.rs b/ldk-server/ldk-server/src/api/open_channel.rs index 3258d61a4..96fdbf2fc 100644 --- a/ldk-server/ldk-server/src/api/open_channel.rs +++ b/ldk-server/ldk-server/src/api/open_channel.rs @@ -1,6 +1,5 @@ use crate::api::error::LdkServerError; use crate::service::Context; -use bytes::Bytes; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_server_protos::api::{OpenChannelRequest, OpenChannelResponse}; @@ -35,8 +34,6 @@ pub(crate) fn handle_open_channel( )? }; - let response = OpenChannelResponse { - user_channel_id: Bytes::from(user_channel_id.0.to_be_bytes().to_vec()), - }; + let response = OpenChannelResponse { user_channel_id: user_channel_id.0.to_string() }; Ok(response) } diff --git a/ldk-server/ldk-server/src/api/update_channel_config.rs b/ldk-server/ldk-server/src/api/update_channel_config.rs index 73f278664..2a01a54b1 100644 --- a/ldk-server/ldk-server/src/api/update_channel_config.rs +++ b/ldk-server/ldk-server/src/api/update_channel_config.rs @@ -13,9 +13,10 @@ pub(crate) const UPDATE_CHANNEL_CONFIG_PATH: &str = "UpdateChannelConfig"; pub(crate) fn handle_update_channel_config_request( context: Context, request: UpdateChannelConfigRequest, ) -> Result { - let user_channel_id: u128 = request.user_channel_id.parse().map_err(|_| { - LdkServerError::new(InvalidRequestError, "Failed to parse user_channel_id: invalid format.") - })?; + let user_channel_id: u128 = request + .user_channel_id + .parse::() + .map_err(|_| LdkServerError::new(InvalidRequestError, "Invalid UserChannelId."))?; //FIXME: Use ldk/ldk-node's partial config update api. let current_config = context From 55b84928fa4ae9fe4fd298a0f411fb8936703ad6 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 18 Mar 2025 13:07:27 -0700 Subject: [PATCH 138/203] Consistently use PaymentId as hex-string. --- ldk-server/ldk-server-protos/src/api.rs | 12 ++++++------ ldk-server/ldk-server-protos/src/proto/api.proto | 8 ++++---- ldk-server/ldk-server/src/api/bolt11_send.rs | 3 +-- ldk-server/ldk-server/src/api/bolt12_send.rs | 3 +-- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index c19249c60..770cbc307 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -147,9 +147,9 @@ pub struct Bolt11SendRequest { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Bolt11SendResponse { - /// An identifier used to uniquely identify a payment. - #[prost(bytes = "bytes", tag = "1")] - pub payment_id: ::prost::bytes::Bytes, + /// An identifier used to uniquely identify a payment in hex-encoded form. + #[prost(string, tag = "1")] + pub payment_id: ::prost::alloc::string::String, } /// Returns a BOLT12 offer for the given amount, if specified. /// @@ -211,9 +211,9 @@ pub struct Bolt12SendRequest { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Bolt12SendResponse { - /// An identifier used to uniquely identify a payment. - #[prost(bytes = "bytes", tag = "1")] - pub payment_id: ::prost::bytes::Bytes, + /// An identifier used to uniquely identify a payment in hex-encoded form. + #[prost(string, tag = "1")] + pub payment_id: ::prost::alloc::string::String, } /// Creates a new outbound channel to the given remote node. /// See more: diff --git a/ldk-server/ldk-server-protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto index 62f8151f3..9f61ba938 100644 --- a/ldk-server/ldk-server-protos/src/proto/api.proto +++ b/ldk-server/ldk-server-protos/src/proto/api.proto @@ -145,8 +145,8 @@ message Bolt11SendRequest { // When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message Bolt11SendResponse { - // An identifier used to uniquely identify a payment. - bytes payment_id = 1; + // An identifier used to uniquely identify a payment in hex-encoded form. + string payment_id = 1; } // Returns a BOLT12 offer for the given amount, if specified. @@ -205,8 +205,8 @@ message Bolt12SendRequest { // When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message Bolt12SendResponse { - // An identifier used to uniquely identify a payment. - bytes payment_id = 1; + // An identifier used to uniquely identify a payment in hex-encoded form. + string payment_id = 1; } // Creates a new outbound channel to the given remote node. diff --git a/ldk-server/ldk-server/src/api/bolt11_send.rs b/ldk-server/ldk-server/src/api/bolt11_send.rs index 7b12483dc..6a1314345 100644 --- a/ldk-server/ldk-server/src/api/bolt11_send.rs +++ b/ldk-server/ldk-server/src/api/bolt11_send.rs @@ -1,6 +1,5 @@ use crate::api::error::LdkServerError; use crate::service::Context; -use bytes::Bytes; use ldk_node::lightning_invoice::Bolt11Invoice; use ldk_server_protos::api::{Bolt11SendRequest, Bolt11SendResponse}; use std::str::FromStr; @@ -20,6 +19,6 @@ pub(crate) fn handle_bolt11_send_request( }, }?; - let response = Bolt11SendResponse { payment_id: Bytes::from(payment_id.0.to_vec()) }; + let response = Bolt11SendResponse { payment_id: payment_id.to_string() }; Ok(response) } diff --git a/ldk-server/ldk-server/src/api/bolt12_send.rs b/ldk-server/ldk-server/src/api/bolt12_send.rs index d3ff75483..ed1dea503 100644 --- a/ldk-server/ldk-server/src/api/bolt12_send.rs +++ b/ldk-server/ldk-server/src/api/bolt12_send.rs @@ -1,6 +1,5 @@ use crate::api::error::LdkServerError; use crate::service::Context; -use bytes::Bytes; use ldk_node::lightning::offers::offer::Offer; use ldk_server_protos::api::{Bolt12SendRequest, Bolt12SendResponse}; use std::str::FromStr; @@ -23,6 +22,6 @@ pub(crate) fn handle_bolt12_send_request( ), }?; - let response = Bolt12SendResponse { payment_id: Bytes::from(payment_id.0.to_vec()) }; + let response = Bolt12SendResponse { payment_id: payment_id.to_string() }; Ok(response) } From fc4e4d8aa6b00db1597e082c5fd0ad9359a8320d Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 20 Mar 2025 12:41:46 -0700 Subject: [PATCH 139/203] Upgrade ldk-node to latest commit. --- ldk-server/Cargo.lock | 2 +- ldk-server/ldk-server/Cargo.toml | 2 +- ldk-server/ldk-server/src/main.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index b8798a971..b69a5829c 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -1055,7 +1055,7 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "ldk-node" version = "0.5.0+git" -source = "git+https://github.com/lightningdevkit/ldk-node.git?rev=6de350040e0fc5eb9cfcd15fad3919f5a79b82b9#6de350040e0fc5eb9cfcd15fad3919f5a79b82b9" +source = "git+https://github.com/lightningdevkit/ldk-node.git?rev=f0338d19256615088fabab2b6927d478ae3ec1a1#f0338d19256615088fabab2b6927d478ae3ec1a1" dependencies = [ "base64 0.22.1", "bdk_chain", diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index 25ad7f9cb..d5b74992f 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -ldk-node = { git = "https://github.com/lightningdevkit/ldk-node.git", rev = "6de350040e0fc5eb9cfcd15fad3919f5a79b82b9" } +ldk-node = { git = "https://github.com/lightningdevkit/ldk-node.git", rev = "f0338d19256615088fabab2b6927d478ae3ec1a1" } serde = { version = "1.0.203", default-features = false, features = ["derive"] } serde_json = { version = "1.0.118", default-features = false } hyper = { version = "1", default-features = false, features = ["server", "http1"] } diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index abea93569..9c2480ff9 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -65,7 +65,7 @@ fn main() { ldk_node_config.network = config_file.network; let mut builder = Builder::from_config(ldk_node_config); - builder.set_log_facade_logger(Some(LogLevel::Trace)); + builder.set_log_facade_logger(); let bitcoind_rpc_addr = config_file.bitcoind_rpc_addr; From 7ae24b152843d6038cb7a1acb10b27824f99395b Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 18 Mar 2025 15:59:27 -0700 Subject: [PATCH 140/203] Add Send+Sync trait bounds for PaginatedKVStore. --- .../ldk-server/src/io/persist/paginated_kv_store.rs | 2 +- ldk-server/ldk-server/src/main.rs | 4 ++-- ldk-server/ldk-server/src/service.rs | 8 +++----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs b/ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs index 28c4ad19f..d036c2ef7 100644 --- a/ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs +++ b/ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs @@ -26,7 +26,7 @@ use std::io; /// [`KVStore`]: ldk_node::lightning::util::persist::KVStore /// [`KVSTORE_NAMESPACE_KEY_ALPHABET`]: ldk_node::lightning::util::persist::KVSTORE_NAMESPACE_KEY_ALPHABET /// [`KVSTORE_NAMESPACE_KEY_MAX_LEN`]: ldk_node::lightning::util::persist::KVSTORE_NAMESPACE_KEY_MAX_LEN -pub trait PaginatedKVStore { +pub trait PaginatedKVStore: Send + Sync { /// Returns the data stored for the given `primary_namespace`, `secondary_namespace`, and `key`. /// /// Returns an [`ErrorKind::NotFound`] if the given `key` could not be found in the given diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index abea93569..bd90b4894 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -92,7 +92,7 @@ fn main() { }, }; - let paginated_store = + let paginated_store: Arc = Arc::new(match SqliteStore::new(PathBuf::from(config_file.storage_dir_path), None, None) { Ok(store) => store, Err(e) => { @@ -240,7 +240,7 @@ fn main() { match res { Ok((stream, _)) => { let io_stream = TokioIo::new(stream); - let node_service = NodeService::new(Arc::clone(&node), Arc::clone(&paginated_store) as Arc); + let node_service = NodeService::new(Arc::clone(&node), Arc::clone(&paginated_store)); runtime.spawn(async move { if let Err(err) = http1::Builder::new().serve_connection(io_stream, node_service).await { eprintln!("Failed to serve connection: {}", err); diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index 3543f9f30..328ded0c2 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -39,20 +39,18 @@ use std::sync::Arc; #[derive(Clone)] pub struct NodeService { node: Arc, - paginated_kv_store: Arc, + paginated_kv_store: Arc, } impl NodeService { - pub(crate) fn new( - node: Arc, paginated_kv_store: Arc, - ) -> Self { + pub(crate) fn new(node: Arc, paginated_kv_store: Arc) -> Self { Self { node, paginated_kv_store } } } pub(crate) struct Context { pub(crate) node: Arc, - pub(crate) paginated_kv_store: Arc, + pub(crate) paginated_kv_store: Arc, } impl Service> for NodeService { From db8922b8f3e62673ff38d4f362a7390e424653bd Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 18 Mar 2025 15:59:48 -0700 Subject: [PATCH 141/203] Add Send+Sync trait bounds for EventPublisher. --- ldk-server/ldk-server/src/io/events/event_publisher.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/io/events/event_publisher.rs b/ldk-server/ldk-server/src/io/events/event_publisher.rs index 83ba90380..f333bb310 100644 --- a/ldk-server/ldk-server/src/io/events/event_publisher.rs +++ b/ldk-server/ldk-server/src/io/events/event_publisher.rs @@ -18,7 +18,7 @@ use ldk_server_protos::events::EventEnvelope; /// The underlying messaging system is expected to support durably buffered events, /// enabling easy decoupling between the LDK Server and event consumers. #[async_trait] -pub trait EventPublisher { +pub trait EventPublisher: Send + Sync { /// Publishes an event to the underlying messaging system. /// /// # Arguments From c893b8fb5011e7516b36e5adb155c273568be011 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Mon, 17 Mar 2025 14:36:02 -0700 Subject: [PATCH 142/203] Add event types for PaymentReceived, PaymentSuccessful & PaymentFailed. --- ldk-server/ldk-server-protos/src/events.rs | 32 ++++++++++++++++++- .../ldk-server-protos/src/proto/events.proto | 23 ++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/ldk-server/ldk-server-protos/src/events.rs b/ldk-server/ldk-server-protos/src/events.rs index d2202e7d0..a9e9000aa 100644 --- a/ldk-server/ldk-server-protos/src/events.rs +++ b/ldk-server/ldk-server-protos/src/events.rs @@ -2,7 +2,7 @@ #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EventEnvelope { - #[prost(oneof = "event_envelope::Event", tags = "2")] + #[prost(oneof = "event_envelope::Event", tags = "2, 3, 4, 6")] pub event: ::core::option::Option, } /// Nested message and enum types in `EventEnvelope`. @@ -11,9 +11,39 @@ pub mod event_envelope { #[derive(Clone, PartialEq, ::prost::Oneof)] pub enum Event { #[prost(message, tag = "2")] + PaymentReceived(super::PaymentReceived), + #[prost(message, tag = "3")] + PaymentSuccessful(super::PaymentSuccessful), + #[prost(message, tag = "4")] + PaymentFailed(super::PaymentFailed), + #[prost(message, tag = "6")] PaymentForwarded(super::PaymentForwarded), } } +/// PaymentReceived indicates a payment has been received. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PaymentReceived { + /// The payment details for the payment in event. + #[prost(message, optional, tag = "1")] + pub payment: ::core::option::Option, +} +/// PaymentSuccessful indicates a sent payment was successful. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PaymentSuccessful { + /// The payment details for the payment in event. + #[prost(message, optional, tag = "1")] + pub payment: ::core::option::Option, +} +/// PaymentFailed indicates a sent payment has failed. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PaymentFailed { + /// The payment details for the payment in event. + #[prost(message, optional, tag = "1")] + pub payment: ::core::option::Option, +} /// PaymentForwarded indicates a payment was forwarded through the node. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/ldk-server/ldk-server-protos/src/proto/events.proto b/ldk-server/ldk-server-protos/src/proto/events.proto index 30dafe47a..19d2f5c8d 100644 --- a/ldk-server/ldk-server-protos/src/proto/events.proto +++ b/ldk-server/ldk-server-protos/src/proto/events.proto @@ -5,10 +5,31 @@ package events; // EventEnvelope wraps different event types in a single message to be used by EventPublisher. message EventEnvelope { oneof event { - PaymentForwarded payment_forwarded = 2; + PaymentReceived payment_received = 2; + PaymentSuccessful payment_successful = 3; + PaymentFailed payment_failed = 4; + PaymentForwarded payment_forwarded = 6; } } +// PaymentReceived indicates a payment has been received. +message PaymentReceived { + // The payment details for the payment in event. + types.Payment payment = 1; +} + +// PaymentSuccessful indicates a sent payment was successful. +message PaymentSuccessful { + // The payment details for the payment in event. + types.Payment payment = 1; +} + +// PaymentFailed indicates a sent payment has failed. +message PaymentFailed { + // The payment details for the payment in event. + types.Payment payment = 1; +} + // PaymentForwarded indicates a payment was forwarded through the node. message PaymentForwarded { types.ForwardedPayment forwarded_payment = 1; From afad40d1b074dd0c3c2c1ffe8e7c62fb634bb597 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 18 Mar 2025 16:22:41 -0700 Subject: [PATCH 143/203] Start publishing more payment events using EventPublisher. --- ldk-server/ldk-server/src/io/events/mod.rs | 12 +++ ldk-server/ldk-server/src/main.rs | 98 ++++++++++++++++------ 2 files changed, 84 insertions(+), 26 deletions(-) diff --git a/ldk-server/ldk-server/src/io/events/mod.rs b/ldk-server/ldk-server/src/io/events/mod.rs index 33eb8c5e5..d49bffd75 100644 --- a/ldk-server/ldk-server/src/io/events/mod.rs +++ b/ldk-server/ldk-server/src/io/events/mod.rs @@ -1 +1,13 @@ pub(crate) mod event_publisher; + +use ldk_server_protos::events::event_envelope; + +/// Event variant to event name mapping. +pub(crate) fn get_event_name(event: &event_envelope::Event) -> &'static str { + match event { + event_envelope::Event::PaymentReceived(_) => "PaymentReceived", + event_envelope::Event::PaymentSuccessful(_) => "PaymentSuccessful", + event_envelope::Event::PaymentFailed(_) => "PaymentFailed", + event_envelope::Event::PaymentForwarded(_) => "PaymentForwarded", + } +} diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index bd90b4894..f17a7b0f3 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -14,6 +14,7 @@ use hyper::server::conn::http1; use hyper_util::rt::TokioIo; use crate::io::events::event_publisher::{EventPublisher, NoopEventPublisher}; +use crate::io::events::get_event_name; use crate::io::persist::paginated_kv_store::PaginatedKVStore; use crate::io::persist::sqlite_store::SqliteStore; use crate::io::persist::{ @@ -29,12 +30,14 @@ use ldk_node::lightning::ln::channelmanager::PaymentId; use ldk_node::logger::LogLevel; use ldk_server_protos::events; use ldk_server_protos::events::{event_envelope, EventEnvelope}; +use ldk_server_protos::types::Payment; use prost::Message; use rand::Rng; use std::fs; use std::path::{Path, PathBuf}; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; +use tokio::select; const USAGE_GUIDE: &str = "Usage: ldk-server "; @@ -124,14 +127,14 @@ fn main() { Err(e) => { println!("Failed to register for SIGTERM stream: {}", e); std::process::exit(-1); - }, + } }; let event_node = Arc::clone(&node); let rest_svc_listener = TcpListener::bind(config_file.rest_service_addr) .await .expect("Failed to bind listening port"); loop { - tokio::select! { + select! { event = event_node.next_event_async() => { match event { Event::ChannelPending { channel_id, counterparty_node_id, .. } => { @@ -154,18 +157,44 @@ fn main() { payment_id, payment_hash, amount_msat ); let payment_id = payment_id.expect("PaymentId expected for ldk-server >=0.1"); - upsert_payment_details(&event_node, Arc::clone(&paginated_store) as Arc, &payment_id); + + publish_event_and_upsert_payment(&payment_id, + |payment_ref| event_envelope::Event::PaymentReceived(events::PaymentReceived { + payment: Some(payment_ref.clone()), + }), + &event_node, + Arc::clone(&event_publisher), + Arc::clone(&paginated_store)).await; }, Event::PaymentSuccessful {payment_id, ..} => { let payment_id = payment_id.expect("PaymentId expected for ldk-server >=0.1"); - upsert_payment_details(&event_node, Arc::clone(&paginated_store) as Arc, &payment_id); + + publish_event_and_upsert_payment(&payment_id, + |payment_ref| event_envelope::Event::PaymentSuccessful(events::PaymentSuccessful { + payment: Some(payment_ref.clone()), + }), + &event_node, + Arc::clone(&event_publisher), + Arc::clone(&paginated_store)).await; }, Event::PaymentFailed {payment_id, ..} => { let payment_id = payment_id.expect("PaymentId expected for ldk-server >=0.1"); - upsert_payment_details(&event_node, Arc::clone(&paginated_store) as Arc, &payment_id); + + publish_event_and_upsert_payment(&payment_id, + |payment_ref| event_envelope::Event::PaymentFailed(events::PaymentFailed { + payment: Some(payment_ref.clone()), + }), + &event_node, + Arc::clone(&event_publisher), + Arc::clone(&paginated_store)).await; }, Event::PaymentClaimable {payment_id, ..} => { - upsert_payment_details(&event_node, Arc::clone(&paginated_store) as Arc, &payment_id); + if let Some(payment_details) = event_node.payment(&payment_id) { + let payment = payment_to_proto(payment_details); + upsert_payment_details(&event_node, Arc::clone(&paginated_store), &payment); + } else { + eprintln!("Unable to find payment with paymentId: {}", payment_id.to_string()); + } }, Event::PaymentForwarded { prev_channel_id, @@ -234,7 +263,6 @@ fn main() { event_node.event_handled(); }, } - }, res = rest_svc_listener.accept() => { match res { @@ -266,30 +294,48 @@ fn main() { println!("Shutdown complete.."); } -fn upsert_payment_details( - event_node: &Node, paginated_store: Arc, payment_id: &PaymentId, +async fn publish_event_and_upsert_payment( + payment_id: &PaymentId, payment_to_event: fn(&Payment) -> event_envelope::Event, + event_node: &Node, event_publisher: Arc, + paginated_store: Arc, ) { if let Some(payment_details) = event_node.payment(payment_id) { let payment = payment_to_proto(payment_details); - let time = - SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs() - as i64; - - match paginated_store.write( - PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, - PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, - &payment_id.0.to_lower_hex_string(), - time, - &payment.encode_to_vec(), - ) { - Ok(_) => { - event_node.event_handled(); - }, + + let event = payment_to_event(&payment); + let event_name = get_event_name(&event); + match event_publisher.publish(EventEnvelope { event: Some(event) }).await { + Ok(_) => {}, Err(e) => { - eprintln!("Failed to write payment to persistence: {}", e); + println!("Failed to publish '{}' event, : {}", event_name, e); + return; }, - } + }; + + upsert_payment_details(event_node, Arc::clone(&paginated_store), &payment); } else { - eprintln!("Unable to find payment with paymentId: {}", payment_id.0.to_lower_hex_string()); + eprintln!("Unable to find payment with paymentId: {}", payment_id); + } +} + +fn upsert_payment_details( + event_node: &Node, paginated_store: Arc, payment: &Payment, +) { + let time = + SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs() as i64; + + match paginated_store.write( + PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, + PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, + &payment.id, + time, + &payment.encode_to_vec(), + ) { + Ok(_) => { + event_node.event_handled(); + }, + Err(e) => { + eprintln!("Failed to write payment to persistence: {}", e); + }, } } From 3af239b3b704362b4380acfb1f9cf092e547b236 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 20 Mar 2025 12:59:01 -0700 Subject: [PATCH 144/203] Add `fee_paid_msat` in Payment. --- .../ldk-server-protos/src/proto/types.proto | 6 +++ ldk-server/ldk-server-protos/src/types.rs | 6 +++ .../ldk-server/src/util/proto_adapter.rs | 43 +++++++++++++------ 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/ldk-server/ldk-server-protos/src/proto/types.proto b/ldk-server/ldk-server-protos/src/proto/types.proto index fef697492..e8e23ebe1 100644 --- a/ldk-server/ldk-server-protos/src/proto/types.proto +++ b/ldk-server/ldk-server-protos/src/proto/types.proto @@ -13,6 +13,12 @@ message Payment { // The amount transferred. optional uint64 amount_msat = 3; + // The fees that were paid for this payment. + // + // For Lightning payments, this will only be updated for outbound payments once they + // succeeded. + optional uint64 fee_paid_msat = 7; + // The direction of the payment. PaymentDirection direction = 4; diff --git a/ldk-server/ldk-server-protos/src/types.rs b/ldk-server/ldk-server-protos/src/types.rs index 20f2c6952..9c65fea0e 100644 --- a/ldk-server/ldk-server-protos/src/types.rs +++ b/ldk-server/ldk-server-protos/src/types.rs @@ -12,6 +12,12 @@ pub struct Payment { /// The amount transferred. #[prost(uint64, optional, tag = "3")] pub amount_msat: ::core::option::Option, + /// The fees that were paid for this payment. + /// + /// For Lightning payments, this will only be updated for outbound payments once they + /// succeeded. + #[prost(uint64, optional, tag = "7")] + pub fee_paid_msat: ::core::option::Option, /// The direction of the payment. #[prost(enumeration = "PaymentDirection", tag = "4")] pub direction: i32, diff --git a/ldk-server/ldk-server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs index 6aa2c356f..92dcadaaf 100644 --- a/ldk-server/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -96,22 +96,37 @@ pub(crate) fn channel_config_to_proto( } pub(crate) fn payment_to_proto(payment: PaymentDetails) -> Payment { - Payment { - id: payment.id.0.to_lower_hex_string(), - kind: Some(payment_kind_to_proto(payment.kind)), - amount_msat: payment.amount_msat, - direction: match payment.direction { - PaymentDirection::Inbound => ldk_server_protos::types::PaymentDirection::Inbound.into(), - PaymentDirection::Outbound => { - ldk_server_protos::types::PaymentDirection::Outbound.into() + match payment { + PaymentDetails { + id, + kind, + amount_msat, + fee_paid_msat, + direction, + status, + latest_update_timestamp, + } => Payment { + id: id.to_string(), + kind: Some(payment_kind_to_proto(kind)), + amount_msat, + fee_paid_msat, + direction: match direction { + PaymentDirection::Inbound => { + ldk_server_protos::types::PaymentDirection::Inbound.into() + }, + PaymentDirection::Outbound => { + ldk_server_protos::types::PaymentDirection::Outbound.into() + }, }, + status: match status { + PaymentStatus::Pending => ldk_server_protos::types::PaymentStatus::Pending.into(), + PaymentStatus::Succeeded => { + ldk_server_protos::types::PaymentStatus::Succeeded.into() + }, + PaymentStatus::Failed => ldk_server_protos::types::PaymentStatus::Failed.into(), + }, + latest_update_timestamp, }, - status: match payment.status { - PaymentStatus::Pending => ldk_server_protos::types::PaymentStatus::Pending.into(), - PaymentStatus::Succeeded => ldk_server_protos::types::PaymentStatus::Succeeded.into(), - PaymentStatus::Failed => ldk_server_protos::types::PaymentStatus::Failed.into(), - }, - latest_update_timestamp: payment.latest_update_timestamp, } } From f902060c4ebaccf37cacf12aefaa2031bfdde527 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 13 Mar 2025 00:09:14 -0700 Subject: [PATCH 145/203] Add RabbitMQ based EventPublisher Impl. RabbitMQ was selected because it is one of the most robust and battle-tested open-source messaging systems, allowing for durable, buffered messages and flexible exchange options. This ensures that events are not lost, even in the case of restarts, network failures, or consumer failures, while keeping consumers decoupled. * Feature-based: Only enabled if we enable `events-rabbitmq` feature, this allows us to support multiple implementations and no strict coupling with a single impl while keep our dependencies to the minimum. * Durable Publishing: Uses publisher confirms and persistent delivery mode to guarantee events are stored by RabbitMQ before returning Ok(()). * Lazy Initialized connection: Wraps Connection and Channel in Option for lazy connection init via ensure_connected. * Reconnection Handling: Implements a single reconnect attempt per publish call. Event publishing is already retried, so this keeps it simple for now. --- ldk-server/ldk-server/Cargo.toml | 7 + ldk-server/ldk-server/src/io/events/mod.rs | 3 + .../ldk-server/src/io/events/rabbitmq/mod.rs | 144 ++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index 25ad7f9cb..f59c8b6b0 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -18,3 +18,10 @@ hex = { package = "hex-conservative", version = "0.2.1", default-features = fals rusqlite = { version = "0.31.0", features = ["bundled"] } rand = { version = "0.8.5", default-features = false } async-trait = { version = "0.1.85", default-features = false } + +# Required for RabittMQ based EventPublisher. Only enabled for `events-rabbitmq` feature. +lapin = { version = "2.4.0", features = ["rustls"], default-features = false, optional = true } + +[features] +default = [] +events-rabbitmq = ["dep:lapin"] diff --git a/ldk-server/ldk-server/src/io/events/mod.rs b/ldk-server/ldk-server/src/io/events/mod.rs index d49bffd75..d15753293 100644 --- a/ldk-server/ldk-server/src/io/events/mod.rs +++ b/ldk-server/ldk-server/src/io/events/mod.rs @@ -1,5 +1,8 @@ pub(crate) mod event_publisher; +#[cfg(feature = "events-rabbitmq")] +pub(crate) mod rabbitmq; + use ldk_server_protos::events::event_envelope; /// Event variant to event name mapping. diff --git a/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs b/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs new file mode 100644 index 000000000..a2e1bc220 --- /dev/null +++ b/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs @@ -0,0 +1,144 @@ +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InternalServerError; +use crate::io::events::event_publisher::EventPublisher; +use ::prost::Message; +use async_trait::async_trait; +use lapin::options::{BasicPublishOptions, ConfirmSelectOptions, ExchangeDeclareOptions}; +use lapin::types::FieldTable; +use lapin::{ + BasicProperties, Channel, Connection, ConnectionProperties, ConnectionState, ExchangeKind, +}; +use ldk_server_protos::events::EventEnvelope; +use std::sync::Arc; +use tokio::sync::Mutex; + +/// A RabbitMQ-based implementation of the EventPublisher trait. +pub struct RabbitMqEventPublisher { + /// The RabbitMQ connection, used for reconnection logic. + connection: Arc>>, + /// The RabbitMQ channel used for publishing events. + channel: Arc>>, + /// Configuration details, including connection string and exchange name. + config: RabbitMqConfig, +} + +/// Configuration for the RabbitMQ event publisher. +#[derive(Debug, Clone)] +pub struct RabbitMqConfig { + pub connection_string: String, + pub exchange_name: String, +} + +/// Delivery mode for persistent messages (written to disk). +const DELIVERY_MODE_PERSISTENT: u8 = 2; + +impl RabbitMqEventPublisher { + /// Creates a new RabbitMqEventPublisher instance. + pub fn new(config: RabbitMqConfig) -> Self { + Self { connection: Arc::new(Mutex::new(None)), channel: Arc::new(Mutex::new(None)), config } + } + + async fn connect(config: &RabbitMqConfig) -> Result<(Connection, Channel), LdkServerError> { + let conn = Connection::connect(&config.connection_string, ConnectionProperties::default()) + .await + .map_err(|e| { + LdkServerError::new( + InternalServerError, + format!("Failed to connect to RabbitMQ: {}", e), + ) + })?; + + let channel = conn.create_channel().await.map_err(|e| { + LdkServerError::new(InternalServerError, format!("Failed to create channel: {}", e)) + })?; + + channel.confirm_select(ConfirmSelectOptions::default()).await.map_err(|e| { + LdkServerError::new(InternalServerError, format!("Failed to enable confirms: {}", e)) + })?; + + channel + .exchange_declare( + &config.exchange_name, + ExchangeKind::Fanout, + ExchangeDeclareOptions { durable: true, ..Default::default() }, + FieldTable::default(), + ) + .await + .map_err(|e| { + LdkServerError::new( + InternalServerError, + format!("Failed to declare exchange: {}", e), + ) + })?; + + Ok((conn, channel)) + } + + async fn ensure_connected(&self) -> Result<(), LdkServerError> { + { + let connection = self.connection.lock().await; + if let Some(connection) = &*connection { + if connection.status().state() == ConnectionState::Connected { + return Ok(()); + } + } + } + + // Connection is not alive, attempt reconnecting. + let (connection, channel) = Self::connect(&self.config) + .await + .map_err(|e| LdkServerError::new(InternalServerError, e.to_string()))?; + *self.connection.lock().await = Some(connection); + *self.channel.lock().await = Some(channel); + Ok(()) + } +} + +#[async_trait] +impl EventPublisher for RabbitMqEventPublisher { + /// Publishes an event to RabbitMQ. + /// + /// The event is published to a fanout exchange with persistent delivery mode, + /// and the method waits for confirmation from RabbitMQ to ensure durability. + async fn publish(&self, event: EventEnvelope) -> Result<(), LdkServerError> { + // Ensure connection is alive before proceeding + self.ensure_connected().await?; + + let channel_guard = self.channel.lock().await; + let channel = channel_guard.as_ref().ok_or_else(|| { + LdkServerError::new(InternalServerError, "Channel not initialized".to_string()) + })?; + + // Publish the event with persistent delivery mode + let confirm = channel + .basic_publish( + &self.config.exchange_name, + "", // Empty routing key should be used for fanout exchange, since it is ignored. + BasicPublishOptions::default(), + &event.encode_to_vec(), + BasicProperties::default().with_delivery_mode(DELIVERY_MODE_PERSISTENT), + ) + .await + .map_err(|e| { + LdkServerError::new( + InternalServerError, + format!("Failed to publish event, error: {}", e), + ) + })?; + + let confirmation = confirm.await.map_err(|e| { + LdkServerError::new(InternalServerError, format!("Failed to get confirmation: {}", e)) + })?; + + match confirmation { + lapin::publisher_confirm::Confirmation::Ack(_) => Ok(()), + lapin::publisher_confirm::Confirmation::Nack(_) => Err(LdkServerError::new( + InternalServerError, + "Message not acknowledged".to_string(), + )), + _ => { + Err(LdkServerError::new(InternalServerError, "Unexpected confirmation".to_string())) + }, + } + } +} From dc4124ab5b83e359fc99a79b3ed251c8170f1ac7 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Thu, 13 Mar 2025 00:10:56 -0700 Subject: [PATCH 146/203] Publish events to RabbitMQ queue if events-rabbitmq feature is enabled. --- ldk-server/ldk-server/ldk-server.config | 9 ++++++++- ldk-server/ldk-server/src/main.rs | 11 +++++++++++ ldk-server/ldk-server/src/util/config.rs | 20 ++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/ldk-server.config b/ldk-server/ldk-server/ldk-server.config index d20dd3b4c..2a187fbeb 100644 --- a/ldk-server/ldk-server/ldk-server.config +++ b/ldk-server/ldk-server/ldk-server.config @@ -18,5 +18,12 @@ "bitcoind_rpc_user": "polaruser", // Bitcoin Core's RPC password. - "bitcoind_rpc_password": "polarpass" + "bitcoind_rpc_user": "polarpass", + + // RabbitMQ connection string. (only required if using RabbitMQ based events using `events-rabbitmq` feature) + "rabbitmq_connection_string": "", + + // RabbitMQ exchange name. (only required if using RabbitMQ based events using `events-rabbitmq` feature) + "rabbitmq_exchange_name": "" + } diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index f17a7b0f3..47169ef61 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -15,6 +15,8 @@ use hyper_util::rt::TokioIo; use crate::io::events::event_publisher::{EventPublisher, NoopEventPublisher}; use crate::io::events::get_event_name; +#[cfg(feature = "events-rabbitmq")] +use crate::io::events::rabbitmq::{RabbitMqConfig, RabbitMqEventPublisher}; use crate::io::persist::paginated_kv_store::PaginatedKVStore; use crate::io::persist::sqlite_store::SqliteStore; use crate::io::persist::{ @@ -106,6 +108,15 @@ fn main() { let event_publisher: Arc = Arc::new(NoopEventPublisher); + #[cfg(feature = "events-rabbitmq")] + let event_publisher: Arc = { + let rabbitmq_config = RabbitMqConfig { + connection_string: config_file.rabbitmq_connection_string, + exchange_name: config_file.rabbitmq_exchange_name, + }; + Arc::new(RabbitMqEventPublisher::new(rabbitmq_config)) + }; + println!("Starting up..."); match node.start_with_runtime(Arc::clone(&runtime)) { Ok(()) => {}, diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 5c6e7b3a8..f847f0775 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -16,6 +16,8 @@ pub struct Config { pub bitcoind_rpc_addr: SocketAddr, pub bitcoind_rpc_user: String, pub bitcoind_rpc_password: String, + pub rabbitmq_connection_string: String, + pub rabbitmq_exchange_name: String, } impl TryFrom for Config { @@ -45,6 +47,16 @@ impl TryFrom for Config { ) })?; + #[cfg(feature = "events-rabbitmq")] + if json_config.rabbitmq_connection_string.as_deref().map_or(true, |s| s.is_empty()) + || json_config.rabbitmq_exchange_name.as_deref().map_or(true, |s| s.is_empty()) + { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Both `rabbitmq_connection_string` and `rabbitmq_exchange_name` must be configured if enabling `events-rabbitmq` feature.".to_string(), + )); + } + Ok(Config { listening_addr, network: json_config.network, @@ -53,6 +65,8 @@ impl TryFrom for Config { bitcoind_rpc_addr, bitcoind_rpc_user: json_config.bitcoind_rpc_user, bitcoind_rpc_password: json_config.bitcoind_rpc_password, + rabbitmq_connection_string: json_config.rabbitmq_connection_string.unwrap_or_default(), + rabbitmq_exchange_name: json_config.rabbitmq_exchange_name.unwrap_or_default(), }) } } @@ -67,6 +81,8 @@ pub struct JsonConfig { bitcoind_rpc_address: String, bitcoind_rpc_user: String, bitcoind_rpc_password: String, + rabbitmq_connection_string: Option, + rabbitmq_exchange_name: Option, } /// Loads the configuration from a JSON file at the given path. @@ -114,6 +130,8 @@ mod tests { "bitcoind_rpc_address":"127.0.0.1:8332", // comment-1 "bitcoind_rpc_user": "bitcoind-testuser", "bitcoind_rpc_password": "bitcoind-testpassword", + "rabbitmq_connection_string": "rabbitmq_connection_string", + "rabbitmq_exchange_name": "rabbitmq_exchange_name", "unknown_key": "random-value" // comment-2 }"#; @@ -130,6 +148,8 @@ mod tests { bitcoind_rpc_addr: SocketAddr::from_str("127.0.0.1:8332").unwrap(), bitcoind_rpc_user: "bitcoind-testuser".to_string(), bitcoind_rpc_password: "bitcoind-testpassword".to_string(), + rabbitmq_connection_string: "rabbitmq_connection_string".to_string(), + rabbitmq_exchange_name: "rabbitmq_exchange_name".to_string(), } ) } From 7fb66b31dbba6b505a02eb7bf7a343a5e5cc99af Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Mon, 17 Mar 2025 17:25:43 -0700 Subject: [PATCH 147/203] Add Integration test for RabbitMqEventPublisher. --- .../integration-tests-events-rabbitmq.yml | 34 +++++++ ldk-server/ldk-server/Cargo.toml | 6 ++ .../ldk-server/src/io/events/rabbitmq/mod.rs | 88 +++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 ldk-server/.github/workflows/integration-tests-events-rabbitmq.yml diff --git a/ldk-server/.github/workflows/integration-tests-events-rabbitmq.yml b/ldk-server/.github/workflows/integration-tests-events-rabbitmq.yml new file mode 100644 index 000000000..7f276514b --- /dev/null +++ b/ldk-server/.github/workflows/integration-tests-events-rabbitmq.yml @@ -0,0 +1,34 @@ +name: RabbitMQ Integration Tests + +on: [ push, pull_request ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + integration-tests: + runs-on: ubuntu-latest + + services: + rabbitmq: + image: rabbitmq:3 + env: + RABBITMQ_DEFAULT_USER: guest + RABBITMQ_DEFAULT_PASS: guest + ports: + - 5672:5672 + options: >- + --health-cmd "rabbitmqctl node_health_check" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run RabbitMQ integration tests + run: cargo test --features integration-tests-events-rabbitmq --verbose --color=always -- --nocapture + env: + RUST_BACKTRACE: 1 diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index f59c8b6b0..2ba9c79dd 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -25,3 +25,9 @@ lapin = { version = "2.4.0", features = ["rustls"], default-features = false, op [features] default = [] events-rabbitmq = ["dep:lapin"] + +# Feature-flags related to integration tests. +integration-tests-events-rabbitmq = ["events-rabbitmq"] + +[dev-dependencies] +futures-util = "0.3.31" diff --git a/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs b/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs index a2e1bc220..481f6b063 100644 --- a/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs +++ b/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs @@ -142,3 +142,91 @@ impl EventPublisher for RabbitMqEventPublisher { } } } + +#[cfg(test)] +#[cfg(feature = "integration-tests-events-rabbitmq")] +mod integration_tests_events_rabbitmq { + use super::*; + use lapin::{ + options::{BasicAckOptions, BasicConsumeOptions, QueueBindOptions, QueueDeclareOptions}, + types::FieldTable, + Channel, Connection, + }; + use ldk_server_protos::events::event_envelope::Event; + use ldk_server_protos::events::PaymentForwarded; + use std::io; + use std::time::Duration; + use tokio; + + use futures_util::stream::StreamExt; + #[tokio::test] + async fn test_publish_and_consume_event() { + let config = RabbitMqConfig { + connection_string: "amqp://guest:guest@localhost:5672/%2f".to_string(), + exchange_name: "test_exchange".to_string(), + }; + + let publisher = RabbitMqEventPublisher::new(config.clone()); + + let conn = Connection::connect(&config.connection_string, ConnectionProperties::default()) + .await + .expect("Failed make rabbitmq connection"); + let channel = conn.create_channel().await.expect("Failed to create rabbitmq channel"); + + let queue_name = "test_queue"; + setup_queue(&queue_name, &channel, &config).await; + + let event = + EventEnvelope { event: Some(Event::PaymentForwarded(PaymentForwarded::default())) }; + publisher.publish(event.clone()).await.expect("Failed to publish event"); + + consume_event(&queue_name, &channel, &event).await.expect("Failed to consume event"); + } + + async fn setup_queue(queue_name: &str, channel: &Channel, config: &RabbitMqConfig) { + channel + .queue_declare(queue_name, QueueDeclareOptions::default(), FieldTable::default()) + .await + .unwrap(); + channel + .exchange_declare( + &config.exchange_name, + ExchangeKind::Fanout, + ExchangeDeclareOptions { durable: true, ..Default::default() }, + FieldTable::default(), + ) + .await + .unwrap(); + + channel + .queue_bind( + queue_name, + &config.exchange_name, + "", + QueueBindOptions::default(), + FieldTable::default(), + ) + .await + .unwrap(); + } + + async fn consume_event( + queue_name: &str, channel: &Channel, expected_event: &EventEnvelope, + ) -> io::Result<()> { + let mut consumer = channel + .basic_consume( + queue_name, + "test_consumer", + BasicConsumeOptions::default(), + FieldTable::default(), + ) + .await + .unwrap(); + let delivery = + tokio::time::timeout(Duration::from_secs(10), consumer.next()).await?.unwrap().unwrap(); + let received_event = EventEnvelope::decode(&*delivery.data)?; + assert_eq!(received_event, *expected_event, "Event mismatch"); + channel.basic_ack(delivery.delivery_tag, BasicAckOptions::default()).await.unwrap(); + Ok(()) + } +} From 2d23e1d424f7d692556a1e2f1bf353be094576e2 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 21 Mar 2025 10:08:44 -0700 Subject: [PATCH 148/203] Fix ldk-server.config --- ldk-server/ldk-server/ldk-server.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/ldk-server.config b/ldk-server/ldk-server/ldk-server.config index 2a187fbeb..d1bead22f 100644 --- a/ldk-server/ldk-server/ldk-server.config +++ b/ldk-server/ldk-server/ldk-server.config @@ -18,7 +18,7 @@ "bitcoind_rpc_user": "polaruser", // Bitcoin Core's RPC password. - "bitcoind_rpc_user": "polarpass", + "bitcoind_rpc_password": "polarpass", // RabbitMQ connection string. (only required if using RabbitMQ based events using `events-rabbitmq` feature) "rabbitmq_connection_string": "", From be92a59239660dcef0dd57ee4902ffdbaea7b824 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 21 Mar 2025 10:09:51 -0700 Subject: [PATCH 149/203] Update Cargo.lock --- ldk-server/Cargo.lock | 1297 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1273 insertions(+), 24 deletions(-) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index b8798a971..7852379ef 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -17,6 +17,17 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.8.11" @@ -26,7 +37,7 @@ dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -38,6 +49,54 @@ dependencies = [ "memchr", ] +[[package]] +name = "amq-protocol" +version = "7.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a41c091e49edfcc098b4f90d4d7706a8cf9158034e84ebfee7ff346092f67c" +dependencies = [ + "amq-protocol-tcp", + "amq-protocol-types", + "amq-protocol-uri", + "cookie-factory", + "nom", + "serde", +] + +[[package]] +name = "amq-protocol-tcp" +version = "7.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed7a4a662472f88823ed2fc81babb0b00562f2c54284e3e7bffc02b6df649bf" +dependencies = [ + "amq-protocol-uri", + "tcp-stream", + "tracing", +] + +[[package]] +name = "amq-protocol-types" +version = "7.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6484fdc918c1b6e2ae8eda2914d19a5873e1975f93ad8d33d6a24d1d98df05" +dependencies = [ + "cookie-factory", + "nom", + "serde", + "serde_json", +] + +[[package]] +name = "amq-protocol-uri" +version = "7.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7f2da69e0e1182765bf33407cd8a843f20791b5af2b57a2645818c4776c56c" +dependencies = [ + "amq-protocol-types", + "percent-encoding", + "url", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -71,6 +130,172 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "asn1-rs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 2.0.12", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand 2.3.0", + "futures-lite 2.6.0", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13f937e26114b93193065fd44f507aa2e9169ad0cdabbb996920b1fe1ddea7ba" +dependencies = [ + "async-channel", + "async-executor", + "async-io 2.4.0", + "async-lock 3.4.0", + "blocking", + "futures-lite 2.6.0", +] + +[[package]] +name = "async-global-executor-trait" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9af57045d58eeb1f7060e7025a1631cbc6399e0a1d10ad6735b3d0ea7f8346ce" +dependencies = [ + "async-global-executor", + "async-trait", + "executor-trait", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.28", + "slab", + "socket2 0.4.10", + "waker-fn", +] + +[[package]] +name = "async-io" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +dependencies = [ + "async-lock 3.4.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.6.0", + "parking", + "polling 3.7.4", + "rustix 0.38.44", + "slab", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.4.0", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-reactor-trait" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6012d170ad00de56c9ee354aef2e358359deb1ec504254e0e5a3774771de0e" +dependencies = [ + "async-io 1.13.0", + "async-trait", + "futures-core", + "reactor-trait", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "async-trait" version = "0.1.86" @@ -82,6 +307,12 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.4.0" @@ -125,6 +356,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + [[package]] name = "bdk_chain" version = "0.21.1" @@ -170,7 +407,7 @@ dependencies = [ "bip39", "bitcoin", "miniscript", - "rand_core", + "rand_core 0.6.4", "serde", "serde_json", ] @@ -285,6 +522,37 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite 2.6.0", + "piper", +] + [[package]] name = "bumpalo" version = "3.17.0" @@ -303,6 +571,15 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + [[package]] name = "cc" version = "1.2.14" @@ -337,6 +614,16 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.5.30" @@ -376,6 +663,39 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +[[package]] +name = "cms" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b77c319abfd5219629c45c34c89ba945ed3c5e49fcde9d16b6c3885f118a730" +dependencies = [ + "const-oid", + "der", + "spki", + "x509-cert", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cookie-factory" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" + [[package]] name = "core-foundation" version = "0.9.4" @@ -392,6 +712,104 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "data-encoding" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "der_derive", + "flagset", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "der_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "des" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +dependencies = [ + "cipher", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -409,6 +827,12 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96487aad690d45a83f2b9876828ba856c5430bbb143cb5730d8a5d04a4805179" +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + [[package]] name = "either" version = "1.13.0" @@ -454,6 +878,42 @@ dependencies = [ "tokio", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +dependencies = [ + "event-listener 5.4.0", + "pin-project-lite", +] + +[[package]] +name = "executor-trait" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c39dff9342e4e0e16ce96be751eb21a94e94a87bb2f6e63ad1961c2ce109bf" +dependencies = [ + "async-trait", +] + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -466,6 +926,15 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -478,6 +947,23 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "flagset" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + [[package]] name = "fnv" version = "1.0.7" @@ -541,6 +1027,34 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +dependencies = [ + "fastrand 2.3.0", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.31" @@ -582,6 +1096,16 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -673,6 +1197,24 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hex-conservative" version = "0.1.2" @@ -694,6 +1236,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "home" version = "0.5.9" @@ -788,7 +1339,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.8", "tokio", "tower-service", "tracing", @@ -823,7 +1374,7 @@ dependencies = [ "futures-util", "http 0.2.12", "hyper 0.14.32", - "rustls", + "rustls 0.21.12", "tokio", "tokio-rustls", ] @@ -1015,6 +1566,36 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -1046,6 +1627,28 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lapin" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3551b363b2fcf985fa39c47114333fa12fbb6518f863d4fd9556d0e19f48c1c9" +dependencies = [ + "amq-protocol", + "async-global-executor-trait", + "async-reactor-trait", + "async-trait", + "executor-trait", + "flume", + "futures-core", + "futures-io", + "parking_lot", + "pinky-swear", + "reactor-trait", + "serde", + "tracing", + "waker-fn", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1079,7 +1682,7 @@ dependencies = [ "lightning-types", "log", "prost", - "rand", + "rand 0.8.5", "reqwest", "rusqlite", "serde", @@ -1095,14 +1698,16 @@ version = "0.1.0" dependencies = [ "async-trait", "bytes", + "futures-util", "hex-conservative 0.2.1", "http-body-util", "hyper 1.6.0", "hyper-util", + "lapin", "ldk-node", "ldk-server-protos", "prost", - "rand", + "rand 0.8.5", "rusqlite", "serde", "serde_json", @@ -1295,6 +1900,12 @@ dependencies = [ "bitcoin", ] +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -1307,6 +1918,16 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.25" @@ -1325,6 +1946,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniscript" version = "12.3.0" @@ -1362,6 +1989,41 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1380,12 +2042,97 @@ dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "p12-keystore" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a09eaa3a6d8884c204c2ab17e313f563b524362e62567f09ba27857a6e31257f" +dependencies = [ + "cbc", + "cms", + "der", + "des", + "hex", + "hmac", + "pkcs12", + "pkcs5", + "rand 0.9.0", + "rc2", + "sha1", + "sha2", + "thiserror 2.0.12", + "x509-parser", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1420,12 +2167,96 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pinky-swear" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cfae3ead413ca051a681152bd266438d3bfa301c9bdf836939a14c721bb2a21" +dependencies = [ + "doc-comment", + "flume", + "parking_lot", + "tracing", +] + +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand 2.3.0", + "futures-io", +] + +[[package]] +name = "pkcs12" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "695b3df3d3cc1015f12d70235e35b6b79befc5fa7a9b95b951eab1dd07c9efc2" +dependencies = [ + "cms", + "const-oid", + "der", + "digest", + "spki", + "x509-cert", + "zeroize", +] + +[[package]] +name = "pkcs5" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" +dependencies = [ + "aes", + "cbc", + "der", + "pbkdf2", + "scrypt", + "sha2", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix 0.38.44", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "possiblyrandom" version = "0.2.0" @@ -1435,13 +2266,19 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -1533,8 +2370,19 @@ 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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "zerocopy 0.8.23", ] [[package]] @@ -1544,7 +2392,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.3", ] [[package]] @@ -1556,6 +2414,44 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.1", +] + +[[package]] +name = "rc2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62c64daa8e9438b84aaae55010a93f396f8e60e3911590fcba770d04643fc1dd" +dependencies = [ + "cipher", +] + +[[package]] +name = "reactor-trait" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "438a4293e4d097556730f4711998189416232f009c137389e0f961d2bc0ddc58" +dependencies = [ + "async-trait", + "futures-core", + "futures-io", +] + +[[package]] +name = "redox_syscall" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +dependencies = [ + "bitflags 2.8.0", +] + [[package]] name = "regex" version = "1.11.1" @@ -1608,8 +2504,8 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", @@ -1661,6 +2557,29 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "0.37.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + [[package]] name = "rustix" version = "0.38.44" @@ -1670,7 +2589,7 @@ dependencies = [ "bitflags 2.8.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.15", "windows-sys 0.52.0", ] @@ -1682,10 +2601,50 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.103.0", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-connector" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a980454b497c439c274f2feae2523ed8138bbd3d323684e1435fec62f800481" +dependencies = [ + "log", + "rustls 0.23.25", + "rustls-native-certs", + "rustls-pki-types", + "rustls-webpki 0.102.8", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -1695,6 +2654,21 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -1705,6 +2679,28 @@ dependencies = [ "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]] +name = "rustls-webpki" +version = "0.103.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa4eeac2588ffff23e9d7a7e9b3f971c5fb5b7ebc9452745e0c232c64f83b2f" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.19" @@ -1717,6 +2713,41 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +dependencies = [ + "pbkdf2", + "salsa20", + "sha2", +] + [[package]] name = "sct" version = "0.7.1" @@ -1734,7 +2765,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "bitcoin_hashes 0.14.0", - "rand", + "rand 0.8.5", "secp256k1-sys", "serde", ] @@ -1748,6 +2779,29 @@ dependencies = [ "cc", ] +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.8.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.217" @@ -1792,6 +2846,28 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1822,6 +2898,16 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.5.8" @@ -1832,6 +2918,25 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -1844,6 +2949,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "1.0.109" @@ -1904,6 +3015,18 @@ dependencies = [ "libc", ] +[[package]] +name = "tcp-stream" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "495b0abdce3dc1f8fd27240651c9e68890c14e9d9c61527b1ce44d8a5a7bd3d5" +dependencies = [ + "cfg-if", + "p12-keystore", + "rustls-connector", + "rustls-pemfile 2.2.0", +] + [[package]] name = "tempfile" version = "3.17.1" @@ -1911,10 +3034,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" dependencies = [ "cfg-if", - "fastrand", + "fastrand 2.3.0", "getrandom 0.3.1", "once_cell", - "rustix", + "rustix 0.38.44", "windows-sys 0.52.0", ] @@ -1924,7 +3047,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.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] @@ -1938,6 +3070,48 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "time" +version = "0.3.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29aa485584182073ed57fd5004aa09c371f021325014694e432313345865fd04" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinystr" version = "0.7.6" @@ -1975,7 +3149,7 @@ dependencies = [ "mio", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.8", "tokio-macros", "windows-sys 0.52.0", ] @@ -1997,7 +3171,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", "tokio", ] @@ -2009,7 +3183,7 @@ checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" dependencies = [ "either", "futures-util", - "thiserror", + "thiserror 1.0.69", "tokio", ] @@ -2057,6 +3231,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + [[package]] name = "unicode-ident" version = "1.0.17" @@ -2125,7 +3305,7 @@ dependencies = [ "bitcoin_hashes 0.14.0", "prost", "prost-build", - "rand", + "rand 0.8.5", "reqwest", "serde", "serde_json", @@ -2133,6 +3313,12 @@ dependencies = [ "url", ] +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + [[package]] name = "want" version = "0.3.1" @@ -2253,7 +3439,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix", + "rustix 0.38.44", ] [[package]] @@ -2305,6 +3491,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -2457,6 +3652,34 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "x509-cert" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" +dependencies = [ + "const-oid", + "der", + "spki", +] + +[[package]] +name = "x509-parser" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror 2.0.12", + "time", +] + [[package]] name = "yoke" version = "0.7.5" @@ -2488,7 +3711,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" +dependencies = [ + "zerocopy-derive 0.8.23", ] [[package]] @@ -2502,6 +3734,17 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "zerocopy-derive" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "zerofrom" version = "0.1.5" @@ -2523,6 +3766,12 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + [[package]] name = "zerovec" version = "0.10.4" From e7d7e2168ef9055c90e0e0a7f8841c80c0687a77 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 21 Mar 2025 12:11:47 -0700 Subject: [PATCH 150/203] Add TOML-based configuration support. Long-term, TOML is a better fit for ldk-server configuration than JSON. This change introduces TOML-based config, enabling the use of nested structs, optional fields, and an industry-standard format instead of a custom-defined one. --- ldk-server/Cargo.lock | 60 +++++++- ldk-server/README.md | 2 +- ldk-server/ldk-server/Cargo.toml | 2 +- ldk-server/ldk-server/ldk-server-config.toml | 20 +++ ldk-server/ldk-server/src/util/config.rs | 148 +++++++++++-------- 5 files changed, 165 insertions(+), 67 deletions(-) create mode 100644 ldk-server/ldk-server/ldk-server-config.toml diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 7852379ef..7b65156e8 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -861,7 +861,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1710,8 +1710,8 @@ dependencies = [ "rand 0.8.5", "rusqlite", "serde", - "serde_json", "tokio", + "toml", ] [[package]] @@ -2590,7 +2590,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2834,6 +2834,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3038,7 +3047,7 @@ dependencies = [ "getrandom 0.3.1", "once_cell", "rustix 0.38.44", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3200,6 +3209,40 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.3" @@ -3621,6 +3664,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" diff --git a/ldk-server/README.md b/ldk-server/README.md index 1d37ee6bc..b15eafb45 100644 --- a/ldk-server/README.md +++ b/ldk-server/README.md @@ -36,7 +36,7 @@ We welcome your feedback and contributions to help shape the future of LDK Serve ### Configuration -Refer `./ldk-server/ldk-server.config` to see available configuration options. +Refer `./ldk-server/ldk-server-config.toml` to see available configuration options. ### Building ``` diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index 2ba9c79dd..41ae2ecd3 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" [dependencies] ldk-node = { git = "https://github.com/lightningdevkit/ldk-node.git", rev = "6de350040e0fc5eb9cfcd15fad3919f5a79b82b9" } serde = { version = "1.0.203", default-features = false, features = ["derive"] } -serde_json = { version = "1.0.118", default-features = false } hyper = { version = "1", default-features = false, features = ["server", "http1"] } http-body-util = { version = "0.1", default-features = false } hyper-util = { version = "0.1", default-features = false, features = ["server-graceful"] } @@ -18,6 +17,7 @@ hex = { package = "hex-conservative", version = "0.2.1", default-features = fals rusqlite = { version = "0.31.0", features = ["bundled"] } rand = { version = "0.8.5", default-features = false } async-trait = { version = "0.1.85", default-features = false } +toml = { version = "0.8.9", default-features = false, features = ["parse"] } # Required for RabittMQ based EventPublisher. Only enabled for `events-rabbitmq` feature. lapin = { version = "2.4.0", features = ["rustls"], default-features = false, optional = true } diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml new file mode 100644 index 000000000..78a5534b4 --- /dev/null +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -0,0 +1,20 @@ +# Lightning node settings +[node] +network = "regtest" # Bitcoin network to use +listening_address = "localhost:3001" # Lightning node listening address +rest_service_address = "127.0.0.1:3002" # LDK Server REST address + +# Storage settings +[storage.disk] +dir_path = "/tmp/ldk-server/" # Path for LDK and BDK data persistence + +# Bitcoin Core settings +[bitcoind] +rpc_address = "127.0.0.1:18444" # RPC endpoint +rpc_user = "polaruser" # RPC username +rpc_password = "polarpass" # RPC password + +# RabbitMQ settings (only required if using events-rabbitmq feature) +[rabbitmq] +connection_string = "" # RabbitMQ connection string +exchange_name = "" # RabbitMQ exchange name diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index f847f0775..377801f49 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -20,72 +20,101 @@ pub struct Config { pub rabbitmq_exchange_name: String, } -impl TryFrom for Config { +impl TryFrom for Config { type Error = io::Error; - fn try_from(json_config: JsonConfig) -> io::Result { + fn try_from(toml_config: TomlConfig) -> io::Result { let listening_addr = - SocketAddress::from_str(&json_config.listening_address).map_err(|e| { + SocketAddress::from_str(&toml_config.node.listening_address).map_err(|e| { io::Error::new( io::ErrorKind::InvalidInput, format!("Invalid listening address configured: {}", e), ) })?; - let rest_service_addr = - SocketAddr::from_str(&json_config.rest_service_address).map_err(|e| { + let rest_service_addr = SocketAddr::from_str(&toml_config.node.rest_service_address) + .map_err(|e| { io::Error::new( io::ErrorKind::InvalidInput, format!("Invalid rest service address configured: {}", e), ) })?; - let bitcoind_rpc_addr = - SocketAddr::from_str(&json_config.bitcoind_rpc_address).map_err(|e| { + SocketAddr::from_str(&toml_config.bitcoind.rpc_address).map_err(|e| { io::Error::new( io::ErrorKind::InvalidInput, format!("Invalid bitcoind RPC address configured: {}", e), ) })?; - #[cfg(feature = "events-rabbitmq")] - if json_config.rabbitmq_connection_string.as_deref().map_or(true, |s| s.is_empty()) - || json_config.rabbitmq_exchange_name.as_deref().map_or(true, |s| s.is_empty()) - { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Both `rabbitmq_connection_string` and `rabbitmq_exchange_name` must be configured if enabling `events-rabbitmq` feature.".to_string(), - )); - } + let (rabbitmq_connection_string, rabbitmq_exchange_name) = { + let rabbitmq = toml_config.rabbitmq.unwrap_or(RabbitmqConfig { + connection_string: String::new(), + exchange_name: String::new(), + }); + #[cfg(feature = "events-rabbitmq")] + if rabbitmq.connection_string.is_empty() || rabbitmq.exchange_name.is_empty() { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Both `rabbitmq.connection_string` and `rabbitmq.exchange_name` must be configured if enabling `events-rabbitmq` feature.".to_string(), + )); + } + (rabbitmq.connection_string, rabbitmq.exchange_name) + }; Ok(Config { listening_addr, - network: json_config.network, + network: toml_config.node.network, rest_service_addr, - storage_dir_path: json_config.storage_dir_path, + storage_dir_path: toml_config.storage.disk.dir_path, bitcoind_rpc_addr, - bitcoind_rpc_user: json_config.bitcoind_rpc_user, - bitcoind_rpc_password: json_config.bitcoind_rpc_password, - rabbitmq_connection_string: json_config.rabbitmq_connection_string.unwrap_or_default(), - rabbitmq_exchange_name: json_config.rabbitmq_exchange_name.unwrap_or_default(), + bitcoind_rpc_user: toml_config.bitcoind.rpc_user, + bitcoind_rpc_password: toml_config.bitcoind.rpc_password, + rabbitmq_connection_string, + rabbitmq_exchange_name, }) } } -/// Configuration loaded from a JSON file. +/// Configuration loaded from a TOML file. #[derive(Deserialize, Serialize)] -pub struct JsonConfig { - listening_address: String, +pub struct TomlConfig { + node: NodeConfig, + storage: StorageConfig, + bitcoind: BitcoindConfig, + rabbitmq: Option, +} + +#[derive(Deserialize, Serialize)] +struct NodeConfig { network: Network, + listening_address: String, rest_service_address: String, - storage_dir_path: String, - bitcoind_rpc_address: String, - bitcoind_rpc_user: String, - bitcoind_rpc_password: String, - rabbitmq_connection_string: Option, - rabbitmq_exchange_name: Option, } -/// Loads the configuration from a JSON file at the given path. +#[derive(Deserialize, Serialize)] +struct StorageConfig { + disk: DiskConfig, +} + +#[derive(Deserialize, Serialize)] +struct DiskConfig { + dir_path: String, +} + +#[derive(Deserialize, Serialize)] +struct BitcoindConfig { + rpc_address: String, + rpc_user: String, + rpc_password: String, +} + +#[derive(Deserialize, Serialize)] +struct RabbitmqConfig { + connection_string: String, + exchange_name: String, +} + +/// Loads the configuration from a TOML file at the given path. pub fn load_config>(config_path: P) -> io::Result { let file_contents = fs::read_to_string(config_path.as_ref()).map_err(|e| { io::Error::new( @@ -94,21 +123,13 @@ pub fn load_config>(config_path: P) -> io::Result { ) })?; - let json_string = remove_json_comments(file_contents.as_str()); - let json_config: JsonConfig = serde_json::from_str(&json_string).map_err(|e| { + let toml_config: TomlConfig = toml::from_str(&file_contents).map_err(|e| { io::Error::new( io::ErrorKind::InvalidData, - format!("Config file contains invalid JSON format: {}", e), + format!("Config file contains invalid TOML format: {}", e), ) })?; - Ok(Config::try_from(json_config)?) -} - -fn remove_json_comments(s: &str) -> String { - s.lines() - .map(|line| if let Some(pos) = line.find("//") { &line[..pos] } else { line }) - .collect::>() - .join("\n") + Ok(Config::try_from(toml_config)?) } #[cfg(test)] @@ -118,25 +139,30 @@ mod tests { use std::str::FromStr; #[test] - fn test_read_json_config_from_file() { + fn test_read_toml_config_from_file() { let storage_path = std::env::temp_dir(); - let config_file_name = "config.json"; - - let json_config = r#"{ - "listening_address": "localhost:3001", - "network": "regtest", - "rest_service_address": "127.0.0.1:3002", - "storage_dir_path": "/tmp", - "bitcoind_rpc_address":"127.0.0.1:8332", // comment-1 - "bitcoind_rpc_user": "bitcoind-testuser", - "bitcoind_rpc_password": "bitcoind-testpassword", - "rabbitmq_connection_string": "rabbitmq_connection_string", - "rabbitmq_exchange_name": "rabbitmq_exchange_name", - "unknown_key": "random-value" - // comment-2 - }"#; - - fs::write(storage_path.join(config_file_name), json_config).unwrap(); + let config_file_name = "config.toml"; + + let toml_config = r#" + [node] + network = "regtest" + listening_address = "localhost:3001" + rest_service_address = "127.0.0.1:3002" + + [storage.disk] + dir_path = "/tmp" + + [bitcoind] + rpc_address = "127.0.0.1:8332" # RPC endpoint + rpc_user = "bitcoind-testuser" + rpc_password = "bitcoind-testpassword" + + [rabbitmq] + connection_string = "rabbitmq_connection_string" + exchange_name = "rabbitmq_exchange_name" + "#; + + fs::write(storage_path.join(config_file_name), toml_config).unwrap(); assert_eq!( load_config(storage_path.join(config_file_name)).unwrap(), From e3bfe903689efa33e4d0a025afa0f0f3c63f13ff Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 21 Mar 2025 14:05:38 -0700 Subject: [PATCH 151/203] Add experimental LSPS2 support. --- ldk-server/ldk-server/Cargo.toml | 3 + ldk-server/ldk-server/ldk-server-config.toml | 34 +++++- ldk-server/ldk-server/src/main.rs | 9 +- ldk-server/ldk-server/src/util/config.rs | 122 ++++++++++++++++--- 4 files changed, 151 insertions(+), 17 deletions(-) diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index ded20467a..fb3527a26 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -26,6 +26,9 @@ lapin = { version = "2.4.0", features = ["rustls"], default-features = false, op default = [] events-rabbitmq = ["dep:lapin"] +# Experimental Features. +experimental-lsps2-support = [] + # Feature-flags related to integration tests. integration-tests-events-rabbitmq = ["events-rabbitmq"] diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml index 78a5534b4..7f5e7ba77 100644 --- a/ldk-server/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -17,4 +17,36 @@ rpc_password = "polarpass" # RPC password # RabbitMQ settings (only required if using events-rabbitmq feature) [rabbitmq] connection_string = "" # RabbitMQ connection string -exchange_name = "" # RabbitMQ exchange name +exchange_name = "" + +# Experimental LSPS2 Service Support +# CAUTION: LSPS2 support is highly experimental and for testing purposes only. +[liquidity.lsps2_service] +# Indicates whether the LSPS service will be announced via the gossip network. +advertise_service = false + +# The fee we withhold for the channel open from the initial payment. +channel_opening_fee_ppm = 1000 # 0.1% fee + +# The proportional overprovisioning for the channel. +channel_over_provisioning_ppm = 500000 # 50% extra capacity + +# The minimum fee required for opening a channel. +min_channel_opening_fee_msat = 10000000 # 10,000 satoshis + +# The minimum number of blocks after confirmation we promise to keep the channel open. +min_channel_lifetime = 4320 # ~30 days + +# The maximum number of blocks that the client is allowed to set its `to_self_delay` parameter. +max_client_to_self_delay = 1440 # ~10 days + +# The minimum payment size that we will accept when opening a channel. +min_payment_size_msat = 10000000 # 10,000 satoshis + +# The maximum payment size that we will accept when opening a channel. +max_payment_size_msat = 25000000000 # 0.25 BTC + +# Optional token for clients (uncomment and set if required) +## A token we may require to be sent by the clients. +## If set, only requests matching this token will be accepted. (uncomment and set if required) +# require_token = "" diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 3f8fe0671..f3ad228db 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -29,7 +29,8 @@ use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto}; use hex::DisplayHex; use ldk_node::config::Config; use ldk_node::lightning::ln::channelmanager::PaymentId; -use ldk_node::logger::LogLevel; +#[cfg(feature = "experimental-lsps2-support")] +use ldk_node::liquidity::LSPS2ServiceConfig; use ldk_server_protos::events; use ldk_server_protos::events::{event_envelope, EventEnvelope}; use ldk_server_protos::types::Payment; @@ -81,6 +82,12 @@ fn main() { config_file.bitcoind_rpc_password, ); + // LSPS2 support is highly experimental and for testing purposes only. + #[cfg(feature = "experimental-lsps2-support")] + builder.set_liquidity_provider_lsps2( + config_file.lsps2_service_config.expect("Missing liquidity.lsps2_server config"), + ); + let runtime = match tokio::runtime::Builder::new_multi_thread().enable_all().build() { Ok(runtime) => Arc::new(runtime), Err(e) => { diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 377801f49..110e49914 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -1,5 +1,6 @@ use ldk_node::bitcoin::Network; use ldk_node::lightning::ln::msgs::SocketAddress; +use ldk_node::liquidity::LSPS2ServiceConfig; use serde::{Deserialize, Serialize}; use std::net::SocketAddr; use std::path::Path; @@ -7,7 +8,7 @@ use std::str::FromStr; use std::{fs, io}; /// Configuration for LDK Server. -#[derive(PartialEq, Eq, Debug)] +#[derive(Debug)] pub struct Config { pub listening_addr: SocketAddress, pub network: Network, @@ -18,6 +19,7 @@ pub struct Config { pub bitcoind_rpc_password: String, pub rabbitmq_connection_string: String, pub rabbitmq_exchange_name: String, + pub lsps2_service_config: Option, } impl TryFrom for Config { @@ -61,6 +63,17 @@ impl TryFrom for Config { (rabbitmq.connection_string, rabbitmq.exchange_name) }; + #[cfg(not(feature = "experimental-lsps2-support"))] + let lsps2_service_config: Option = None; + #[cfg(feature = "experimental-lsps2-support")] + let lsps2_service_config = Some(toml_config.liquidity + .and_then(|l| l.lsps2_service) + .ok_or_else(|| io::Error::new( + io::ErrorKind::InvalidInput, + "`liquidity.lsps2_service` must be defined in config if enabling `experimental-lsps2-support` feature." + ))? + .into()); + Ok(Config { listening_addr, network: toml_config.node.network, @@ -71,6 +84,7 @@ impl TryFrom for Config { bitcoind_rpc_password: toml_config.bitcoind.rpc_password, rabbitmq_connection_string, rabbitmq_exchange_name, + lsps2_service_config, }) } } @@ -82,6 +96,7 @@ pub struct TomlConfig { storage: StorageConfig, bitcoind: BitcoindConfig, rabbitmq: Option, + liquidity: Option, } #[derive(Deserialize, Serialize)] @@ -114,6 +129,52 @@ struct RabbitmqConfig { exchange_name: String, } +#[derive(Deserialize, Serialize)] +struct LiquidityConfig { + lsps2_service: Option, +} + +#[derive(Deserialize, Serialize, Debug)] +struct LSPS2ServiceTomlConfig { + advertise_service: bool, + channel_opening_fee_ppm: u32, + channel_over_provisioning_ppm: u32, + min_channel_opening_fee_msat: u64, + min_channel_lifetime: u32, + max_client_to_self_delay: u32, + min_payment_size_msat: u64, + max_payment_size_msat: u64, + require_token: Option, +} + +impl Into for LSPS2ServiceTomlConfig { + fn into(self) -> LSPS2ServiceConfig { + match self { + LSPS2ServiceTomlConfig { + advertise_service, + channel_opening_fee_ppm, + channel_over_provisioning_ppm, + min_channel_opening_fee_msat, + min_channel_lifetime, + max_client_to_self_delay, + min_payment_size_msat, + max_payment_size_msat, + require_token, + } => LSPS2ServiceConfig { + advertise_service, + channel_opening_fee_ppm, + channel_over_provisioning_ppm, + min_channel_opening_fee_msat, + min_channel_lifetime, + min_payment_size_msat, + max_client_to_self_delay, + max_payment_size_msat, + require_token, + }, + } + } +} + /// Loads the configuration from a TOML file at the given path. pub fn load_config>(config_path: P) -> io::Result { let file_contents = fs::read_to_string(config_path.as_ref()).map_err(|e| { @@ -160,23 +221,54 @@ mod tests { [rabbitmq] connection_string = "rabbitmq_connection_string" exchange_name = "rabbitmq_exchange_name" + + [liquidity.lsps2_service] + advertise_service = false + channel_opening_fee_ppm = 1000 # 0.1% fee + channel_over_provisioning_ppm = 500000 # 50% extra capacity + min_channel_opening_fee_msat = 10000000 # 10,000 satoshis + min_channel_lifetime = 4320 # ~30 days + max_client_to_self_delay = 1440 # ~10 days + min_payment_size_msat = 10000000 # 10,000 satoshis + max_payment_size_msat = 25000000000 # 0.25 BTC "#; fs::write(storage_path.join(config_file_name), toml_config).unwrap(); - assert_eq!( - load_config(storage_path.join(config_file_name)).unwrap(), - Config { - listening_addr: SocketAddress::from_str("localhost:3001").unwrap(), - network: Network::Regtest, - rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(), - storage_dir_path: "/tmp".to_string(), - bitcoind_rpc_addr: SocketAddr::from_str("127.0.0.1:8332").unwrap(), - bitcoind_rpc_user: "bitcoind-testuser".to_string(), - bitcoind_rpc_password: "bitcoind-testpassword".to_string(), - rabbitmq_connection_string: "rabbitmq_connection_string".to_string(), - rabbitmq_exchange_name: "rabbitmq_exchange_name".to_string(), - } - ) + let config = load_config(storage_path.join(config_file_name)).unwrap(); + let expected = Config { + listening_addr: SocketAddress::from_str("localhost:3001").unwrap(), + network: Network::Regtest, + rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(), + storage_dir_path: "/tmp".to_string(), + bitcoind_rpc_addr: SocketAddr::from_str("127.0.0.1:8332").unwrap(), + bitcoind_rpc_user: "bitcoind-testuser".to_string(), + bitcoind_rpc_password: "bitcoind-testpassword".to_string(), + rabbitmq_connection_string: "rabbitmq_connection_string".to_string(), + rabbitmq_exchange_name: "rabbitmq_exchange_name".to_string(), + lsps2_service_config: Some(LSPS2ServiceConfig { + require_token: None, + advertise_service: false, + channel_opening_fee_ppm: 1000, + channel_over_provisioning_ppm: 500000, + min_channel_opening_fee_msat: 10000000, + min_channel_lifetime: 4320, + max_client_to_self_delay: 1440, + min_payment_size_msat: 10000000, + max_payment_size_msat: 25000000000, + }), + }; + + assert_eq!(config.listening_addr, expected.listening_addr); + assert_eq!(config.network, expected.network); + assert_eq!(config.rest_service_addr, expected.rest_service_addr); + assert_eq!(config.storage_dir_path, expected.storage_dir_path); + assert_eq!(config.bitcoind_rpc_addr, expected.bitcoind_rpc_addr); + assert_eq!(config.bitcoind_rpc_user, expected.bitcoind_rpc_user); + assert_eq!(config.bitcoind_rpc_password, expected.bitcoind_rpc_password); + assert_eq!(config.rabbitmq_connection_string, expected.rabbitmq_connection_string); + assert_eq!(config.rabbitmq_exchange_name, expected.rabbitmq_exchange_name); + #[cfg(feature = "experimental-lsps2-support")] + assert_eq!(config.lsps2_service_config.is_some(), expected.lsps2_service_config.is_some()); } } From 025f9a10a84d7ea89e407965f3671c5637b681fa Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 21 Mar 2025 18:07:20 -0700 Subject: [PATCH 152/203] Remove unused ldk-server.config --- ldk-server/ldk-server/ldk-server.config | 29 ------------------------- 1 file changed, 29 deletions(-) delete mode 100644 ldk-server/ldk-server/ldk-server.config diff --git a/ldk-server/ldk-server/ldk-server.config b/ldk-server/ldk-server/ldk-server.config deleted file mode 100644 index d1bead22f..000000000 --- a/ldk-server/ldk-server/ldk-server.config +++ /dev/null @@ -1,29 +0,0 @@ -{ - // The addresses on which the lightning node will listen for incoming connections. - "listening_address": "localhost:3001", - - // The Bitcoin network to use. - "network": "regtest", - - // The address on which LDK Server will accept incoming requests. - "rest_service_address": "127.0.0.1:3002", - - // The path where the underlying LDK and BDK persist their data. - "storage_dir_path": "/tmp/ldk-server/", - - // Bitcoin Core's RPC endpoint. - "bitcoind_rpc_address": "127.0.0.1:18444", - - // Bitcoin Core's RPC user. - "bitcoind_rpc_user": "polaruser", - - // Bitcoin Core's RPC password. - "bitcoind_rpc_password": "polarpass", - - // RabbitMQ connection string. (only required if using RabbitMQ based events using `events-rabbitmq` feature) - "rabbitmq_connection_string": "", - - // RabbitMQ exchange name. (only required if using RabbitMQ based events using `events-rabbitmq` feature) - "rabbitmq_exchange_name": "" - -} From 48a64acb8c9736915af743ec56c5300a37d64a7d Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Fri, 28 Mar 2025 12:43:38 -0700 Subject: [PATCH 153/203] Log and exit in case of invalid configuration. --- ldk-server/ldk-server/src/main.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index f3ad228db..8421530ec 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -64,7 +64,13 @@ fn main() { } let mut ldk_node_config = Config::default(); - let config_file = load_config(Path::new(arg)).expect("Invalid configuration file."); + let config_file = match load_config(Path::new(arg)) { + Ok(config) => config, + Err(e) => { + eprintln!("Invalid configuration file: {}", e); + std::process::exit(-1); + }, + }; ldk_node_config.storage_dir_path = config_file.storage_dir_path.clone(); ldk_node_config.listening_addresses = Some(vec![config_file.listening_addr]); From 9cef61d0e60a6a021a4c4c9ff18a32ad3ef1ca40 Mon Sep 17 00:00:00 2001 From: moisesPomilio <93723302+moisesPompilio@users.noreply.github.com> Date: Thu, 26 Jun 2025 19:14:21 -0300 Subject: [PATCH 154/203] Refactor CloseChannel API to remove force close functionality --- ldk-server/ldk-server-protos/src/api.rs | 10 +--------- ldk-server/ldk-server-protos/src/proto/api.proto | 14 ++------------ ldk-server/ldk-server/src/api/close_channel.rs | 10 +--------- 3 files changed, 4 insertions(+), 30 deletions(-) diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index 770cbc307..af93fcb34 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -270,9 +270,7 @@ pub struct UpdateChannelConfigRequest { #[derive(Clone, PartialEq, ::prost::Message)] pub struct UpdateChannelConfigResponse {} /// Closes the channel specified by given request. -/// See more: -/// - -/// - +/// See more: #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CloseChannelRequest { @@ -282,12 +280,6 @@ pub struct CloseChannelRequest { /// The hex-encoded public key of the node to close a channel with. #[prost(string, tag = "2")] pub counterparty_node_id: ::prost::alloc::string::String, - /// Whether to force close the specified channel. - #[prost(bool, optional, tag = "3")] - pub force_close: ::core::option::Option, - /// The reason for force-closing, can only be set while force closing a channel. - #[prost(string, optional, tag = "4")] - pub force_close_reason: ::core::option::Option<::prost::alloc::string::String>, } /// The response `content` for the `CloseChannel` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. diff --git a/ldk-server/ldk-server-protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto index 9f61ba938..b65b2d5a2 100644 --- a/ldk-server/ldk-server-protos/src/proto/api.proto +++ b/ldk-server/ldk-server-protos/src/proto/api.proto @@ -261,9 +261,7 @@ message UpdateChannelConfigResponse { } // Closes the channel specified by given request. -// See more: -// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.close_channel -// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.force_close_channel +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.close_channel message CloseChannelRequest { // The local `user_channel_id` of this channel. @@ -271,19 +269,11 @@ message CloseChannelRequest { // The hex-encoded public key of the node to close a channel with. string counterparty_node_id = 2; - - // Whether to force close the specified channel. - optional bool force_close = 3; - - // The reason for force-closing, can only be set while force closing a channel. - optional string force_close_reason = 4; } // The response `content` for the `CloseChannel` API, when HttpStatusCode is OK (200). // When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message CloseChannelResponse { - -} +message CloseChannelResponse {} // Returns a list of known channels. // See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_channels diff --git a/ldk-server/ldk-server/src/api/close_channel.rs b/ldk-server/ldk-server/src/api/close_channel.rs index 95054a454..170195ffe 100644 --- a/ldk-server/ldk-server/src/api/close_channel.rs +++ b/ldk-server/ldk-server/src/api/close_channel.rs @@ -21,15 +21,7 @@ pub(crate) fn handle_close_channel_request( format!("Invalid counterparty node ID, error: {}", e), ) })?; - - match request.force_close { - Some(true) => context.node.force_close_channel( - &user_channel_id, - counterparty_node_id, - request.force_close_reason, - )?, - _ => context.node.close_channel(&user_channel_id, counterparty_node_id)?, - }; + context.node.close_channel(&user_channel_id, counterparty_node_id)?; let response = CloseChannelResponse {}; Ok(response) From f21b502fe5e2d968dba94ea6316cd9face55c21c Mon Sep 17 00:00:00 2001 From: moisesPomilio <93723302+moisesPompilio@users.noreply.github.com> Date: Thu, 26 Jun 2025 19:20:53 -0300 Subject: [PATCH 155/203] add close channel in the cli --- ldk-server/ldk-server-cli/src/main.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 7ebd5e94b..20efa891b 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -6,8 +6,8 @@ use ldk_server_client::error::LdkServerErrorCode::{ }; use ldk_server_client::ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, Bolt12SendRequest, - GetBalancesRequest, GetNodeInfoRequest, ListChannelsRequest, ListPaymentsRequest, - OnchainReceiveRequest, OnchainSendRequest, OpenChannelRequest, + CloseChannelRequest, GetBalancesRequest, GetNodeInfoRequest, ListChannelsRequest, + ListPaymentsRequest, OnchainReceiveRequest, OnchainSendRequest, OpenChannelRequest, }; use ldk_server_client::ldk_server_protos::types::{ bolt11_invoice_description, Bolt11InvoiceDescription, PageToken, Payment, @@ -75,6 +75,12 @@ enum Commands { #[arg(short, long)] payer_note: Option, }, + CloseChannel { + #[arg(short, long)] + user_channel_id: String, + #[arg(short, long)] + counterparty_node_id: String, + }, OpenChannel { #[arg(short, long)] node_pubkey: String, @@ -170,6 +176,13 @@ async fn main() { .await, ); }, + Commands::CloseChannel { user_channel_id, counterparty_node_id } => { + handle_response_result( + client + .close_channel(CloseChannelRequest { user_channel_id, counterparty_node_id }) + .await, + ); + }, Commands::OpenChannel { node_pubkey, address, From 20f5623fc9a91953ed14cfb4a5c4ea14385fa80a Mon Sep 17 00:00:00 2001 From: moisesPomilio <93723302+moisesPompilio@users.noreply.github.com> Date: Thu, 26 Jun 2025 19:29:42 -0300 Subject: [PATCH 156/203] Add force_close_channel API endpoint and handler Introduce ForceCloseChannelRequest and ForceCloseChannelResponse to the API, implement the handle_force_close_channel_request function, and register the new endpoint in the service router. --- ldk-server/ldk-server-protos/src/api.rs | 20 ++++++++ .../ldk-server-protos/src/proto/api.proto | 15 ++++++ .../ldk-server/src/api/close_channel.rs | 49 ++++++++++++++----- ldk-server/ldk-server/src/service.rs | 8 ++- 4 files changed, 80 insertions(+), 12 deletions(-) diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index af93fcb34..d89283b6c 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -286,6 +286,26 @@ pub struct CloseChannelRequest { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct CloseChannelResponse {} +/// Force closes the channel specified by given request. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ForceCloseChannelRequest { + /// The local `user_channel_id` of this channel. + #[prost(string, tag = "1")] + pub user_channel_id: ::prost::alloc::string::String, + /// The hex-encoded public key of the node to close a channel with. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// The reason for force-closing. + #[prost(string, optional, tag = "3")] + pub force_close_reason: ::core::option::Option<::prost::alloc::string::String>, +} +/// The response `content` for the `ForceCloseChannel` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ForceCloseChannelResponse {} /// Returns a list of known channels. /// See more: #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/ldk-server/ldk-server-protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto index b65b2d5a2..32be3c374 100644 --- a/ldk-server/ldk-server-protos/src/proto/api.proto +++ b/ldk-server/ldk-server-protos/src/proto/api.proto @@ -275,6 +275,21 @@ message CloseChannelRequest { // When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. message CloseChannelResponse {} +// Force closes the channel specified by given request. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.force_close_channel +message ForceCloseChannelRequest { + // The local `user_channel_id` of this channel. + string user_channel_id = 1; + // The hex-encoded public key of the node to close a channel with. + string counterparty_node_id = 2; + // The reason for force-closing. + optional string force_close_reason = 3; +} + +// The response `content` for the `ForceCloseChannel` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. +message ForceCloseChannelResponse {} + // Returns a list of known channels. // See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_channels message ListChannelsRequest {} diff --git a/ldk-server/ldk-server/src/api/close_channel.rs b/ldk-server/ldk-server/src/api/close_channel.rs index 170195ffe..1d9d0b0ad 100644 --- a/ldk-server/ldk-server/src/api/close_channel.rs +++ b/ldk-server/ldk-server/src/api/close_channel.rs @@ -3,7 +3,9 @@ use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::UserChannelId; -use ldk_server_protos::api::{CloseChannelRequest, CloseChannelResponse}; +use ldk_server_protos::api::{ + CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse, +}; use std::str::FromStr; pub(crate) const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; @@ -11,18 +13,43 @@ pub(crate) const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; pub(crate) fn handle_close_channel_request( context: Context, request: CloseChannelRequest, ) -> Result { - let user_channel_id = - UserChannelId((&request.user_channel_id).parse::().map_err(|_| { - LdkServerError::new(InvalidRequestError, "Invalid UserChannelId.".to_string()) - })?); - let counterparty_node_id = PublicKey::from_str(&request.counterparty_node_id).map_err(|e| { + let user_channel_id = parse_user_channel_id(&request.user_channel_id)?; + let counterparty_node_id = parse_counterparty_node_id(&request.counterparty_node_id)?; + + context.node.close_channel(&user_channel_id, counterparty_node_id)?; + + Ok(CloseChannelResponse {}) +} + +pub(crate) const FORCE_CLOSE_CHANNEL_PATH: &str = "ForceCloseChannel"; + +pub(crate) fn handle_force_close_channel_request( + context: Context, request: ForceCloseChannelRequest, +) -> Result { + let user_channel_id = parse_user_channel_id(&request.user_channel_id)?; + let counterparty_node_id = parse_counterparty_node_id(&request.counterparty_node_id)?; + + context.node.force_close_channel( + &user_channel_id, + counterparty_node_id, + request.force_close_reason, + )?; + + Ok(ForceCloseChannelResponse {}) +} + +fn parse_user_channel_id(id: &str) -> Result { + let parsed = id.parse::().map_err(|_| { + LdkServerError::new(InvalidRequestError, "Invalid UserChannelId.".to_string()) + })?; + Ok(UserChannelId(parsed)) +} + +fn parse_counterparty_node_id(id: &str) -> Result { + PublicKey::from_str(id).map_err(|e| { LdkServerError::new( InvalidRequestError, format!("Invalid counterparty node ID, error: {}", e), ) - })?; - context.node.close_channel(&user_channel_id, counterparty_node_id)?; - - let response = CloseChannelResponse {}; - Ok(response) + }) } diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index 328ded0c2..6eb02c527 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -11,7 +11,10 @@ use crate::api::bolt11_receive::{handle_bolt11_receive_request, BOLT11_RECEIVE_P use crate::api::bolt11_send::{handle_bolt11_send_request, BOLT11_SEND_PATH}; use crate::api::bolt12_receive::{handle_bolt12_receive_request, BOLT12_RECEIVE_PATH}; use crate::api::bolt12_send::{handle_bolt12_send_request, BOLT12_SEND_PATH}; -use crate::api::close_channel::{handle_close_channel_request, CLOSE_CHANNEL_PATH}; +use crate::api::close_channel::{ + handle_close_channel_request, handle_force_close_channel_request, CLOSE_CHANNEL_PATH, + FORCE_CLOSE_CHANNEL_PATH, +}; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::api::get_balances::{handle_get_balances_request, GET_BALANCES}; @@ -85,6 +88,9 @@ impl Service> for NodeService { CLOSE_CHANNEL_PATH => { Box::pin(handle_request(context, req, handle_close_channel_request)) }, + FORCE_CLOSE_CHANNEL_PATH => { + Box::pin(handle_request(context, req, handle_force_close_channel_request)) + }, LIST_CHANNELS_PATH => { Box::pin(handle_request(context, req, handle_list_channels_request)) }, From 2ed7d7a052443948044f18f82e6fc3e535d6a73f Mon Sep 17 00:00:00 2001 From: moisesPomilio <93723302+moisesPompilio@users.noreply.github.com> Date: Thu, 26 Jun 2025 23:06:48 -0300 Subject: [PATCH 157/203] add force close channel in the cli --- ldk-server/ldk-server-cli/src/main.rs | 28 ++++++++++++++++++++-- ldk-server/ldk-server-client/src/client.rs | 19 +++++++++++---- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 20efa891b..a45ec6ea9 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -6,8 +6,9 @@ use ldk_server_client::error::LdkServerErrorCode::{ }; use ldk_server_client::ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, Bolt12SendRequest, - CloseChannelRequest, GetBalancesRequest, GetNodeInfoRequest, ListChannelsRequest, - ListPaymentsRequest, OnchainReceiveRequest, OnchainSendRequest, OpenChannelRequest, + CloseChannelRequest, ForceCloseChannelRequest, GetBalancesRequest, GetNodeInfoRequest, + ListChannelsRequest, ListPaymentsRequest, OnchainReceiveRequest, OnchainSendRequest, + OpenChannelRequest, }; use ldk_server_client::ldk_server_protos::types::{ bolt11_invoice_description, Bolt11InvoiceDescription, PageToken, Payment, @@ -81,6 +82,14 @@ enum Commands { #[arg(short, long)] counterparty_node_id: String, }, + ForceCloseChannel { + #[arg(short, long)] + user_channel_id: String, + #[arg(short, long)] + counterparty_node_id: String, + #[arg(long)] + force_close_reason: Option, + }, OpenChannel { #[arg(short, long)] node_pubkey: String, @@ -183,6 +192,21 @@ async fn main() { .await, ); }, + Commands::ForceCloseChannel { + user_channel_id, + counterparty_node_id, + force_close_reason, + } => { + handle_response_result( + client + .force_close_channel(ForceCloseChannelRequest { + user_channel_id, + counterparty_node_id, + force_close_reason, + }) + .await, + ); + }, Commands::OpenChannel { node_pubkey, address, diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index e4a519bbb..02d9e56f8 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -7,10 +7,11 @@ use crate::error::LdkServerErrorCode::{ use ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse, Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, - CloseChannelRequest, CloseChannelResponse, GetBalancesRequest, GetBalancesResponse, - GetNodeInfoRequest, GetNodeInfoResponse, ListChannelsRequest, ListChannelsResponse, - ListPaymentsRequest, ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse, - OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, OpenChannelResponse, + CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse, + GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse, + ListChannelsRequest, ListChannelsResponse, ListPaymentsRequest, ListPaymentsResponse, + OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, + OpenChannelRequest, OpenChannelResponse, }; use ldk_server_protos::error::{ErrorCode, ErrorResponse}; use reqwest::header::CONTENT_TYPE; @@ -28,6 +29,7 @@ const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive"; const BOLT12_SEND_PATH: &str = "Bolt12Send"; const OPEN_CHANNEL_PATH: &str = "OpenChannel"; const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; +const FORCE_CLOSE_CHANNEL_PATH: &str = "ForceCloseChannel"; const LIST_CHANNELS_PATH: &str = "ListChannels"; const LIST_PAYMENTS_PATH: &str = "ListPayments"; @@ -134,6 +136,15 @@ impl LdkServerClient { self.post_request(&request, &url).await } + /// Force closes the channel specified by given request. + /// For API contract/usage, refer to docs for [`ForceCloseChannelRequest`] and [`ForceCloseChannelResponse`]. + pub async fn force_close_channel( + &self, request: ForceCloseChannelRequest, + ) -> Result { + let url = format!("http://{}/{FORCE_CLOSE_CHANNEL_PATH}", self.base_url); + self.post_request(&request, &url).await + } + /// Retrieves list of known channels. /// For API contract/usage, refer to docs for [`ListChannelsRequest`] and [`ListChannelsResponse`]. pub async fn list_channels( From 2e90606d6548605b8b7231960a983ea078cfbfe5 Mon Sep 17 00:00:00 2001 From: moisesPomilio <93723302+moisesPompilio@users.noreply.github.com> Date: Thu, 26 Jun 2025 23:10:04 -0300 Subject: [PATCH 158/203] fix configuration file name in running instructions --- ldk-server/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/README.md b/ldk-server/README.md index b15eafb45..8ea707130 100644 --- a/ldk-server/README.md +++ b/ldk-server/README.md @@ -46,7 +46,7 @@ cargo build ### Running ``` -cargo run --bin ldk-server ./ldk-server/ldk-server.config +cargo run --bin ldk-server ./ldk-server/ldk-server-config.toml ``` Interact with the node using CLI: From a5ea162c7282da8d970a0fe3f3bde050015fffc9 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 22 Jul 2025 16:30:44 -0500 Subject: [PATCH 159/203] Allow setting alias in config --- ldk-server/ldk-server/src/util/config.rs | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 110e49914..8256bbb07 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -1,5 +1,6 @@ use ldk_node::bitcoin::Network; use ldk_node::lightning::ln::msgs::SocketAddress; +use ldk_node::lightning::routing::gossip::NodeAlias; use ldk_node::liquidity::LSPS2ServiceConfig; use serde::{Deserialize, Serialize}; use std::net::SocketAddr; @@ -11,6 +12,7 @@ use std::{fs, io}; #[derive(Debug)] pub struct Config { pub listening_addr: SocketAddress, + pub alias: Option, pub network: Network, pub rest_service_addr: SocketAddr, pub storage_dir_path: String, @@ -48,6 +50,21 @@ impl TryFrom for Config { ) })?; + let alias = if let Some(alias_str) = toml_config.node.alias { + let mut bytes = [0u8; 32]; + let alias_bytes = alias_str.trim().as_bytes(); + if alias_bytes.len() > 32 { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "node.alias must be at most 32 bytes long.".to_string(), + )); + } + bytes[..alias_bytes.len()].copy_from_slice(alias_bytes); + Some(NodeAlias(bytes)) + } else { + None + }; + let (rabbitmq_connection_string, rabbitmq_exchange_name) = { let rabbitmq = toml_config.rabbitmq.unwrap_or(RabbitmqConfig { connection_string: String::new(), @@ -77,6 +94,7 @@ impl TryFrom for Config { Ok(Config { listening_addr, network: toml_config.node.network, + alias, rest_service_addr, storage_dir_path: toml_config.storage.disk.dir_path, bitcoind_rpc_addr, @@ -104,6 +122,7 @@ struct NodeConfig { network: Network, listening_address: String, rest_service_address: String, + alias: Option, } #[derive(Deserialize, Serialize)] @@ -209,6 +228,7 @@ mod tests { network = "regtest" listening_address = "localhost:3001" rest_service_address = "127.0.0.1:3002" + alias = "LDK Server" [storage.disk] dir_path = "/tmp" @@ -235,9 +255,14 @@ mod tests { fs::write(storage_path.join(config_file_name), toml_config).unwrap(); + let mut bytes = [0u8; 32]; + let alias = "LDK Server"; + bytes[..alias.as_bytes().len()].copy_from_slice(alias.as_bytes()); + let config = load_config(storage_path.join(config_file_name)).unwrap(); let expected = Config { listening_addr: SocketAddress::from_str("localhost:3001").unwrap(), + alias: Some(NodeAlias(bytes)), network: Network::Regtest, rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(), storage_dir_path: "/tmp".to_string(), From 22864fac0a13f7ce4e9acb582b60dbf9762ed4f8 Mon Sep 17 00:00:00 2001 From: Leo Nash Date: Sat, 15 Nov 2025 20:19:27 +0000 Subject: [PATCH 160/203] Add esplora chain source --- ldk-server/ldk-server/ldk-server-config.toml | 7 + ldk-server/ldk-server/src/main.rs | 23 +-- ldk-server/ldk-server/src/util/config.rs | 155 ++++++++++++++++--- 3 files changed, 153 insertions(+), 32 deletions(-) diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml index 7f5e7ba77..1282f696f 100644 --- a/ldk-server/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -8,12 +8,19 @@ rest_service_address = "127.0.0.1:3002" # LDK Server REST address [storage.disk] dir_path = "/tmp/ldk-server/" # Path for LDK and BDK data persistence + +# Must set either bitcoind or esplora settings, but not both + # Bitcoin Core settings [bitcoind] rpc_address = "127.0.0.1:18444" # RPC endpoint rpc_user = "polaruser" # RPC username rpc_password = "polarpass" # RPC password +# Esplora settings +[esplora] +server_url = "https://mempool.space/api" # Esplora endpoint + # RabbitMQ settings (only required if using events-rabbitmq feature) [rabbitmq] connection_string = "" # RabbitMQ connection string diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 8421530ec..d327d885b 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -24,7 +24,7 @@ use crate::io::persist::{ FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, }; -use crate::util::config::load_config; +use crate::util::config::{load_config, ChainSource}; use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto}; use hex::DisplayHex; use ldk_node::config::Config; @@ -79,14 +79,19 @@ fn main() { let mut builder = Builder::from_config(ldk_node_config); builder.set_log_facade_logger(); - let bitcoind_rpc_addr = config_file.bitcoind_rpc_addr; - - builder.set_chain_source_bitcoind_rpc( - bitcoind_rpc_addr.ip().to_string(), - bitcoind_rpc_addr.port(), - config_file.bitcoind_rpc_user, - config_file.bitcoind_rpc_password, - ); + match config_file.chain_source { + ChainSource::Rpc { rpc_address, rpc_user, rpc_password } => { + builder.set_chain_source_bitcoind_rpc( + rpc_address.ip().to_string(), + rpc_address.port(), + rpc_user, + rpc_password, + ); + }, + ChainSource::Esplora { server_url } => { + builder.set_chain_source_esplora(server_url, None); + }, + } // LSPS2 support is highly experimental and for testing purposes only. #[cfg(feature = "experimental-lsps2-support")] diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 8256bbb07..01548caf2 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -16,14 +16,18 @@ pub struct Config { pub network: Network, pub rest_service_addr: SocketAddr, pub storage_dir_path: String, - pub bitcoind_rpc_addr: SocketAddr, - pub bitcoind_rpc_user: String, - pub bitcoind_rpc_password: String, + pub chain_source: ChainSource, pub rabbitmq_connection_string: String, pub rabbitmq_exchange_name: String, pub lsps2_service_config: Option, } +#[derive(Debug)] +pub enum ChainSource { + Rpc { rpc_address: SocketAddr, rpc_user: String, rpc_password: String }, + Esplora { server_url: String }, +} + impl TryFrom for Config { type Error = io::Error; @@ -42,13 +46,30 @@ impl TryFrom for Config { format!("Invalid rest service address configured: {}", e), ) })?; - let bitcoind_rpc_addr = - SocketAddr::from_str(&toml_config.bitcoind.rpc_address).map_err(|e| { - io::Error::new( + let chain_source = match (toml_config.esplora, toml_config.bitcoind) { + (Some(EsploraConfig { server_url }), None) => ChainSource::Esplora { server_url }, + (None, Some(BitcoindConfig { rpc_address, rpc_user, rpc_password })) => { + let rpc_address = SocketAddr::from_str(&rpc_address).map_err(|e| { + io::Error::new( + io::ErrorKind::InvalidInput, + format!("Invalid bitcoind RPC address configured: {}", e), + ) + })?; + ChainSource::Rpc { rpc_address, rpc_user, rpc_password } + }, + (Some(_), Some(_)) => { + return Err(io::Error::new( io::ErrorKind::InvalidInput, - format!("Invalid bitcoind RPC address configured: {}", e), - ) - })?; + format!("Must set a single chain source, multiple were configured"), + )) + }, + (None, None) => { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + format!("At least one chain source must be set, either bitcoind or esplora"), + )) + }, + }; let alias = if let Some(alias_str) = toml_config.node.alias { let mut bytes = [0u8; 32]; @@ -97,9 +118,7 @@ impl TryFrom for Config { alias, rest_service_addr, storage_dir_path: toml_config.storage.disk.dir_path, - bitcoind_rpc_addr, - bitcoind_rpc_user: toml_config.bitcoind.rpc_user, - bitcoind_rpc_password: toml_config.bitcoind.rpc_password, + chain_source, rabbitmq_connection_string, rabbitmq_exchange_name, lsps2_service_config, @@ -112,7 +131,8 @@ impl TryFrom for Config { pub struct TomlConfig { node: NodeConfig, storage: StorageConfig, - bitcoind: BitcoindConfig, + bitcoind: Option, + esplora: Option, rabbitmq: Option, liquidity: Option, } @@ -142,6 +162,11 @@ struct BitcoindConfig { rpc_password: String, } +#[derive(Deserialize, Serialize)] +struct EsploraConfig { + server_url: String, +} + #[derive(Deserialize, Serialize)] struct RabbitmqConfig { connection_string: String, @@ -233,10 +258,8 @@ mod tests { [storage.disk] dir_path = "/tmp" - [bitcoind] - rpc_address = "127.0.0.1:8332" # RPC endpoint - rpc_user = "bitcoind-testuser" - rpc_password = "bitcoind-testpassword" + [esplora] + server_url = "https://mempool.space/api" [rabbitmq] connection_string = "rabbitmq_connection_string" @@ -266,9 +289,9 @@ mod tests { network: Network::Regtest, rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(), storage_dir_path: "/tmp".to_string(), - bitcoind_rpc_addr: SocketAddr::from_str("127.0.0.1:8332").unwrap(), - bitcoind_rpc_user: "bitcoind-testuser".to_string(), - bitcoind_rpc_password: "bitcoind-testpassword".to_string(), + chain_source: ChainSource::Esplora { + server_url: String::from("https://mempool.space/api"), + }, rabbitmq_connection_string: "rabbitmq_connection_string".to_string(), rabbitmq_exchange_name: "rabbitmq_exchange_name".to_string(), lsps2_service_config: Some(LSPS2ServiceConfig { @@ -288,12 +311,98 @@ mod tests { assert_eq!(config.network, expected.network); assert_eq!(config.rest_service_addr, expected.rest_service_addr); assert_eq!(config.storage_dir_path, expected.storage_dir_path); - assert_eq!(config.bitcoind_rpc_addr, expected.bitcoind_rpc_addr); - assert_eq!(config.bitcoind_rpc_user, expected.bitcoind_rpc_user); - assert_eq!(config.bitcoind_rpc_password, expected.bitcoind_rpc_password); + let ChainSource::Esplora { server_url } = config.chain_source else { + panic!("unexpected config chain source"); + }; + let ChainSource::Esplora { server_url: expected_server_url } = expected.chain_source else { + panic!("unexpected chain source"); + }; + assert_eq!(server_url, expected_server_url); assert_eq!(config.rabbitmq_connection_string, expected.rabbitmq_connection_string); assert_eq!(config.rabbitmq_exchange_name, expected.rabbitmq_exchange_name); #[cfg(feature = "experimental-lsps2-support")] assert_eq!(config.lsps2_service_config.is_some(), expected.lsps2_service_config.is_some()); + + // Test case where only bitcoind is set + + let toml_config = r#" + [node] + network = "regtest" + listening_address = "localhost:3001" + rest_service_address = "127.0.0.1:3002" + alias = "LDK Server" + + [storage.disk] + dir_path = "/tmp" + + [bitcoind] + rpc_address = "127.0.0.1:8332" # RPC endpoint + rpc_user = "bitcoind-testuser" + rpc_password = "bitcoind-testpassword" + + [rabbitmq] + connection_string = "rabbitmq_connection_string" + exchange_name = "rabbitmq_exchange_name" + + [liquidity.lsps2_service] + advertise_service = false + channel_opening_fee_ppm = 1000 # 0.1% fee + channel_over_provisioning_ppm = 500000 # 50% extra capacity + min_channel_opening_fee_msat = 10000000 # 10,000 satoshis + min_channel_lifetime = 4320 # ~30 days + max_client_to_self_delay = 1440 # ~10 days + min_payment_size_msat = 10000000 # 10,000 satoshis + max_payment_size_msat = 25000000000 # 0.25 BTC + "#; + + fs::write(storage_path.join(config_file_name), toml_config).unwrap(); + let config = load_config(storage_path.join(config_file_name)).unwrap(); + + let ChainSource::Rpc { rpc_address, rpc_user, rpc_password } = config.chain_source else { + panic!("unexpected chain source"); + }; + + assert_eq!(rpc_address, SocketAddr::from_str("127.0.0.1:8332").unwrap()); + assert_eq!(rpc_user, "bitcoind-testuser"); + assert_eq!(rpc_password, "bitcoind-testpassword"); + + // Test case where both bitcoind and esplora are set, resulting in an error + + let toml_config = r#" + [node] + network = "regtest" + listening_address = "localhost:3001" + rest_service_address = "127.0.0.1:3002" + alias = "LDK Server" + + [storage.disk] + dir_path = "/tmp" + + [bitcoind] + rpc_address = "127.0.0.1:8332" # RPC endpoint + rpc_user = "bitcoind-testuser" + rpc_password = "bitcoind-testpassword" + + [esplora] + server_url = "https://mempool.space/api" + + [rabbitmq] + connection_string = "rabbitmq_connection_string" + exchange_name = "rabbitmq_exchange_name" + + [liquidity.lsps2_service] + advertise_service = false + channel_opening_fee_ppm = 1000 # 0.1% fee + channel_over_provisioning_ppm = 500000 # 50% extra capacity + min_channel_opening_fee_msat = 10000000 # 10,000 satoshis + min_channel_lifetime = 4320 # ~30 days + max_client_to_self_delay = 1440 # ~10 days + min_payment_size_msat = 10000000 # 10,000 satoshis + max_payment_size_msat = 25000000000 # 0.25 BTC + "#; + + fs::write(storage_path.join(config_file_name), toml_config).unwrap(); + let error = load_config(storage_path.join(config_file_name)).unwrap_err(); + assert_eq!(error.to_string(), "Must set a single chain source, multiple were configured"); } } From 310aa81554f90ff7c9bbc406fbc932d46c5dbe43 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Mon, 1 Dec 2025 15:12:23 -0600 Subject: [PATCH 161/203] Update ldk-node to 0.7.0 Co-Authored-By: Jeffrey Czyz --- ldk-server/Cargo.lock | 1575 ++++++++++------- .../ldk-server-protos/src/proto/types.proto | 6 + ldk-server/ldk-server-protos/src/types.rs | 6 + ldk-server/ldk-server/Cargo.toml | 2 +- ldk-server/ldk-server/ldk-server-config.toml | 5 + ldk-server/ldk-server/src/api/bolt12_send.rs | 5 +- ldk-server/ldk-server/src/api/error.rs | 5 +- ldk-server/ldk-server/src/main.rs | 33 +- ldk-server/ldk-server/src/util/config.rs | 7 + .../ldk-server/src/util/proto_adapter.rs | 31 +- 10 files changed, 1007 insertions(+), 668 deletions(-) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 1aa8892d1..60a3b4d3b 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -1,21 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +version = 4 [[package]] name = "aes" @@ -30,30 +15,30 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] name = "amq-protocol" -version = "7.2.2" +version = "7.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a41c091e49edfcc098b4f90d4d7706a8cf9158034e84ebfee7ff346092f67c" +checksum = "587d313f3a8b4a40f866cc84b6059fe83133bf172165ac3b583129dd211d8e1c" dependencies = [ "amq-protocol-tcp", "amq-protocol-types", @@ -65,9 +50,9 @@ dependencies = [ [[package]] name = "amq-protocol-tcp" -version = "7.2.2" +version = "7.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed7a4a662472f88823ed2fc81babb0b00562f2c54284e3e7bffc02b6df649bf" +checksum = "dc707ab9aa964a85d9fc25908a3fdc486d2e619406883b3105b48bf304a8d606" dependencies = [ "amq-protocol-uri", "tcp-stream", @@ -76,9 +61,9 @@ dependencies = [ [[package]] name = "amq-protocol-types" -version = "7.2.2" +version = "7.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6484fdc918c1b6e2ae8eda2914d19a5873e1975f93ad8d33d6a24d1d98df05" +checksum = "bf99351d92a161c61ec6ecb213bc7057f5b837dd4e64ba6cb6491358efd770c4" dependencies = [ "cookie-factory", "nom", @@ -88,21 +73,15 @@ dependencies = [ [[package]] name = "amq-protocol-uri" -version = "7.2.2" +version = "7.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7f2da69e0e1182765bf33407cd8a843f20791b5af2b57a2645818c4776c56c" +checksum = "f89f8273826a676282208e5af38461a07fe939def57396af6ad5997fcf56577d" dependencies = [ "amq-protocol-types", "percent-encoding", "url", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -114,15 +93,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arrayvec" @@ -142,7 +121,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 2.0.12", + "thiserror", "time", ] @@ -154,7 +133,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", "synstructure", ] @@ -166,14 +145,14 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", ] [[package]] name = "async-channel" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ "concurrent-queue", "event-listener-strategy", @@ -183,14 +162,15 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.1" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" dependencies = [ "async-task", "concurrent-queue", "fastrand 2.3.0", - "futures-lite 2.6.0", + "futures-lite 2.6.1", + "pin-project-lite", "slab", ] @@ -202,10 +182,10 @@ checksum = "13f937e26114b93193065fd44f507aa2e9169ad0cdabbb996920b1fe1ddea7ba" dependencies = [ "async-channel", "async-executor", - "async-io 2.4.0", - "async-lock 3.4.0", + "async-io 2.6.0", + "async-lock 3.4.1", "blocking", - "futures-lite 2.6.0", + "futures-lite 2.6.1", ] [[package]] @@ -241,21 +221,20 @@ dependencies = [ [[package]] name = "async-io" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock 3.4.0", + "autocfg", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.6.0", + "futures-lite 2.6.1", "parking", - "polling 3.7.4", - "rustix 0.38.44", + "polling 3.11.0", + "rustix 1.1.2", "slab", - "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -269,11 +248,11 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ - "event-listener 5.4.0", + "event-listener 5.4.1", "event-listener-strategy", "pin-project-lite", ] @@ -298,13 +277,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.86" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", ] [[package]] @@ -315,24 +294,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "backtrace" -version = "0.3.74" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "base58ck" @@ -358,15 +322,15 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.7.3" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "bdk_chain" -version = "0.21.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4955734f97b2baed3f36d16ae7c203fdde31ae85391ac44ee3cbcaf0886db5ce" +checksum = "5b5d691fd092aacec7e05046b7d04897d58d6d65ed3152cb6cf65dababcfabed" dependencies = [ "bdk_core", "bitcoin", @@ -376,20 +340,30 @@ dependencies = [ [[package]] name = "bdk_core" -version = "0.4.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b545aea1efc090e4f71f1dd5468090d9f54c3de48002064c04895ef811fbe0b2" +checksum = "0dbbe4aad0c898bfeb5253c222be3ea3dccfb380a07e72c87e3e4ed6664a6753" 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.20.1" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7fdf5efbebabc0c0bb46c0348ef0d4db505856c7d6c5d50cebba1e5eda5fe4" +checksum = "0c9f5961444b5f51b9c3937e729a212363d0e4cde6390ded6e01e16292078df4" dependencies = [ "async-trait", "bdk_core", @@ -399,9 +373,9 @@ dependencies = [ [[package]] name = "bdk_wallet" -version = "1.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a13c947be940d32a91b876fc5223a6d839a40bc219496c5c78af74714b1b3f7" +checksum = "8b172f2caa6311b8172cf99559cd7f7a61cb58834e35e4ca208b3299e7be8bec" dependencies = [ "bdk_chain", "bip39", @@ -430,20 +404,22 @@ dependencies = [ [[package]] name = "bip39" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33415e24172c1b7d6066f6d999545375ab8e1d95421d6784bdfff9496f292387" +checksum = "43d193de1f7487df1914d3a568b772458861d33f9c54249612cc2893d6915054" dependencies = [ "bitcoin_hashes 0.13.0", + "rand 0.8.5", + "rand_core 0.6.4", "serde", "unicode-normalization", ] [[package]] name = "bitcoin" -version = "0.32.5" +version = "0.32.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6bc65742dea50536e35ad42492b234c27904a27f0abdcbce605015cb4ea026" +checksum = "0fda569d741b895131a88ee5589a467e73e9c4718e958ac9308e4f7dc44b6945" dependencies = [ "base58ck", "base64 0.21.7", @@ -518,9 +494,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "block-buffer" @@ -542,22 +518,22 @@ dependencies = [ [[package]] name = "blocking" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ "async-channel", "async-task", "futures-io", - "futures-lite 2.6.0", + "futures-lite 2.6.1", "piper", ] [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "byteorder" @@ -567,9 +543,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cbc" @@ -582,30 +558,42 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.14" +version = "1.2.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" +checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20-poly1305" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "4b4b0fc281743d80256607bd65e8beedc42cb0787ea119c85b81b4c0eab85e5f" [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "num-traits", "serde", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -626,9 +614,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.30" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -636,9 +624,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.30" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstyle", "clap_lex", @@ -647,21 +635,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.28" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "cms" @@ -739,15 +727,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "der" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "der_derive", @@ -778,14 +766,14 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", ] [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -818,26 +806,43 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", ] [[package]] name = "dnssec-prover" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96487aad690d45a83f2b9876828ba856c5430bbb143cb5730d8a5d04a4805179" +checksum = "ec4f825369fc7134da70ca4040fddc8e03b80a46d249ae38d9c1c39b7b4476bf" [[package]] name = "doc-comment" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "electrum-client" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "ede7b07e2578a6df0093b101915c79dca0119d7f7810099ad9eef11341d2ae57" +dependencies = [ + "bitcoin", + "byteorder", + "libc", + "log", + "rustls 0.23.34", + "serde", + "serde_json", + "webpki-roots 0.25.4", + "winapi", +] [[package]] name = "encoding_rs" @@ -856,24 +861,24 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "esplora-client" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0da3c186d286e046253ccdc4bb71aa87ef872e4eff2045947c0c4fe3d2b2efc" +checksum = "a0af349d96a5d9ad77ba59f1437aa6f348b03c5865d4f7d6e7a662d60aedce39" dependencies = [ "bitcoin", "hex-conservative 0.2.1", "log", - "reqwest", + "reqwest 0.12.24", "serde", "tokio", ] @@ -886,9 +891,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -897,11 +902,11 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.0", + "event-listener 5.4.1", "pin-project-lite", ] @@ -941,6 +946,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + [[package]] name = "fixedbitset" version = "0.4.2" @@ -949,9 +960,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flagset" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" +checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" [[package]] name = "flume" @@ -972,9 +983,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -1044,9 +1055,9 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ "fastrand 2.3.0", "futures-core", @@ -1063,7 +1074,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", ] [[package]] @@ -1098,9 +1109,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -1108,38 +1119,36 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", + "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.6", + "r-efi", + "wasip2", + "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "h2" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ "bytes", "fnv", @@ -1172,9 +1181,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "hashlink" @@ -1205,9 +1214,9 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -1247,11 +1256,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.9" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1267,9 +1276,9 @@ dependencies = [ [[package]] name = "http" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -1294,27 +1303,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.2.0", + "http 1.3.1", ] [[package]] name = "http-body-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "futures-util", - "http 1.2.0", + "futures-core", + "http 1.3.1", "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -1339,7 +1348,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.8", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -1348,21 +1357,24 @@ dependencies = [ [[package]] name = "hyper" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", - "http 1.2.0", + "futures-core", + "http 1.3.1", "http-body 1.0.1", "httparse", "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", + "want", ] [[package]] @@ -1376,34 +1388,61 @@ dependencies = [ "hyper 0.14.32", "rustls 0.21.12", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +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", + "hyper-util", + "rustls 0.23.34", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.4", + "tower-service", + "webpki-roots 1.0.3", ] [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ + "base64 0.22.1", "bytes", + "futures-channel", + "futures-core", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body 1.0.1", - "hyper 1.6.0", + "hyper 1.7.0", + "ipnet", + "libc", + "percent-encoding", "pin-project-lite", + "socket2 0.6.1", "tokio", + "tower-service", + "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -1419,21 +1458,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -1442,104 +1482,66 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", + "icu_locale_core", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", -] - [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -1548,9 +1550,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -1558,12 +1560,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.16.0", ] [[package]] @@ -1602,6 +1604,16 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "itertools" version = "0.10.5" @@ -1613,15 +1625,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -1629,9 +1641,9 @@ dependencies = [ [[package]] name = "lapin" -version = "2.5.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3551b363b2fcf985fa39c47114333fa12fbb6518f863d4fd9556d0e19f48c1c9" +checksum = "02d2aa4725b9607915fa1a73e940710a3be6af508ce700e56897cbe8847fbb07" dependencies = [ "amq-protocol", "async-global-executor-trait", @@ -1657,17 +1669,20 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "ldk-node" -version = "0.5.0+git" -source = "git+https://github.com/lightningdevkit/ldk-node.git?rev=f0338d19256615088fabab2b6927d478ae3ec1a1#f0338d19256615088fabab2b6927d478ae3ec1a1" +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", @@ -1675,6 +1690,7 @@ dependencies = [ "lightning-block-sync", "lightning-invoice", "lightning-liquidity", + "lightning-macros", "lightning-net-tokio", "lightning-persister", "lightning-rapid-gossip-sync", @@ -1682,13 +1698,14 @@ dependencies = [ "lightning-types", "log", "prost", - "rand 0.8.5", - "reqwest", + "rand 0.9.2", + "reqwest 0.12.24", "rusqlite", + "rustls 0.23.34", "serde", "serde_json", "tokio", - "vss-client", + "vss-client-ng", "winapi", ] @@ -1701,7 +1718,7 @@ dependencies = [ "futures-util", "hex-conservative 0.2.1", "http-body-util", - "hyper 1.6.0", + "hyper 1.7.0", "hyper-util", "lapin", "ldk-node", @@ -1730,7 +1747,7 @@ version = "0.1.0" dependencies = [ "ldk-server-protos", "prost", - "reqwest", + "reqwest 0.11.27", ] [[package]] @@ -1743,15 +1760,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.169" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libm" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libsqlite3-sys" @@ -1766,9 +1783,9 @@ dependencies = [ [[package]] name = "lightning" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3224b577def19c2bb3dcf2c35a95d94909183204c061746d1245ecc6e889e8e" +checksum = "4342d07db2b3fe7c9a73849e94d012ebcfa3588c25097daf0b5ff2857c04e0e1" dependencies = [ "bech32", "bitcoin", @@ -1776,28 +1793,31 @@ dependencies = [ "hashbrown 0.13.2", "libm", "lightning-invoice", + "lightning-macros", "lightning-types", "possiblyrandom", ] [[package]] name = "lightning-background-processor" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04231b97fd7509d73ce9857a416eb1477a55d076d4e22cbf26c649a772bde909" +checksum = "abdc5450264184deba88b1dc61fa8d2ca905e21748bad556915757ac73d91103" dependencies = [ "bitcoin", "bitcoin-io", "bitcoin_hashes 0.14.0", "lightning", + "lightning-liquidity", "lightning-rapid-gossip-sync", + "possiblyrandom", ] [[package]] name = "lightning-block-sync" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baab5bdee174a2047d939a4ca0dc2e1c23caa0f8cab0b4380aed77a20e116f1e" +checksum = "ee5069846b07a62aaecdaf25233e067bc69f245b7c8fd00cc9c217053221f875" dependencies = [ "bitcoin", "chunked_transfer", @@ -1808,9 +1828,9 @@ dependencies = [ [[package]] name = "lightning-invoice" -version = "0.33.1" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4254e7d05961a3728bc90737c522e7091735ba6f2f71014096d4b3eb4ee5d89" +checksum = "b85e5e14bcdb30d746e9785b04f27938292e8944f78f26517e01e91691f6b3f2" dependencies = [ "bech32", "bitcoin", @@ -1820,14 +1840,15 @@ dependencies = [ [[package]] name = "lightning-liquidity" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfbed71e656557185f25e006c1bcd8773c5c83387c727166666d3b0bce0f0ca5" +checksum = "58a6480d4d7726c49b4cd170b18a39563bbe897d0b8960be11d5e4a0cebd43b0" dependencies = [ "bitcoin", "chrono", "lightning", "lightning-invoice", + "lightning-macros", "lightning-types", "serde", "serde_json", @@ -1835,20 +1856,20 @@ dependencies = [ [[package]] name = "lightning-macros" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d44a6fb8c698180c758fd391ae9631be92a4dbf0a82121e7dd8b1a28d0cfa75" +checksum = "80bd6063f4d0c34320f1db9193138c878e64142e6d1c42bd5f0124936e8764ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", ] [[package]] name = "lightning-net-tokio" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6a6c93b1e592f1d46bb24233cac4a33b4015c99488ee229927a81d16226e45" +checksum = "8055737e3d2d06240a3fdf10e26b2716110fcea90011a0839e8e82fc6e58ff5e" dependencies = [ "bitcoin", "lightning", @@ -1857,20 +1878,21 @@ dependencies = [ [[package]] name = "lightning-persister" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d80558dc398eb4609b1079044d8eb5760a58724627ff57c6d7c194c78906e026" +checksum = "e6d78990de56ca75c5535c3f8e6f86b183a1aa8f521eb32afb9e8181f3bd91d7" dependencies = [ "bitcoin", "lightning", + "tokio", "windows-sys 0.48.0", ] [[package]] name = "lightning-rapid-gossip-sync" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78dacdef3e2f5d727754f902f4e6bbc43bfc886fec8e71f36757711060916ebe" +checksum = "b094f79f22713aa95194a166c77b2f6c7d68f9d76622a43552a29b8fe6fa92d0" dependencies = [ "bitcoin", "bitcoin-io", @@ -1880,11 +1902,12 @@ dependencies = [ [[package]] name = "lightning-transaction-sync" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031493ff20f40c9bbf80dde70ca5bb5ce86f65d6fda939bfecb5a2d59dc54767" +checksum = "2f16c2cc74a73e29295bb5c0de61f4a0e6fe7151562ebdd48ee9935fcaa59bd8" dependencies = [ "bitcoin", + "electrum-client", "esplora-client", "futures", "lightning", @@ -1893,9 +1916,9 @@ dependencies = [ [[package]] name = "lightning-types" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cd84d4e71472035903e43caded8ecc123066ce466329ccd5ae537a8d5488c7" +checksum = "5681708d3075bdff3a1b4daa400590e2703e7871bdc14e94ee7334fb6314ae40" dependencies = [ "bitcoin", ] @@ -1912,33 +1935,44 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + [[package]] name = "litemap" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.25" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "lru-slab" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mime" @@ -1954,33 +1988,24 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniscript" -version = "12.3.0" +version = "12.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd3c9608217b0d6fa9c9c8ddd875b85ab72bd4311cfc8db35e1b5a08fc11f4d" +checksum = "487906208f38448e186e3deb02f2b8ef046a9078b0de00bdb28bf4fb9b76951c" dependencies = [ "bech32", "bitcoin", "serde", ] -[[package]] -name = "miniz_oxide" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" -dependencies = [ - "adler2", -] - [[package]] name = "mio" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -2033,15 +2058,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "oid-registry" version = "0.8.1" @@ -2053,9 +2069,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl-probe" @@ -2065,9 +2081,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "p12-keystore" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a09eaa3a6d8884c204c2ab17e313f563b524362e62567f09ba27857a6e31257f" +checksum = "3cae83056e7cb770211494a0ecf66d9fa7eba7d00977e5bb91f0e925b40b937f" dependencies = [ "cbc", "cms", @@ -2077,11 +2093,11 @@ dependencies = [ "hmac", "pkcs12", "pkcs5", - "rand 0.9.0", + "rand 0.9.2", "rc2", "sha1", "sha2", - "thiserror 2.0.12", + "thiserror", "x509-parser", ] @@ -2093,9 +2109,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -2103,15 +2119,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -2135,9 +2151,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "percent-encoding-rfc3986" @@ -2169,9 +2185,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pinky-swear" -version = "6.2.0" +version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cfae3ead413ca051a681152bd266438d3bfa301c9bdf836939a14c721bb2a21" +checksum = "b1ea6e230dd3a64d61bcb8b79e597d3ab6b4c94ec7a234ce687dd718b4f2e657" dependencies = [ "doc-comment", "flume", @@ -2222,9 +2238,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "polling" @@ -2244,17 +2260,16 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.4" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi 0.4.0", + "hermit-abi 0.5.2", "pin-project-lite", - "rustix 0.38.44", - "tracing", - "windows-sys 0.59.0", + "rustix 1.1.2", + "windows-sys 0.61.2", ] [[package]] @@ -2263,7 +2278,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b122a615d72104fb3d8b26523fdf9232cd8ee06949fb37e4ce3ff964d15dffd" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", ] [[package]] @@ -2274,11 +2298,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -2293,9 +2317,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -2355,34 +2379,94 @@ dependencies = [ ] [[package]] -name = "quote" -version = "1.0.38" +name = "quinn" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ - "proc-macro2", + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.34", + "socket2 0.6.1", + "thiserror", + "tokio", + "tracing", + "web-time", ] [[package]] -name = "rand" -version = "0.8.5" +name = "quinn-proto" +version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ - "libc", + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls 0.23.34", + "rustls-pki-types", + "slab", + "thiserror", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2 0.6.1", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", ] [[package]] name = "rand" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy 0.8.23", ] [[package]] @@ -2411,7 +2495,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -2420,7 +2504,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.3.4", ] [[package]] @@ -2445,18 +2529,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -2466,9 +2550,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -2477,9 +2561,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reqwest" @@ -2496,7 +2580,7 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.32", - "hyper-rustls", + "hyper-rustls 0.24.2", "ipnet", "js-sys", "log", @@ -2509,29 +2593,68 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", - "tokio-rustls", - "tokio-socks", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.25.4", "winreg", ] +[[package]] +name = "reqwest" +version = "0.12.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.7.0", + "hyper-rustls 0.27.7", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls 0.23.34", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tokio-rustls 0.26.4", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 1.0.3", +] + [[package]] name = "ring" -version = "0.17.9" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -2543,7 +2666,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -2552,10 +2675,10 @@ dependencies = [ ] [[package]] -name = "rustc-demangle" -version = "0.1.24" +name = "rustc-hash" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rusticata-macros" @@ -2586,13 +2709,26 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.4.15", "windows-sys 0.59.0", ] +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.10.0", + "errno", + "libc", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", +] + [[package]] name = "rustls" version = "0.21.12" @@ -2607,29 +2743,30 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.25" +version = "0.23.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" +checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" dependencies = [ + "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.0", + "rustls-webpki 0.103.8", "subtle", "zeroize", ] [[package]] name = "rustls-connector" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a980454b497c439c274f2feae2523ed8138bbd3d323684e1435fec62f800481" +checksum = "70cc376c6ba1823ae229bacf8ad93c136d93524eab0e4e5e0e4f96b9c4e5b212" dependencies = [ "log", - "rustls 0.23.25", + "rustls 0.23.34", "rustls-native-certs", "rustls-pki-types", - "rustls-webpki 0.102.8", + "rustls-webpki 0.103.8", ] [[package]] @@ -2665,36 +2802,29 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" - -[[package]] -name = "rustls-webpki" -version = "0.101.7" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ - "ring", - "untrusted", + "web-time", + "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.102.8" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", - "rustls-pki-types", "untrusted", ] [[package]] name = "rustls-webpki" -version = "0.103.0" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa4eeac2588ffff23e9d7a7e9b3f971c5fb5b7ebc9452745e0c232c64f83b2f" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "ring", "rustls-pki-types", @@ -2703,15 +2833,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa20" @@ -2724,11 +2854,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2785,7 +2915,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.10.0", "core-foundation", "core-foundation-sys", "libc", @@ -2794,9 +2924,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -2804,41 +2934,52 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.217" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", ] [[package]] name = "serde_json" -version = "1.0.138" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -2868,9 +3009,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -2885,27 +3026,24 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] [[package]] name = "slab" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" @@ -2919,14 +3057,24 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + [[package]] name = "spin" version = "0.9.8" @@ -2948,9 +3096,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "strsim" @@ -2977,9 +3125,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.98" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -2992,15 +3140,24 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", ] [[package]] @@ -3038,63 +3195,42 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.17.1" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ - "cfg-if", "fastrand 2.3.0", - "getrandom 0.3.1", + "getrandom 0.3.4", "once_cell", - "rustix 0.38.44", - "windows-sys 0.59.0", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", + "rustix 1.1.2", + "windows-sys 0.61.2", ] [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.69" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", + "syn 2.0.108", ] [[package]] name = "time" -version = "0.3.40" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", @@ -3107,15 +3243,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.21" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29aa485584182073ed57fd5004aa09c371f021325014694e432313345865fd04" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -3123,9 +3259,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -3133,9 +3269,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -3148,30 +3284,29 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.43.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", "libc", "mio", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.8", + "socket2 0.6.1", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", ] [[package]] @@ -3185,22 +3320,20 @@ dependencies = [ ] [[package]] -name = "tokio-socks" -version = "0.5.2" +name = "tokio-rustls" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "either", - "futures-util", - "thiserror 1.0.69", + "rustls 0.23.34", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.13" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", @@ -3211,9 +3344,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -3223,18 +3356,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", @@ -3243,6 +3376,45 @@ dependencies = [ "winnow", ] +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.10.0", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" version = "0.3.3" @@ -3261,9 +3433,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", ] @@ -3276,21 +3448,21 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -3303,21 +3475,16 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -3337,19 +3504,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "vss-client" -version = "0.3.1" +name = "vss-client-ng" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d787f7640ceae8caef95434f1b14936402b73e18d34868b052a502a5d5085490" +checksum = "52c6bf7f2c3e22e62c638ad7d8c48dd5dc7e79033c5e088bdd797bbc815b29bb" dependencies = [ "async-trait", - "base64 0.21.7", + "base64 0.22.1", "bitcoin", "bitcoin_hashes 0.14.0", + "chacha20-poly1305", "prost", "prost-build", "rand 0.8.5", - "reqwest", + "reqwest 0.12.24", "serde", "serde_json", "tokio", @@ -3373,50 +3541,37 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.13.3+wasi-0.2.2" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.98", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -3427,9 +3582,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3437,31 +3592,41 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.98", - "wasm-bindgen-backend", + "syn 2.0.108", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -3473,6 +3638,15 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "webpki-roots" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "which" version = "4.4.2" @@ -3509,11 +3683,61 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.52.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-targets 0.52.6", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[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.108", +] + +[[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.108", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", ] [[package]] @@ -3543,6 +3767,24 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -3567,13 +3809,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3586,6 +3845,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3598,6 +3863,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3610,12 +3881,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3628,6 +3911,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3640,6 +3929,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -3652,6 +3947,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3664,11 +3965,17 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winnow" -version = "0.7.4" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] @@ -3684,25 +3991,16 @@ dependencies = [ ] [[package]] -name = "wit-bindgen-rt" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" -dependencies = [ - "bitflags 2.8.0", -] - -[[package]] -name = "write16" -version = "1.0.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "x509-cert" @@ -3728,17 +4026,16 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror 2.0.12", + "thiserror", "time", ] [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -3746,89 +4043,79 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ - "byteorder", - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" -dependencies = [ - "zerocopy-derive 0.8.23", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", + "syn 2.0.108", ] [[package]] name = "zerofrom" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -3837,11 +4124,11 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.108", ] diff --git a/ldk-server/ldk-server-protos/src/proto/types.proto b/ldk-server/ldk-server-protos/src/proto/types.proto index e8e23ebe1..5f4144126 100644 --- a/ldk-server/ldk-server-protos/src/proto/types.proto +++ b/ldk-server/ldk-server-protos/src/proto/types.proto @@ -101,6 +101,12 @@ message Bolt11Jit { // See [`LdkChannelConfig::accept_underpaying_htlcs`](https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.accept_underpaying_htlcs) // for more information. LSPFeeLimits lsp_fee_limits = 4; + + // The value, in thousands of a satoshi, that was deducted from this payment as an extra + // fee taken by our channel counterparty. + // + // Will only be `Some` once we received the payment. + optional uint64 counterparty_skimmed_fee_msat = 5; } // Represents a BOLT 12 ‘offer’ payment, i.e., a payment for an Offer. diff --git a/ldk-server/ldk-server-protos/src/types.rs b/ldk-server/ldk-server-protos/src/types.rs index 9c65fea0e..2e5dc8c2f 100644 --- a/ldk-server/ldk-server-protos/src/types.rs +++ b/ldk-server/ldk-server-protos/src/types.rs @@ -134,6 +134,12 @@ pub struct Bolt11Jit { /// for more information. #[prost(message, optional, tag = "4")] pub lsp_fee_limits: ::core::option::Option, + /// The value, in thousands of a satoshi, that was deducted from this payment as an extra + /// fee taken by our channel counterparty. + /// + /// Will only be `Some` once we received the payment. + #[prost(uint64, optional, tag = "5")] + pub counterparty_skimmed_fee_msat: ::core::option::Option, } /// Represents a BOLT 12 ‘offer’ payment, i.e., a payment for an Offer. #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index fb3527a26..c2c46ecc1 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -ldk-node = { git = "https://github.com/lightningdevkit/ldk-node.git", rev = "f0338d19256615088fabab2b6927d478ae3ec1a1" } +ldk-node = { version = "0.7.0" } serde = { version = "1.0.203", default-features = false, features = ["derive"] } hyper = { version = "1", default-features = false, features = ["server", "http1"] } http-body-util = { version = "0.1", default-features = false } diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml index 1282f696f..7727cff5f 100644 --- a/ldk-server/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -53,6 +53,11 @@ min_payment_size_msat = 10000000 # 10,000 satoshis # The maximum payment size that we will accept when opening a channel. max_payment_size_msat = 25000000000 # 0.25 BTC +# Use the 'client-trusts-LSP' trust model. +# When set, the service will delay broadcasting the JIT channel's +# funding transaction until the client claimed sufficient HTLC parts to pay for the channel open. +client_trusts_lsp = false + # Optional token for clients (uncomment and set if required) ## A token we may require to be sent by the clients. ## If set, only requests matching this token will be accepted. (uncomment and set if required) diff --git a/ldk-server/ldk-server/src/api/bolt12_send.rs b/ldk-server/ldk-server/src/api/bolt12_send.rs index ed1dea503..bbf392a75 100644 --- a/ldk-server/ldk-server/src/api/bolt12_send.rs +++ b/ldk-server/ldk-server/src/api/bolt12_send.rs @@ -13,12 +13,15 @@ pub(crate) fn handle_bolt12_send_request( Offer::from_str(&request.offer.as_str()).map_err(|_| ldk_node::NodeError::InvalidOffer)?; let payment_id = match request.amount_msat { - None => context.node.bolt12_payment().send(&offer, request.quantity, request.payer_note), + None => { + context.node.bolt12_payment().send(&offer, request.quantity, request.payer_note, None) + }, Some(amount_msat) => context.node.bolt12_payment().send_using_amount( &offer, amount_msat, request.quantity, request.payer_note, + None, ), }?; diff --git a/ldk-server/ldk-server/src/api/error.rs b/ldk-server/ldk-server/src/api/error.rs index 4fa365f9b..c9103da08 100644 --- a/ldk-server/ldk-server/src/api/error.rs +++ b/ldk-server/ldk-server/src/api/error.rs @@ -78,7 +78,9 @@ impl From for LdkServerError { | NodeError::InvalidNodeAlias | NodeError::InvalidDateTime | NodeError::InvalidFeeRate - | NodeError::UriParameterParsingFailed => { + | NodeError::UriParameterParsingFailed + | NodeError::InvalidBlindedPaths + | NodeError::AsyncPaymentServicesDisabled => { (error.to_string(), LdkServerErrorCode::InvalidRequestError) }, @@ -92,6 +94,7 @@ impl From for LdkServerError { | NodeError::ProbeSendingFailed | NodeError::ChannelCreationFailed | NodeError::ChannelClosingFailed + | NodeError::ChannelSplicingFailed | NodeError::ChannelConfigUpdateFailed | NodeError::DuplicatePayment | NodeError::InsufficientFunds diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index d327d885b..0962a3c49 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -29,8 +29,6 @@ use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto}; use hex::DisplayHex; use ldk_node::config::Config; use ldk_node::lightning::ln::channelmanager::PaymentId; -#[cfg(feature = "experimental-lsps2-support")] -use ldk_node::liquidity::LSPS2ServiceConfig; use ldk_server_protos::events; use ldk_server_protos::events::{event_envelope, EventEnvelope}; use ldk_server_protos::types::Payment; @@ -79,6 +77,13 @@ fn main() { let mut builder = Builder::from_config(ldk_node_config); builder.set_log_facade_logger(); + if let Some(alias) = config_file.alias { + if let Err(e) = builder.set_node_alias(alias.to_string()) { + eprintln!("Failed to set node alias: {e}"); + std::process::exit(-1); + } + } + match config_file.chain_source { ChainSource::Rpc { rpc_address, rpc_user, rpc_password } => { builder.set_chain_source_bitcoind_rpc( @@ -107,6 +112,8 @@ fn main() { }, }; + builder.set_runtime(runtime.handle().clone()); + let node = match builder.build() { Ok(node) => Arc::new(node), Err(e) => { @@ -136,7 +143,7 @@ fn main() { }; println!("Starting up..."); - match node.start_with_runtime(Arc::clone(&runtime)) { + match node.start() { Ok(()) => {}, Err(e) => { eprintln!("Failed to start up LDK Node: {}", e); @@ -171,14 +178,18 @@ fn main() { "CHANNEL_PENDING: {} from counterparty {}", channel_id, counterparty_node_id ); - event_node.event_handled(); + if let Err(e) = event_node.event_handled() { + eprintln!("Failed to mark event as handled: {e}"); + } }, Event::ChannelReady { channel_id, counterparty_node_id, .. } => { println!( "CHANNEL_READY: {} from counterparty {:?}", channel_id, counterparty_node_id ); - event_node.event_handled(); + if let Err(e) = event_node.event_handled() { + eprintln!("Failed to mark event as handled: {e}"); + } }, Event::PaymentReceived { payment_id, payment_hash, amount_msat, .. } => { println!( @@ -281,7 +292,9 @@ fn main() { &forwarded_payment.encode_to_vec(), ) { Ok(_) => { - event_node.event_handled(); + if let Err(e) = event_node.event_handled() { + eprintln!("Failed to mark event as handled: {e}"); + } } Err(e) => { println!("Failed to write forwarded payment to persistence: {}", e); @@ -289,7 +302,9 @@ fn main() { } }, _ => { - event_node.event_handled(); + if let Err(e) = event_node.event_handled() { + eprintln!("Failed to mark event as handled: {e}"); + } }, } }, @@ -361,7 +376,9 @@ fn upsert_payment_details( &payment.encode_to_vec(), ) { Ok(_) => { - event_node.event_handled(); + if let Err(e) = event_node.event_handled() { + eprintln!("Failed to mark event as handled: {e}"); + } }, Err(e) => { eprintln!("Failed to write payment to persistence: {}", e); diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 01548caf2..11e5bdfd0 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -188,6 +188,7 @@ struct LSPS2ServiceTomlConfig { max_client_to_self_delay: u32, min_payment_size_msat: u64, max_payment_size_msat: u64, + client_trusts_lsp: bool, require_token: Option, } @@ -203,6 +204,7 @@ impl Into for LSPS2ServiceTomlConfig { max_client_to_self_delay, min_payment_size_msat, max_payment_size_msat, + client_trusts_lsp, require_token, } => LSPS2ServiceConfig { advertise_service, @@ -213,6 +215,7 @@ impl Into for LSPS2ServiceTomlConfig { min_payment_size_msat, max_client_to_self_delay, max_payment_size_msat, + client_trusts_lsp, require_token, }, } @@ -274,6 +277,7 @@ mod tests { max_client_to_self_delay = 1440 # ~10 days min_payment_size_msat = 10000000 # 10,000 satoshis max_payment_size_msat = 25000000000 # 0.25 BTC + client_trusts_lsp = true "#; fs::write(storage_path.join(config_file_name), toml_config).unwrap(); @@ -304,6 +308,7 @@ mod tests { max_client_to_self_delay: 1440, min_payment_size_msat: 10000000, max_payment_size_msat: 25000000000, + client_trusts_lsp: true, }), }; @@ -353,6 +358,7 @@ mod tests { max_client_to_self_delay = 1440 # ~10 days min_payment_size_msat = 10000000 # 10,000 satoshis max_payment_size_msat = 25000000000 # 0.25 BTC + client_trusts_lsp = true "#; fs::write(storage_path.join(config_file_name), toml_config).unwrap(); @@ -399,6 +405,7 @@ mod tests { max_client_to_self_delay = 1440 # ~10 days min_payment_size_msat = 10000000 # 10,000 satoshis max_payment_size_msat = 25000000000 # 0.25 BTC + client_trusts_lsp = true "#; fs::write(storage_path.join(config_file_name), toml_config).unwrap(); diff --git a/ldk-server/ldk-server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs index 92dcadaaf..c645242d9 100644 --- a/ldk-server/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -147,19 +147,24 @@ pub(crate) fn payment_kind_to_proto( secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), })), }, - PaymentKind::Bolt11Jit { hash, preimage, secret, lsp_fee_limits } => { - ldk_server_protos::types::PaymentKind { - kind: Some(Bolt11Jit(ldk_server_protos::types::Bolt11Jit { - hash: hash.to_string(), - preimage: preimage.map(|p| p.to_string()), - secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), - lsp_fee_limits: Some(LspFeeLimits { - max_total_opening_fee_msat: lsp_fee_limits.max_total_opening_fee_msat, - max_proportional_opening_fee_ppm_msat: lsp_fee_limits - .max_proportional_opening_fee_ppm_msat, - }), - })), - } + PaymentKind::Bolt11Jit { + hash, + preimage, + secret, + lsp_fee_limits, + counterparty_skimmed_fee_msat, + } => ldk_server_protos::types::PaymentKind { + kind: Some(Bolt11Jit(ldk_server_protos::types::Bolt11Jit { + hash: hash.to_string(), + preimage: preimage.map(|p| p.to_string()), + secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), + lsp_fee_limits: Some(LspFeeLimits { + max_total_opening_fee_msat: lsp_fee_limits.max_total_opening_fee_msat, + max_proportional_opening_fee_ppm_msat: lsp_fee_limits + .max_proportional_opening_fee_ppm_msat, + }), + counterparty_skimmed_fee_msat, + })), }, PaymentKind::Bolt12Offer { hash, preimage, secret, offer_id, payer_note, quantity } => { ldk_server_protos::types::PaymentKind { From cec76fc524d07593100375232cd9d3b72659d06e Mon Sep 17 00:00:00 2001 From: benthecarman Date: Mon, 1 Dec 2025 15:12:49 -0600 Subject: [PATCH 162/203] Update MSRV in CI to 1.85 In ldk-node's update, it bumped its MSRV to 1.85 so we need to do the same here. --- ldk-server/.github/workflows/build.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ldk-server/.github/workflows/build.yml b/ldk-server/.github/workflows/build.yml index 630435fbc..d406e0c74 100644 --- a/ldk-server/.github/workflows/build.yml +++ b/ldk-server/.github/workflows/build.yml @@ -9,16 +9,16 @@ jobs: platform: [ ubuntu-latest, macos-latest, - ] - toolchain: + ] + toolchain: [ stable, beta, - 1.75.0, # MSRV + 1.85.0, # MSRV, same as ldk-node ] include: - toolchain: stable check-fmt: true - - toolchain: 1.75.0 + - toolchain: 1.85.0 msrv: true runs-on: ${{ matrix.platform }} steps: @@ -33,8 +33,8 @@ jobs: run: rustup component add rustfmt && cargo fmt --all -- --check - name: Pin packages to allow for MSRV if: matrix.msrv - run: | - cargo update -p home --precise "0.5.9" --verbose # home v0.5.11 requires rustc 1.81 or newer + run: | # None needed yet + echo "No packages need pinning for MSRV ${{ matrix.toolchain }}" - name: Build on Rust ${{ matrix.toolchain }} run: cargo build --verbose --color always - name: Test on Rust ${{ matrix.toolchain }} From ad3eb56aede890c151cdfc17aa96e19a5be23192 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Wed, 3 Dec 2025 16:03:49 -0600 Subject: [PATCH 163/203] Add configurable log level and log file Before we were dropping all our logs on the floor besides a few printlns in the code. This implements a logger for the log facade that writes logs to the console as well as to the log file. We also add to the config options for setting the log file and log level. --- ldk-server/Cargo.lock | 2 + ldk-server/ldk-server/Cargo.toml | 2 + ldk-server/ldk-server/ldk-server-config.toml | 3 + ldk-server/ldk-server/src/main.rs | 91 +++++++--- ldk-server/ldk-server/src/util/config.rs | 41 +++++ ldk-server/ldk-server/src/util/logger.rs | 169 +++++++++++++++++++ ldk-server/ldk-server/src/util/mod.rs | 1 + 7 files changed, 281 insertions(+), 28 deletions(-) create mode 100644 ldk-server/ldk-server/src/util/logger.rs diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 60a3b4d3b..828cb3ca6 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -1715,6 +1715,7 @@ version = "0.1.0" dependencies = [ "async-trait", "bytes", + "chrono", "futures-util", "hex-conservative 0.2.1", "http-body-util", @@ -1723,6 +1724,7 @@ dependencies = [ "lapin", "ldk-node", "ldk-server-protos", + "log", "prost", "rand 0.8.5", "rusqlite", diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index c2c46ecc1..e1053f778 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -18,6 +18,8 @@ rusqlite = { version = "0.31.0", features = ["bundled"] } rand = { version = "0.8.5", default-features = false } async-trait = { version = "0.1.85", default-features = false } toml = { version = "0.8.9", default-features = false, features = ["parse"] } +chrono = { version = "0.4", default-features = false, features = ["clock"] } +log = "0.4.28" # Required for RabittMQ based EventPublisher. Only enabled for `events-rabbitmq` feature. lapin = { version = "2.4.0", features = ["rustls"], default-features = false, optional = true } diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml index 7727cff5f..45967f542 100644 --- a/ldk-server/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -8,6 +8,9 @@ rest_service_address = "127.0.0.1:3002" # LDK Server REST address [storage.disk] dir_path = "/tmp/ldk-server/" # Path for LDK and BDK data persistence +[log] +level = "Debug" # Log level (Error, Warn, Info, Debug, Trace) +file_path = "/tmp/ldk-server/ldk-server.log" # Log file path # Must set either bitcoind or esplora settings, but not both diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 0962a3c49..72f5fb129 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -25,6 +25,7 @@ use crate::io::persist::{ PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, }; use crate::util::config::{load_config, ChainSource}; +use crate::util::logger::ServerLogger; use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto}; use hex::DisplayHex; use ldk_node::config::Config; @@ -32,6 +33,7 @@ use ldk_node::lightning::ln::channelmanager::PaymentId; use ldk_server_protos::events; use ldk_server_protos::events::{event_envelope, EventEnvelope}; use ldk_server_protos::types::Payment; +use log::{error, info}; use prost::Message; use rand::Rng; use std::fs; @@ -70,6 +72,25 @@ fn main() { }, }; + let log_file_path = config_file.log_file_path.map(|p| PathBuf::from(p)).unwrap_or_else(|| { + let mut default_log_path = PathBuf::from(&config_file.storage_dir_path); + default_log_path.push("ldk-server.log"); + default_log_path + }); + + if log_file_path == PathBuf::from(&config_file.storage_dir_path) { + eprintln!("Log file path cannot be the same as storage directory path."); + std::process::exit(-1); + } + + let logger = match ServerLogger::init(config_file.log_level, &log_file_path) { + Ok(logger) => logger, + Err(e) => { + eprintln!("Failed to initialize logger: {e}"); + std::process::exit(-1); + }, + }; + ldk_node_config.storage_dir_path = config_file.storage_dir_path.clone(); ldk_node_config.listening_addresses = Some(vec![config_file.listening_addr]); ldk_node_config.network = config_file.network; @@ -79,7 +100,7 @@ fn main() { if let Some(alias) = config_file.alias { if let Err(e) = builder.set_node_alias(alias.to_string()) { - eprintln!("Failed to set node alias: {e}"); + error!("Failed to set node alias: {e}"); std::process::exit(-1); } } @@ -107,7 +128,7 @@ fn main() { let runtime = match tokio::runtime::Builder::new_multi_thread().enable_all().build() { Ok(runtime) => Arc::new(runtime), Err(e) => { - eprintln!("Failed to setup tokio runtime: {}", e); + error!("Failed to setup tokio runtime: {e}"); std::process::exit(-1); }, }; @@ -117,7 +138,7 @@ fn main() { let node = match builder.build() { Ok(node) => Arc::new(node), Err(e) => { - eprintln!("Failed to build LDK Node: {}", e); + error!("Failed to build LDK Node: {e}"); std::process::exit(-1); }, }; @@ -126,7 +147,7 @@ fn main() { Arc::new(match SqliteStore::new(PathBuf::from(config_file.storage_dir_path), None, None) { Ok(store) => store, Err(e) => { - eprintln!("Failed to create SqliteStore: {:?}", e); + error!("Failed to create SqliteStore: {e:?}"); std::process::exit(-1); }, }); @@ -142,26 +163,35 @@ fn main() { Arc::new(RabbitMqEventPublisher::new(rabbitmq_config)) }; - println!("Starting up..."); + info!("Starting up..."); match node.start() { Ok(()) => {}, Err(e) => { - eprintln!("Failed to start up LDK Node: {}", e); + error!("Failed to start up LDK Node: {e}"); std::process::exit(-1); }, } - println!( + info!( "CONNECTION_STRING: {}@{}", node.node_id(), node.config().listening_addresses.as_ref().unwrap().first().unwrap() ); runtime.block_on(async { + // Register SIGHUP handler for log rotation + let mut sighup_stream = match tokio::signal::unix::signal(SignalKind::hangup()) { + Ok(stream) => stream, + Err(e) => { + error!("Failed to register SIGHUP handler: {e}"); + std::process::exit(-1); + } + }; + let mut sigterm_stream = match tokio::signal::unix::signal(SignalKind::terminate()) { Ok(stream) => stream, Err(e) => { - println!("Failed to register for SIGTERM stream: {}", e); + error!("Failed to register for SIGTERM stream: {e}"); std::process::exit(-1); } }; @@ -174,25 +204,25 @@ fn main() { event = event_node.next_event_async() => { match event { Event::ChannelPending { channel_id, counterparty_node_id, .. } => { - println!( + info!( "CHANNEL_PENDING: {} from counterparty {}", channel_id, counterparty_node_id ); if let Err(e) = event_node.event_handled() { - eprintln!("Failed to mark event as handled: {e}"); + error!("Failed to mark event as handled: {e}"); } }, Event::ChannelReady { channel_id, counterparty_node_id, .. } => { - println!( + info!( "CHANNEL_READY: {} from counterparty {:?}", channel_id, counterparty_node_id ); if let Err(e) = event_node.event_handled() { - eprintln!("Failed to mark event as handled: {e}"); + error!("Failed to mark event as handled: {e}"); } }, Event::PaymentReceived { payment_id, payment_hash, amount_msat, .. } => { - println!( + info!( "PAYMENT_RECEIVED: with id {:?}, hash {}, amount_msat {}", payment_id, payment_hash, amount_msat ); @@ -233,7 +263,7 @@ fn main() { let payment = payment_to_proto(payment_details); upsert_payment_details(&event_node, Arc::clone(&paginated_store), &payment); } else { - eprintln!("Unable to find payment with paymentId: {}", payment_id.to_string()); + error!("Unable to find payment with paymentId: {}", payment_id.to_string()); } }, Event::PaymentForwarded { @@ -249,7 +279,7 @@ fn main() { outbound_amount_forwarded_msat } => { - println!("PAYMENT_FORWARDED: with outbound_amount_forwarded_msat {}, total_fee_earned_msat: {}, inbound channel: {}, outbound channel: {}", + info!("PAYMENT_FORWARDED: with outbound_amount_forwarded_msat {}, total_fee_earned_msat: {}, inbound channel: {}, outbound channel: {}", outbound_amount_forwarded_msat.unwrap_or(0), total_fee_earned_msat.unwrap_or(0), prev_channel_id, next_channel_id ); @@ -281,7 +311,7 @@ fn main() { }).await { Ok(_) => {}, Err(e) => { - println!("Failed to publish 'PaymentForwarded' event: {}", e); + error!("Failed to publish 'PaymentForwarded' event: {}", e); continue; } }; @@ -293,17 +323,17 @@ fn main() { ) { Ok(_) => { if let Err(e) = event_node.event_handled() { - eprintln!("Failed to mark event as handled: {e}"); + error!("Failed to mark event as handled: {e}"); } } Err(e) => { - println!("Failed to write forwarded payment to persistence: {}", e); + error!("Failed to write forwarded payment to persistence: {}", e); } } }, _ => { if let Err(e) = event_node.event_handled() { - eprintln!("Failed to mark event as handled: {e}"); + error!("Failed to mark event as handled: {e}"); } }, } @@ -315,19 +345,24 @@ fn main() { let node_service = NodeService::new(Arc::clone(&node), Arc::clone(&paginated_store)); runtime.spawn(async move { if let Err(err) = http1::Builder::new().serve_connection(io_stream, node_service).await { - eprintln!("Failed to serve connection: {}", err); + error!("Failed to serve connection: {}", err); } }); }, - Err(e) => eprintln!("Failed to accept connection: {}", e), + Err(e) => error!("Failed to accept connection: {}", e), } } _ = tokio::signal::ctrl_c() => { - println!("Received CTRL-C, shutting down.."); + info!("Received CTRL-C, shutting down.."); break; } + _ = sighup_stream.recv() => { + if let Err(e) = logger.reopen() { + error!("Failed to reopen log file on SIGHUP: {e}"); + } + } _ = sigterm_stream.recv() => { - println!("Received SIGTERM, shutting down.."); + info!("Received SIGTERM, shutting down.."); break; } } @@ -335,7 +370,7 @@ fn main() { }); node.stop().expect("Shutdown should always succeed."); - println!("Shutdown complete.."); + info!("Shutdown complete.."); } async fn publish_event_and_upsert_payment( @@ -351,14 +386,14 @@ async fn publish_event_and_upsert_payment( match event_publisher.publish(EventEnvelope { event: Some(event) }).await { Ok(_) => {}, Err(e) => { - println!("Failed to publish '{}' event, : {}", event_name, e); + error!("Failed to publish '{event_name}' event, : {e}"); return; }, }; upsert_payment_details(event_node, Arc::clone(&paginated_store), &payment); } else { - eprintln!("Unable to find payment with paymentId: {}", payment_id); + error!("Unable to find payment with paymentId: {payment_id}"); } } @@ -377,11 +412,11 @@ fn upsert_payment_details( ) { Ok(_) => { if let Err(e) = event_node.event_handled() { - eprintln!("Failed to mark event as handled: {e}"); + error!("Failed to mark event as handled: {e}"); } }, Err(e) => { - eprintln!("Failed to write payment to persistence: {}", e); + error!("Failed to write payment to persistence: {e}"); }, } } diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 11e5bdfd0..b2d896c0d 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -2,6 +2,7 @@ use ldk_node::bitcoin::Network; use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_node::lightning::routing::gossip::NodeAlias; use ldk_node::liquidity::LSPS2ServiceConfig; +use log::LevelFilter; use serde::{Deserialize, Serialize}; use std::net::SocketAddr; use std::path::Path; @@ -20,6 +21,8 @@ pub struct Config { pub rabbitmq_connection_string: String, pub rabbitmq_exchange_name: String, pub lsps2_service_config: Option, + pub log_level: LevelFilter, + pub log_file_path: Option, } #[derive(Debug)] @@ -86,6 +89,21 @@ impl TryFrom for Config { None }; + let log_level = toml_config + .log + .as_ref() + .and_then(|log_config| log_config.level.as_ref()) + .map(|level_str| { + LevelFilter::from_str(level_str).map_err(|e| { + io::Error::new( + io::ErrorKind::InvalidInput, + format!("Invalid log level configured: {}", e), + ) + }) + }) + .transpose()? + .unwrap_or(LevelFilter::Debug); + let (rabbitmq_connection_string, rabbitmq_exchange_name) = { let rabbitmq = toml_config.rabbitmq.unwrap_or(RabbitmqConfig { connection_string: String::new(), @@ -122,6 +140,8 @@ impl TryFrom for Config { rabbitmq_connection_string, rabbitmq_exchange_name, lsps2_service_config, + log_level, + log_file_path: toml_config.log.and_then(|l| l.file), }) } } @@ -135,6 +155,7 @@ pub struct TomlConfig { esplora: Option, rabbitmq: Option, liquidity: Option, + log: Option, } #[derive(Deserialize, Serialize)] @@ -167,6 +188,12 @@ struct EsploraConfig { server_url: String, } +#[derive(Deserialize, Serialize)] +struct LogConfig { + level: Option, + file: Option, +} + #[derive(Deserialize, Serialize)] struct RabbitmqConfig { connection_string: String, @@ -260,6 +287,10 @@ mod tests { [storage.disk] dir_path = "/tmp" + + [log] + level = "Trace" + file = "/var/log/ldk-server.log" [esplora] server_url = "https://mempool.space/api" @@ -310,6 +341,8 @@ mod tests { max_payment_size_msat: 25000000000, client_trusts_lsp: true, }), + log_level: LevelFilter::Trace, + log_file_path: Some("/var/log/ldk-server.log".to_string()), }; assert_eq!(config.listening_addr, expected.listening_addr); @@ -339,6 +372,10 @@ mod tests { [storage.disk] dir_path = "/tmp" + + [log] + level = "Trace" + file = "/var/log/ldk-server.log" [bitcoind] rpc_address = "127.0.0.1:8332" # RPC endpoint @@ -383,6 +420,10 @@ mod tests { [storage.disk] dir_path = "/tmp" + + [log] + level = "Trace" + file = "/var/log/ldk-server.log" [bitcoind] rpc_address = "127.0.0.1:8332" # RPC endpoint diff --git a/ldk-server/ldk-server/src/util/logger.rs b/ldk-server/ldk-server/src/util/logger.rs new file mode 100644 index 000000000..66a236ca3 --- /dev/null +++ b/ldk-server/ldk-server/src/util/logger.rs @@ -0,0 +1,169 @@ +use log::{Level, LevelFilter, Log, Metadata, Record}; +use std::fs::{self, File, OpenOptions}; +use std::io::{self, BufWriter, Write}; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; + +/// A logger implementation that writes logs to both stderr and a file. +/// +/// The logger formats log messages with RFC3339 timestamps and writes them to: +/// - stdout/stderr for console output +/// - A file specified during initialization +/// +/// All log messages follow the format: +/// `[TIMESTAMP LEVEL TARGET FILE:LINE] MESSAGE` +/// +/// Example: `[2025-12-04T10:30:45Z INFO ldk_server:42] Starting up...` +/// +/// The logger handles SIGHUP for log rotation by reopening the file handle when signaled. +pub struct ServerLogger { + /// The maximum log level to display + level: LevelFilter, + /// The file to write logs to, protected by a mutex for thread-safe access + file: Mutex>, + /// Path to the log file for reopening on SIGHUP + log_file_path: PathBuf, +} + +impl ServerLogger { + /// Initializes the global logger with the specified level and file path. + /// + /// Opens or creates the log file at the given path. If the file exists, logs are appended. + /// If the file doesn't exist, it will be created along with any necessary parent directories. + /// + /// This should be called once at application startup. Subsequent calls will fail. + /// + /// Returns an Arc to the logger for signal handling purposes. + pub fn init(level: LevelFilter, log_file_path: &Path) -> Result, io::Error> { + // Create parent directories if they don't exist + if let Some(parent) = log_file_path.parent() { + fs::create_dir_all(parent)?; + } + + let file = open_log_file(log_file_path)?; + + let logger = Arc::new(ServerLogger { + level, + file: Mutex::new(file), + log_file_path: log_file_path.to_path_buf(), + }); + + log::set_boxed_logger(Box::new(LoggerWrapper(Arc::clone(&logger)))) + .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + log::set_max_level(level); + Ok(logger) + } + + /// Reopens the log file. Called on SIGHUP for log rotation. + pub fn reopen(&self) -> Result<(), io::Error> { + let new_file = open_log_file(&self.log_file_path)?; + match self.file.lock() { + Ok(mut file) => { + // Flush the old buffer before replacing with the new file + file.flush()?; + *file = new_file; + Ok(()) + }, + Err(e) => { + Err(io::Error::new(io::ErrorKind::Other, format!("Failed to acquire lock: {}", e))) + }, + } + } +} + +impl Log for ServerLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= self.level + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + let level_str = format_level(record.level()); + let line = record.line().unwrap_or(0); + + // Log to console + let _ = match record.level() { + Level::Error => { + write!( + io::stderr(), + "[{} {} {}:{}] {}\n", + format_timestamp(), + level_str, + record.target(), + line, + record.args() + ) + }, + _ => { + write!( + io::stdout(), + "[{} {} {}:{}] {}\n", + format_timestamp(), + level_str, + record.target(), + line, + record.args() + ) + }, + }; + + // Log to file + if let Ok(mut file) = self.file.lock() { + let _ = write!( + file, + "[{} {} {}:{}] {}\n", + format_timestamp(), + level_str, + record.target(), + line, + record.args() + ); + } + } + } + + fn flush(&self) { + let _ = io::stdout().flush(); + let _ = io::stderr().flush(); + if let Ok(mut file) = self.file.lock() { + let _ = file.flush(); + } + } +} + +fn format_timestamp() -> String { + let now = chrono::Utc::now(); + now.to_rfc3339_opts(chrono::SecondsFormat::Millis, true) +} + +fn format_level(level: Level) -> &'static str { + match level { + Level::Error => "ERROR", + Level::Warn => "WARN ", + Level::Info => "INFO ", + Level::Debug => "DEBUG", + Level::Trace => "TRACE", + } +} + +fn open_log_file(log_file_path: &Path) -> Result, io::Error> { + let file = OpenOptions::new().create(true).append(true).open(log_file_path)?; + Ok(BufWriter::new(file)) +} + +/// Wrapper to allow Arc to implement Log trait +struct LoggerWrapper(Arc); + +impl Log for LoggerWrapper { + fn enabled(&self, metadata: &Metadata) -> bool { + self.0.enabled(metadata) + } + + fn log(&self, record: &Record) { + self.0.log(record) + } + + fn flush(&self) { + self.0.flush() + } +} diff --git a/ldk-server/ldk-server/src/util/mod.rs b/ldk-server/ldk-server/src/util/mod.rs index 02789f03c..2bcbee65e 100644 --- a/ldk-server/ldk-server/src/util/mod.rs +++ b/ldk-server/ldk-server/src/util/mod.rs @@ -1,2 +1,3 @@ pub(crate) mod config; +pub(crate) mod logger; pub(crate) mod proto_adapter; From 64079537acacb9b2069270c60845329adda301a0 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 9 Dec 2025 17:32:31 -0600 Subject: [PATCH 164/203] Limit request body size to 10MB Limit the request body to prevent abuse and too much memory allocation --- ldk-server/ldk-server/src/service.rs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index 6eb02c527..50b7cb399 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -1,6 +1,6 @@ use ldk_node::Node; -use http_body_util::{BodyExt, Full}; +use http_body_util::{BodyExt, Full, Limited}; use hyper::body::{Bytes, Incoming}; use hyper::service::Service; use hyper::{Request, Response, StatusCode}; @@ -39,6 +39,10 @@ use std::future::Future; use std::pin::Pin; use std::sync::Arc; +// Maximum request body size: 10 MB +// This prevents memory exhaustion from large requests +const MAX_BODY_SIZE: usize = 10 * 1024 * 1024; + #[derive(Clone)] pub struct NodeService { node: Arc, @@ -127,8 +131,23 @@ async fn handle_request< >( context: Context, request: Request, handler: F, ) -> Result<>>::Response, hyper::Error> { - // TODO: we should bound the amount of data we read to avoid allocating too much memory. - let bytes = request.into_body().collect().await?.to_bytes(); + // Limit the size of the request body to prevent abuse + let limited_body = Limited::new(request.into_body(), MAX_BODY_SIZE); + let bytes = match limited_body.collect().await { + Ok(collected) => collected.to_bytes(), + Err(_) => { + let (error_response, status_code) = to_error_response(LdkServerError::new( + InvalidRequestError, + "Request body too large or failed to read.", + )); + return Ok(Response::builder() + .status(status_code) + .body(Full::new(Bytes::from(error_response.encode_to_vec()))) + // unwrap safety: body only errors when previous chained calls failed. + .unwrap()); + }, + }; + match T::decode(bytes) { Ok(request) => match handler(context, request) { Ok(response) => Ok(Response::builder() From e88fe095b6de93f2e9e3cd8faa75803236ca2cbf Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 9 Dec 2025 18:16:40 -0600 Subject: [PATCH 165/203] Hook up ChannelConfig in open channel endpoint --- ldk-server/ldk-server/src/api/mod.rs | 49 +++++++++++++++++++ ldk-server/ldk-server/src/api/open_channel.rs | 12 +++-- .../src/api/update_channel_config.rs | 49 +------------------ 3 files changed, 60 insertions(+), 50 deletions(-) diff --git a/ldk-server/ldk-server/src/api/mod.rs b/ldk-server/ldk-server/src/api/mod.rs index c1b0fa2ec..834c7e49f 100644 --- a/ldk-server/ldk-server/src/api/mod.rs +++ b/ldk-server/ldk-server/src/api/mod.rs @@ -1,3 +1,8 @@ +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; +use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; +use ldk_server_protos::types::channel_config::MaxDustHtlcExposure; + pub(crate) mod bolt11_receive; pub(crate) mod bolt11_send; pub(crate) mod bolt12_receive; @@ -14,3 +19,47 @@ pub(crate) mod onchain_receive; pub(crate) mod onchain_send; pub(crate) mod open_channel; pub(crate) mod update_channel_config; + +pub(crate) fn build_channel_config_from_proto( + default_config: ChannelConfig, proto_channel_config: ldk_server_protos::types::ChannelConfig, +) -> Result { + let max_dust_htlc_exposure = proto_channel_config + .max_dust_htlc_exposure + .map(|max_dust_htlc_exposure| match max_dust_htlc_exposure { + MaxDustHtlcExposure::FixedLimitMsat(limit_msat) => { + MaxDustHTLCExposure::FixedLimit { limit_msat } + }, + MaxDustHtlcExposure::FeeRateMultiplier(multiplier) => { + MaxDustHTLCExposure::FeeRateMultiplier { multiplier } + }, + }) + .unwrap_or(default_config.max_dust_htlc_exposure); + + let cltv_expiry_delta = match proto_channel_config.cltv_expiry_delta { + Some(c) => Some(u16::try_from(c).map_err(|_| { + LdkServerError::new( + InvalidRequestError, + format!("Invalid cltv_expiry_delta, must be between 0 and {}", u16::MAX), + ) + })?), + None => None, + } + .unwrap_or(default_config.cltv_expiry_delta); + + Ok(ChannelConfig { + forwarding_fee_proportional_millionths: proto_channel_config + .forwarding_fee_proportional_millionths + .unwrap_or(default_config.forwarding_fee_proportional_millionths), + forwarding_fee_base_msat: proto_channel_config + .forwarding_fee_base_msat + .unwrap_or(default_config.forwarding_fee_base_msat), + cltv_expiry_delta, + max_dust_htlc_exposure, + force_close_avoidance_max_fee_satoshis: proto_channel_config + .force_close_avoidance_max_fee_satoshis + .unwrap_or(default_config.force_close_avoidance_max_fee_satoshis), + accept_underpaying_htlcs: proto_channel_config + .accept_underpaying_htlcs + .unwrap_or(default_config.accept_underpaying_htlcs), + }) +} diff --git a/ldk-server/ldk-server/src/api/open_channel.rs b/ldk-server/ldk-server/src/api/open_channel.rs index 96fdbf2fc..c26dab0f0 100644 --- a/ldk-server/ldk-server/src/api/open_channel.rs +++ b/ldk-server/ldk-server/src/api/open_channel.rs @@ -1,6 +1,8 @@ +use crate::api::build_channel_config_from_proto; use crate::api::error::LdkServerError; use crate::service::Context; use ldk_node::bitcoin::secp256k1::PublicKey; +use ldk_node::config::ChannelConfig; use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_server_protos::api::{OpenChannelRequest, OpenChannelResponse}; use std::str::FromStr; @@ -15,14 +17,18 @@ pub(crate) fn handle_open_channel( let address = SocketAddress::from_str(&request.address) .map_err(|_| ldk_node::NodeError::InvalidSocketAddress)?; + let channel_config = request + .channel_config + .map(|proto_config| build_channel_config_from_proto(ChannelConfig::default(), proto_config)) + .transpose()?; + let user_channel_id = if request.announce_channel { context.node.open_announced_channel( node_id, address, request.channel_amount_sats, request.push_to_counterparty_msat, - // TODO: Allow setting ChannelConfig in open-channel. - None, + channel_config, )? } else { context.node.open_channel( @@ -30,7 +36,7 @@ pub(crate) fn handle_open_channel( address, request.channel_amount_sats, request.push_to_counterparty_msat, - None, + channel_config, )? }; diff --git a/ldk-server/ldk-server/src/api/update_channel_config.rs b/ldk-server/ldk-server/src/api/update_channel_config.rs index 2a01a54b1..e5905c22c 100644 --- a/ldk-server/ldk-server/src/api/update_channel_config.rs +++ b/ldk-server/ldk-server/src/api/update_channel_config.rs @@ -1,11 +1,10 @@ +use crate::api::build_channel_config_from_proto; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::{InvalidRequestError, LightningError}; use crate::service::Context; use ldk_node::bitcoin::secp256k1::PublicKey; -use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; use ldk_node::UserChannelId; use ldk_server_protos::api::{UpdateChannelConfigRequest, UpdateChannelConfigResponse}; -use ldk_server_protos::types::channel_config::MaxDustHtlcExposure; use std::str::FromStr; pub(crate) const UPDATE_CHANNEL_CONFIG_PATH: &str = "UpdateChannelConfig"; @@ -29,7 +28,7 @@ pub(crate) fn handle_update_channel_config_request( })? .config; - let updated_channel_config = build_updated_channel_config( + let updated_channel_config = build_channel_config_from_proto( current_config, request.channel_config.ok_or_else(|| { LdkServerError::new(InvalidRequestError, "Channel config must be provided.") @@ -56,47 +55,3 @@ pub(crate) fn handle_update_channel_config_request( Ok(UpdateChannelConfigResponse {}) } - -fn build_updated_channel_config( - current_config: ChannelConfig, proto_channel_config: ldk_server_protos::types::ChannelConfig, -) -> Result { - let max_dust_htlc_exposure = proto_channel_config - .max_dust_htlc_exposure - .map(|max_dust_htlc_exposure| match max_dust_htlc_exposure { - MaxDustHtlcExposure::FixedLimitMsat(limit_msat) => { - MaxDustHTLCExposure::FixedLimit { limit_msat } - }, - MaxDustHtlcExposure::FeeRateMultiplier(multiplier) => { - MaxDustHTLCExposure::FeeRateMultiplier { multiplier } - }, - }) - .unwrap_or(current_config.max_dust_htlc_exposure); - - let cltv_expiry_delta = match proto_channel_config.cltv_expiry_delta { - Some(c) => Some(u16::try_from(c).map_err(|_| { - LdkServerError::new( - InvalidRequestError, - format!("Invalid cltv_expiry_delta, must be between 0 and {}", u16::MAX), - ) - })?), - None => None, - } - .unwrap_or_else(|| current_config.cltv_expiry_delta); - - Ok(ChannelConfig { - forwarding_fee_proportional_millionths: proto_channel_config - .forwarding_fee_proportional_millionths - .unwrap_or(current_config.forwarding_fee_proportional_millionths), - forwarding_fee_base_msat: proto_channel_config - .forwarding_fee_base_msat - .unwrap_or(current_config.forwarding_fee_base_msat), - cltv_expiry_delta, - max_dust_htlc_exposure, - force_close_avoidance_max_fee_satoshis: proto_channel_config - .force_close_avoidance_max_fee_satoshis - .unwrap_or(current_config.force_close_avoidance_max_fee_satoshis), - accept_underpaying_htlcs: proto_channel_config - .accept_underpaying_htlcs - .unwrap_or(current_config.accept_underpaying_htlcs), - }) -} From a06b4ebb05417f4495759e8461af309d47552739 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 9 Dec 2025 19:22:55 -0600 Subject: [PATCH 166/203] Move endpoint path constants to shared defintion We had these defined in 2 separate areas which defeats the point of having them defined in constants. This moves them into the ldk-server-protos crate so they are shared among both the cli and server. Luckily there weren't any discrepancies. --- ldk-server/ldk-server-client/src/client.rs | 20 +++---- ldk-server/ldk-server-protos/src/endpoints.rs | 16 ++++++ ldk-server/ldk-server-protos/src/lib.rs | 1 + .../ldk-server/src/api/bolt11_receive.rs | 2 - ldk-server/ldk-server/src/api/bolt11_send.rs | 2 - .../ldk-server/src/api/bolt12_receive.rs | 2 - ldk-server/ldk-server/src/api/bolt12_send.rs | 2 - .../ldk-server/src/api/close_channel.rs | 4 -- ldk-server/ldk-server/src/api/get_balances.rs | 2 - .../ldk-server/src/api/get_node_info.rs | 2 - .../ldk-server/src/api/get_payment_details.rs | 2 - .../ldk-server/src/api/list_channels.rs | 2 - .../src/api/list_forwarded_payments.rs | 2 - .../ldk-server/src/api/list_payments.rs | 2 - .../ldk-server/src/api/onchain_receive.rs | 1 - ldk-server/ldk-server/src/api/onchain_send.rs | 2 - ldk-server/ldk-server/src/api/open_channel.rs | 2 - .../src/api/update_channel_config.rs | 2 - ldk-server/ldk-server/src/service.rs | 54 ++++++++++--------- 19 files changed, 51 insertions(+), 71 deletions(-) create mode 100644 ldk-server/ldk-server-protos/src/endpoints.rs diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index 02d9e56f8..0b081a27f 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -13,26 +13,18 @@ use ldk_server_protos::api::{ OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, OpenChannelResponse, }; +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, + LIST_CHANNELS_PATH, LIST_PAYMENTS_PATH, ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, + OPEN_CHANNEL_PATH, +}; use ldk_server_protos::error::{ErrorCode, ErrorResponse}; use reqwest::header::CONTENT_TYPE; use reqwest::Client; const APPLICATION_OCTET_STREAM: &str = "application/octet-stream"; -const GET_NODE_INFO_PATH: &str = "GetNodeInfo"; -const GET_BALANCES_PATH: &str = "GetBalances"; -const ONCHAIN_RECEIVE_PATH: &str = "OnchainReceive"; -const ONCHAIN_SEND_PATH: &str = "OnchainSend"; -const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; -const BOLT11_SEND_PATH: &str = "Bolt11Send"; -const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive"; -const BOLT12_SEND_PATH: &str = "Bolt12Send"; -const OPEN_CHANNEL_PATH: &str = "OpenChannel"; -const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; -const FORCE_CLOSE_CHANNEL_PATH: &str = "ForceCloseChannel"; -const LIST_CHANNELS_PATH: &str = "ListChannels"; -const LIST_PAYMENTS_PATH: &str = "ListPayments"; - /// Client to access a hosted instance of LDK Server. #[derive(Clone)] pub struct LdkServerClient { diff --git a/ldk-server/ldk-server-protos/src/endpoints.rs b/ldk-server/ldk-server-protos/src/endpoints.rs new file mode 100644 index 000000000..ef0c46563 --- /dev/null +++ b/ldk-server/ldk-server-protos/src/endpoints.rs @@ -0,0 +1,16 @@ +pub const GET_NODE_INFO_PATH: &str = "GetNodeInfo"; +pub const GET_BALANCES_PATH: &str = "GetBalances"; +pub const ONCHAIN_RECEIVE_PATH: &str = "OnchainReceive"; +pub const ONCHAIN_SEND_PATH: &str = "OnchainSend"; +pub const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; +pub const BOLT11_SEND_PATH: &str = "Bolt11Send"; +pub const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive"; +pub const BOLT12_SEND_PATH: &str = "Bolt12Send"; +pub const OPEN_CHANNEL_PATH: &str = "OpenChannel"; +pub const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; +pub const FORCE_CLOSE_CHANNEL_PATH: &str = "ForceCloseChannel"; +pub const LIST_CHANNELS_PATH: &str = "ListChannels"; +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"; diff --git a/ldk-server/ldk-server-protos/src/lib.rs b/ldk-server/ldk-server-protos/src/lib.rs index e69faeaf7..1999d0609 100644 --- a/ldk-server/ldk-server-protos/src/lib.rs +++ b/ldk-server/ldk-server-protos/src/lib.rs @@ -1,4 +1,5 @@ pub mod api; +pub mod endpoints; pub mod error; pub mod events; pub mod types; diff --git a/ldk-server/ldk-server/src/api/bolt11_receive.rs b/ldk-server/ldk-server/src/api/bolt11_receive.rs index c81b94c4e..024404b87 100644 --- a/ldk-server/ldk-server/src/api/bolt11_receive.rs +++ b/ldk-server/ldk-server/src/api/bolt11_receive.rs @@ -3,8 +3,6 @@ use crate::service::Context; use crate::util::proto_adapter::proto_to_bolt11_description; use ldk_server_protos::api::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; -pub(crate) const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; - pub(crate) fn handle_bolt11_receive_request( context: Context, request: Bolt11ReceiveRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/bolt11_send.rs b/ldk-server/ldk-server/src/api/bolt11_send.rs index 6a1314345..4b273218a 100644 --- a/ldk-server/ldk-server/src/api/bolt11_send.rs +++ b/ldk-server/ldk-server/src/api/bolt11_send.rs @@ -4,8 +4,6 @@ use ldk_node::lightning_invoice::Bolt11Invoice; use ldk_server_protos::api::{Bolt11SendRequest, Bolt11SendResponse}; use std::str::FromStr; -pub(crate) const BOLT11_SEND_PATH: &str = "Bolt11Send"; - pub(crate) fn handle_bolt11_send_request( context: Context, request: Bolt11SendRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/bolt12_receive.rs b/ldk-server/ldk-server/src/api/bolt12_receive.rs index cb1ee502d..9749baff4 100644 --- a/ldk-server/ldk-server/src/api/bolt12_receive.rs +++ b/ldk-server/ldk-server/src/api/bolt12_receive.rs @@ -2,8 +2,6 @@ use crate::api::error::LdkServerError; use crate::service::Context; use ldk_server_protos::api::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; -pub(crate) const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive"; - pub(crate) fn handle_bolt12_receive_request( context: Context, request: Bolt12ReceiveRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/bolt12_send.rs b/ldk-server/ldk-server/src/api/bolt12_send.rs index bbf392a75..ddaf9f893 100644 --- a/ldk-server/ldk-server/src/api/bolt12_send.rs +++ b/ldk-server/ldk-server/src/api/bolt12_send.rs @@ -4,8 +4,6 @@ use ldk_node::lightning::offers::offer::Offer; use ldk_server_protos::api::{Bolt12SendRequest, Bolt12SendResponse}; use std::str::FromStr; -pub(crate) const BOLT12_SEND_PATH: &str = "Bolt12Send"; - pub(crate) fn handle_bolt12_send_request( context: Context, request: Bolt12SendRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/close_channel.rs b/ldk-server/ldk-server/src/api/close_channel.rs index 1d9d0b0ad..268cb6de7 100644 --- a/ldk-server/ldk-server/src/api/close_channel.rs +++ b/ldk-server/ldk-server/src/api/close_channel.rs @@ -8,8 +8,6 @@ use ldk_server_protos::api::{ }; use std::str::FromStr; -pub(crate) const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; - pub(crate) fn handle_close_channel_request( context: Context, request: CloseChannelRequest, ) -> Result { @@ -21,8 +19,6 @@ pub(crate) fn handle_close_channel_request( Ok(CloseChannelResponse {}) } -pub(crate) const FORCE_CLOSE_CHANNEL_PATH: &str = "ForceCloseChannel"; - pub(crate) fn handle_force_close_channel_request( context: Context, request: ForceCloseChannelRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/get_balances.rs b/ldk-server/ldk-server/src/api/get_balances.rs index 5516fed9e..dce81ef14 100644 --- a/ldk-server/ldk-server/src/api/get_balances.rs +++ b/ldk-server/ldk-server/src/api/get_balances.rs @@ -3,8 +3,6 @@ use crate::service::Context; use crate::util::proto_adapter::{lightning_balance_to_proto, pending_sweep_balance_to_proto}; use ldk_server_protos::api::{GetBalancesRequest, GetBalancesResponse}; -pub(crate) const GET_BALANCES: &str = "GetBalances"; - pub(crate) fn handle_get_balances_request( context: Context, _request: GetBalancesRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/get_node_info.rs b/ldk-server/ldk-server/src/api/get_node_info.rs index 52dff388b..5763bea9d 100644 --- a/ldk-server/ldk-server/src/api/get_node_info.rs +++ b/ldk-server/ldk-server/src/api/get_node_info.rs @@ -3,8 +3,6 @@ use crate::service::Context; use ldk_server_protos::api::{GetNodeInfoRequest, GetNodeInfoResponse}; use ldk_server_protos::types::BestBlock; -pub(crate) const GET_NODE_INFO: &str = "GetNodeInfo"; - pub(crate) fn handle_get_node_info_request( context: Context, _request: GetNodeInfoRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/get_payment_details.rs b/ldk-server/ldk-server/src/api/get_payment_details.rs index 033f5f8cf..d0b6fc22d 100644 --- a/ldk-server/ldk-server/src/api/get_payment_details.rs +++ b/ldk-server/ldk-server/src/api/get_payment_details.rs @@ -6,8 +6,6 @@ use hex::FromHex; use ldk_node::lightning::ln::channelmanager::PaymentId; use ldk_server_protos::api::{GetPaymentDetailsRequest, GetPaymentDetailsResponse}; -pub(crate) const GET_PAYMENT_DETAILS_PATH: &str = "GetPaymentDetails"; - pub(crate) fn handle_get_payment_details_request( context: Context, request: GetPaymentDetailsRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/list_channels.rs b/ldk-server/ldk-server/src/api/list_channels.rs index 712eee770..046fad645 100644 --- a/ldk-server/ldk-server/src/api/list_channels.rs +++ b/ldk-server/ldk-server/src/api/list_channels.rs @@ -3,8 +3,6 @@ use crate::service::Context; use crate::util::proto_adapter::channel_to_proto; use ldk_server_protos::api::{ListChannelsRequest, ListChannelsResponse}; -pub(crate) const LIST_CHANNELS_PATH: &str = "ListChannels"; - pub(crate) fn handle_list_channels_request( context: Context, _request: ListChannelsRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/list_forwarded_payments.rs b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs index c6762e0f4..b11996194 100644 --- a/ldk-server/ldk-server/src/api/list_forwarded_payments.rs +++ b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs @@ -10,8 +10,6 @@ use ldk_server_protos::api::{ListForwardedPaymentsRequest, ListForwardedPayments use ldk_server_protos::types::{ForwardedPayment, PageToken}; use prost::Message; -pub(crate) const LIST_FORWARDED_PAYMENTS_PATH: &str = "ListForwardedPayments"; - pub(crate) fn handle_list_forwarded_payments_request( context: Context, request: ListForwardedPaymentsRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/list_payments.rs b/ldk-server/ldk-server/src/api/list_payments.rs index 0e9d53525..2b6f8ff1f 100644 --- a/ldk-server/ldk-server/src/api/list_payments.rs +++ b/ldk-server/ldk-server/src/api/list_payments.rs @@ -9,8 +9,6 @@ use ldk_server_protos::api::{ListPaymentsRequest, ListPaymentsResponse}; use ldk_server_protos::types::{PageToken, Payment}; use prost::Message; -pub(crate) const LIST_PAYMENTS_PATH: &str = "ListPayments"; - pub(crate) fn handle_list_payments_request( context: Context, request: ListPaymentsRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/onchain_receive.rs b/ldk-server/ldk-server/src/api/onchain_receive.rs index 2c8a9d45a..3196801f7 100644 --- a/ldk-server/ldk-server/src/api/onchain_receive.rs +++ b/ldk-server/ldk-server/src/api/onchain_receive.rs @@ -2,7 +2,6 @@ use crate::api::error::LdkServerError; use crate::service::Context; use ldk_server_protos::api::{OnchainReceiveRequest, OnchainReceiveResponse}; -pub(crate) const ONCHAIN_RECEIVE_PATH: &str = "OnchainReceive"; pub(crate) fn handle_onchain_receive_request( context: Context, _request: OnchainReceiveRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/onchain_send.rs b/ldk-server/ldk-server/src/api/onchain_send.rs index be9b2e0de..d169cb1ac 100644 --- a/ldk-server/ldk-server/src/api/onchain_send.rs +++ b/ldk-server/ldk-server/src/api/onchain_send.rs @@ -5,8 +5,6 @@ use ldk_node::bitcoin::{Address, FeeRate}; use ldk_server_protos::api::{OnchainSendRequest, OnchainSendResponse}; use std::str::FromStr; -pub(crate) const ONCHAIN_SEND_PATH: &str = "OnchainSend"; - pub(crate) fn handle_onchain_send_request( context: Context, request: OnchainSendRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/open_channel.rs b/ldk-server/ldk-server/src/api/open_channel.rs index 96fdbf2fc..a6eb9c27e 100644 --- a/ldk-server/ldk-server/src/api/open_channel.rs +++ b/ldk-server/ldk-server/src/api/open_channel.rs @@ -5,8 +5,6 @@ use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_server_protos::api::{OpenChannelRequest, OpenChannelResponse}; use std::str::FromStr; -pub(crate) const OPEN_CHANNEL_PATH: &str = "OpenChannel"; - pub(crate) fn handle_open_channel( context: Context, request: OpenChannelRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/update_channel_config.rs b/ldk-server/ldk-server/src/api/update_channel_config.rs index 2a01a54b1..dbdd1c6d6 100644 --- a/ldk-server/ldk-server/src/api/update_channel_config.rs +++ b/ldk-server/ldk-server/src/api/update_channel_config.rs @@ -8,8 +8,6 @@ use ldk_server_protos::api::{UpdateChannelConfigRequest, UpdateChannelConfigResp use ldk_server_protos::types::channel_config::MaxDustHtlcExposure; use std::str::FromStr; -pub(crate) const UPDATE_CHANNEL_CONFIG_PATH: &str = "UpdateChannelConfig"; - pub(crate) fn handle_update_channel_config_request( context: Context, request: UpdateChannelConfigRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index 6eb02c527..5ae227fa2 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -5,34 +5,32 @@ use hyper::body::{Bytes, Incoming}; use hyper::service::Service; use hyper::{Request, Response, StatusCode}; +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, UPDATE_CHANNEL_CONFIG_PATH, +}; + use prost::Message; -use crate::api::bolt11_receive::{handle_bolt11_receive_request, BOLT11_RECEIVE_PATH}; -use crate::api::bolt11_send::{handle_bolt11_send_request, BOLT11_SEND_PATH}; -use crate::api::bolt12_receive::{handle_bolt12_receive_request, BOLT12_RECEIVE_PATH}; -use crate::api::bolt12_send::{handle_bolt12_send_request, BOLT12_SEND_PATH}; -use crate::api::close_channel::{ - handle_close_channel_request, handle_force_close_channel_request, CLOSE_CHANNEL_PATH, - FORCE_CLOSE_CHANNEL_PATH, -}; +use crate::api::bolt11_receive::handle_bolt11_receive_request; +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::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::api::get_balances::{handle_get_balances_request, GET_BALANCES}; -use crate::api::get_node_info::{handle_get_node_info_request, GET_NODE_INFO}; -use crate::api::get_payment_details::{ - handle_get_payment_details_request, GET_PAYMENT_DETAILS_PATH, -}; -use crate::api::list_channels::{handle_list_channels_request, LIST_CHANNELS_PATH}; -use crate::api::list_forwarded_payments::{ - handle_list_forwarded_payments_request, LIST_FORWARDED_PAYMENTS_PATH, -}; -use crate::api::list_payments::{handle_list_payments_request, LIST_PAYMENTS_PATH}; -use crate::api::onchain_receive::{handle_onchain_receive_request, ONCHAIN_RECEIVE_PATH}; -use crate::api::onchain_send::{handle_onchain_send_request, ONCHAIN_SEND_PATH}; -use crate::api::open_channel::{handle_open_channel, OPEN_CHANNEL_PATH}; -use crate::api::update_channel_config::{ - handle_update_channel_config_request, UPDATE_CHANNEL_CONFIG_PATH, -}; +use crate::api::get_balances::handle_get_balances_request; +use crate::api::get_node_info::handle_get_node_info_request; +use crate::api::get_payment_details::handle_get_payment_details_request; +use crate::api::list_channels::handle_list_channels_request; +use crate::api::list_forwarded_payments::handle_list_forwarded_payments_request; +use crate::api::list_payments::handle_list_payments_request; +use crate::api::onchain_receive::handle_onchain_receive_request; +use crate::api::onchain_send::handle_onchain_send_request; +use crate::api::open_channel::handle_open_channel; +use crate::api::update_channel_config::handle_update_channel_config_request; use crate::io::persist::paginated_kv_store::PaginatedKVStore; use crate::util::proto_adapter::to_error_response; use std::future::Future; @@ -68,8 +66,12 @@ impl Service> for NodeService { }; // Exclude '/' from path pattern matching. match &req.uri().path()[1..] { - GET_NODE_INFO => Box::pin(handle_request(context, req, handle_get_node_info_request)), - GET_BALANCES => Box::pin(handle_request(context, req, handle_get_balances_request)), + GET_NODE_INFO_PATH => { + Box::pin(handle_request(context, req, handle_get_node_info_request)) + }, + GET_BALANCES_PATH => { + Box::pin(handle_request(context, req, handle_get_balances_request)) + }, ONCHAIN_RECEIVE_PATH => { Box::pin(handle_request(context, req, handle_onchain_receive_request)) }, From 1d1cd59c397a5e950d0d6ab6fd1b4ab7a89945db Mon Sep 17 00:00:00 2001 From: Anyitechs Date: Tue, 9 Dec 2025 13:10:57 +0100 Subject: [PATCH 167/203] add `RouteParametersConfig` struct to proto types --- .../ldk-server-protos/src/proto/types.proto | 21 +++++++++++++++++ ldk-server/ldk-server-protos/src/types.rs | 23 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/ldk-server/ldk-server-protos/src/proto/types.proto b/ldk-server/ldk-server-protos/src/proto/types.proto index 5f4144126..730616921 100644 --- a/ldk-server/ldk-server-protos/src/proto/types.proto +++ b/ldk-server/ldk-server-protos/src/proto/types.proto @@ -683,3 +683,24 @@ message Bolt11InvoiceDescription { string hash = 2; } } + +// Configuration options for payment routing and pathfinding. +// See https://docs.rs/lightning/0.2.0/lightning/routing/router/struct.RouteParametersConfig.html for more details on each field. +message RouteParametersConfig { + // The maximum total fees, in millisatoshi, that may accrue during route finding. + // Defaults to 1% of the payment amount + 50 sats + optional uint64 max_total_routing_fee_msat = 1; + + // The maximum total CLTV delta we accept for the route. + // Defaults to 1008. + uint32 max_total_cltv_expiry_delta = 2; + + // The maximum number of paths that may be used by (MPP) payments. + // Defaults to 10. + uint32 max_path_count = 3; + + // Selects the maximum share of a channel's total capacity which will be + // sent over a channel, as a power of 1/2. + // Default value: 2 + uint32 max_channel_saturation_power_of_half = 4; +} diff --git a/ldk-server/ldk-server-protos/src/types.rs b/ldk-server/ldk-server-protos/src/types.rs index 2e5dc8c2f..3251bc452 100644 --- a/ldk-server/ldk-server-protos/src/types.rs +++ b/ldk-server/ldk-server-protos/src/types.rs @@ -779,6 +779,29 @@ pub mod bolt11_invoice_description { Hash(::prost::alloc::string::String), } } +/// Configuration options for payment routing and pathfinding. +/// See for more details on each field. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RouteParametersConfig { + /// The maximum total fees, in millisatoshi, that may accrue during route finding. + /// Defaults to 1% of the payment amount + 50 sats + #[prost(uint64, optional, tag = "1")] + pub max_total_routing_fee_msat: ::core::option::Option, + /// The maximum total CLTV delta we accept for the route. + /// Defaults to 1008. + #[prost(uint32, tag = "2")] + pub max_total_cltv_expiry_delta: u32, + /// The maximum number of paths that may be used by (MPP) payments. + /// Defaults to 10. + #[prost(uint32, tag = "3")] + pub max_path_count: u32, + /// Selects the maximum share of a channel's total capacity which will be + /// sent over a channel, as a power of 1/2. + /// Default value: 2 + #[prost(uint32, tag = "4")] + pub max_channel_saturation_power_of_half: u32, +} /// Represents the direction of a payment. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] From c118e6878c79cb0b657b3467c07ea7849c00be7e Mon Sep 17 00:00:00 2001 From: Anyitechs Date: Tue, 9 Dec 2025 13:24:59 +0100 Subject: [PATCH 168/203] allow `route_parameters` in BOLT11 & BOLT12 send API --- ldk-server/ldk-server-cli/src/main.rs | 77 ++++++++++++++++++- ldk-server/ldk-server-protos/src/api.rs | 6 ++ .../ldk-server-protos/src/proto/api.proto | 6 ++ ldk-server/ldk-server/src/api/bolt11_send.rs | 34 +++++++- ldk-server/ldk-server/src/api/bolt12_send.rs | 41 +++++++++- 5 files changed, 154 insertions(+), 10 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index a45ec6ea9..b9486817c 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -10,11 +10,19 @@ use ldk_server_client::ldk_server_protos::api::{ ListChannelsRequest, ListPaymentsRequest, OnchainReceiveRequest, OnchainSendRequest, OpenChannelRequest, }; +use ldk_server_client::ldk_server_protos::types::RouteParametersConfig; use ldk_server_client::ldk_server_protos::types::{ bolt11_invoice_description, Bolt11InvoiceDescription, PageToken, Payment, }; use std::fmt::Debug; +// Having these default values as constants in the Proto file and +// importing/reusing them here might be better, but Proto3 removed +// the ability to set default values. +const DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA: u32 = 1008; +const DEFAULT_MAX_PATH_COUNT: u32 = 10; +const DEFAULT_MAX_CHANNEL_SATURATION_POWER_OF_HALF: u32 = 2; + #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Cli { @@ -55,6 +63,14 @@ enum Commands { invoice: String, #[arg(long)] amount_msat: Option, + #[arg(long)] + max_total_routing_fee_msat: Option, + #[arg(long)] + max_total_cltv_expiry_delta: Option, + #[arg(long)] + max_path_count: Option, + #[arg(long)] + max_channel_saturation_power_of_half: Option, }, Bolt12Receive { #[arg(short, long)] @@ -75,6 +91,14 @@ enum Commands { quantity: Option, #[arg(short, long)] payer_note: Option, + #[arg(long)] + max_total_routing_fee_msat: Option, + #[arg(long)] + max_total_cltv_expiry_delta: Option, + #[arg(long)] + max_path_count: Option, + #[arg(long)] + max_channel_saturation_power_of_half: Option, }, CloseChannel { #[arg(short, long)] @@ -161,9 +185,30 @@ async fn main() { handle_response_result(client.bolt11_receive(request).await); }, - Commands::Bolt11Send { invoice, amount_msat } => { + Commands::Bolt11Send { + invoice, + amount_msat, + max_total_routing_fee_msat, + max_total_cltv_expiry_delta, + max_path_count, + max_channel_saturation_power_of_half, + } => { + let route_parameters = RouteParametersConfig { + max_total_routing_fee_msat, + max_total_cltv_expiry_delta: max_total_cltv_expiry_delta + .unwrap_or(DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA), + max_path_count: max_path_count.unwrap_or(DEFAULT_MAX_PATH_COUNT), + max_channel_saturation_power_of_half: max_channel_saturation_power_of_half + .unwrap_or(DEFAULT_MAX_CHANNEL_SATURATION_POWER_OF_HALF), + }; handle_response_result( - client.bolt11_send(Bolt11SendRequest { invoice, amount_msat }).await, + client + .bolt11_send(Bolt11SendRequest { + invoice, + amount_msat, + route_parameters: Some(route_parameters), + }) + .await, ); }, Commands::Bolt12Receive { description, amount_msat, expiry_secs, quantity } => { @@ -178,10 +223,34 @@ async fn main() { .await, ); }, - Commands::Bolt12Send { offer, amount_msat, quantity, payer_note } => { + Commands::Bolt12Send { + offer, + amount_msat, + quantity, + payer_note, + max_total_routing_fee_msat, + max_total_cltv_expiry_delta, + max_path_count, + max_channel_saturation_power_of_half, + } => { + let route_parameters = RouteParametersConfig { + max_total_routing_fee_msat, + max_total_cltv_expiry_delta: max_total_cltv_expiry_delta + .unwrap_or(DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA), + max_path_count: max_path_count.unwrap_or(DEFAULT_MAX_PATH_COUNT), + max_channel_saturation_power_of_half: max_channel_saturation_power_of_half + .unwrap_or(DEFAULT_MAX_CHANNEL_SATURATION_POWER_OF_HALF), + }; + handle_response_result( client - .bolt12_send(Bolt12SendRequest { offer, amount_msat, quantity, payer_note }) + .bolt12_send(Bolt12SendRequest { + offer, + amount_msat, + quantity, + payer_note, + route_parameters: Some(route_parameters), + }) .await, ); }, diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index d89283b6c..631ef8375 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -141,6 +141,9 @@ pub struct Bolt11SendRequest { /// This operation will fail if the amount specified is less than the value required by the given invoice. #[prost(uint64, optional, tag = "2")] pub amount_msat: ::core::option::Option, + /// Configuration options for payment routing and pathfinding. + #[prost(message, optional, tag = "3")] + pub route_parameters: ::core::option::Option, } /// The response `content` for the `Bolt11Send` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. @@ -205,6 +208,9 @@ pub struct Bolt12SendRequest { /// If set, it will be seen by the recipient and reflected back in the invoice. #[prost(string, optional, tag = "4")] pub payer_note: ::core::option::Option<::prost::alloc::string::String>, + /// Configuration options for payment routing and pathfinding. + #[prost(message, optional, tag = "5")] + pub route_parameters: ::core::option::Option, } /// The response `content` for the `Bolt12Send` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. diff --git a/ldk-server/ldk-server-protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto index 32be3c374..49d4ff761 100644 --- a/ldk-server/ldk-server-protos/src/proto/api.proto +++ b/ldk-server/ldk-server-protos/src/proto/api.proto @@ -138,6 +138,9 @@ message Bolt11SendRequest { // amount paid to be determined by the user. // This operation will fail if the amount specified is less than the value required by the given invoice. optional uint64 amount_msat = 2; + + // Configuration options for payment routing and pathfinding. + optional types.RouteParametersConfig route_parameters = 3; } @@ -199,6 +202,9 @@ message Bolt12SendRequest { // If set, it will be seen by the recipient and reflected back in the invoice. optional string payer_note = 4; + + // Configuration options for payment routing and pathfinding. + optional types.RouteParametersConfig route_parameters = 5; } // The response `content` for the `Bolt12Send` API, when HttpStatusCode is OK (200). diff --git a/ldk-server/ldk-server/src/api/bolt11_send.rs b/ldk-server/ldk-server/src/api/bolt11_send.rs index 6a1314345..fd22b415c 100644 --- a/ldk-server/ldk-server/src/api/bolt11_send.rs +++ b/ldk-server/ldk-server/src/api/bolt11_send.rs @@ -1,5 +1,7 @@ use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; +use ldk_node::lightning::routing::router::RouteParametersConfig; use ldk_node::lightning_invoice::Bolt11Invoice; use ldk_server_protos::api::{Bolt11SendRequest, Bolt11SendResponse}; use std::str::FromStr; @@ -12,10 +14,38 @@ pub(crate) fn handle_bolt11_send_request( let invoice = Bolt11Invoice::from_str(&request.invoice.as_str()) .map_err(|_| ldk_node::NodeError::InvalidInvoice)?; + let route_parameters = match request.route_parameters { + Some(params) => { + let max_path_count: u8 = params.max_path_count.try_into().map_err(|_| { + LdkServerError::new( + InvalidRequestError, + format!("Invalid max_path_count, must be between 0 and {}", u8::MAX), + ) + })?; + let max_channel_saturation_power_of_half: u8 = + params.max_channel_saturation_power_of_half.try_into().map_err(|_| { + LdkServerError::new( + InvalidRequestError, + format!( + "Invalid max_channel_saturation_power_of_half, must be between 0 and {}", + u8::MAX + ), + ) + })?; + Some(RouteParametersConfig { + max_total_routing_fee_msat: params.max_total_routing_fee_msat, + max_total_cltv_expiry_delta: params.max_total_cltv_expiry_delta, + max_path_count, + max_channel_saturation_power_of_half, + }) + }, + None => None, + }; + let payment_id = match request.amount_msat { - None => context.node.bolt11_payment().send(&invoice, None), + None => context.node.bolt11_payment().send(&invoice, route_parameters), Some(amount_msat) => { - context.node.bolt11_payment().send_using_amount(&invoice, amount_msat, None) + context.node.bolt11_payment().send_using_amount(&invoice, amount_msat, route_parameters) }, }?; diff --git a/ldk-server/ldk-server/src/api/bolt12_send.rs b/ldk-server/ldk-server/src/api/bolt12_send.rs index bbf392a75..439fe1376 100644 --- a/ldk-server/ldk-server/src/api/bolt12_send.rs +++ b/ldk-server/ldk-server/src/api/bolt12_send.rs @@ -1,6 +1,8 @@ use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; use ldk_node::lightning::offers::offer::Offer; +use ldk_node::lightning::routing::router::RouteParametersConfig; use ldk_server_protos::api::{Bolt12SendRequest, Bolt12SendResponse}; use std::str::FromStr; @@ -12,16 +14,47 @@ pub(crate) fn handle_bolt12_send_request( let offer = Offer::from_str(&request.offer.as_str()).map_err(|_| ldk_node::NodeError::InvalidOffer)?; - let payment_id = match request.amount_msat { - None => { - context.node.bolt12_payment().send(&offer, request.quantity, request.payer_note, None) + let route_parameters = match request.route_parameters { + Some(params) => { + let max_path_count = params.max_path_count.try_into().map_err(|_| { + LdkServerError::new( + InvalidRequestError, + format!("Invalid max_path_count, must be between 0 and {}", u8::MAX), + ) + })?; + let max_channel_saturation_power_of_half = + params.max_channel_saturation_power_of_half.try_into().map_err(|_| { + LdkServerError::new( + InvalidRequestError, + format!( + "Invalid max_channel_saturation_power_of_half, must be between 0 and {}", + u8::MAX + ), + ) + })?; + Some(RouteParametersConfig { + max_total_routing_fee_msat: params.max_total_routing_fee_msat, + max_total_cltv_expiry_delta: params.max_total_cltv_expiry_delta, + max_path_count, + max_channel_saturation_power_of_half, + }) }, + None => None, + }; + + let payment_id = match request.amount_msat { + None => context.node.bolt12_payment().send( + &offer, + request.quantity, + request.payer_note, + route_parameters, + ), Some(amount_msat) => context.node.bolt12_payment().send_using_amount( &offer, amount_msat, request.quantity, request.payer_note, - None, + route_parameters, ), }?; From fd0d364b39a78da1be2cd7d38bc7b98fef2ba2ae Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 21 Oct 2025 13:12:15 -0500 Subject: [PATCH 169/203] Add splicing RPCs and CLI commands --- ldk-server/ldk-server-cli/src/main.rs | 48 ++++++++++++- ldk-server/ldk-server-client/src/client.rs | 23 ++++++- ldk-server/ldk-server-protos/src/api.rs | 49 +++++++++++++ ldk-server/ldk-server-protos/src/endpoints.rs | 2 + .../ldk-server-protos/src/proto/api.proto | 45 ++++++++++++ ldk-server/ldk-server/src/api/mod.rs | 1 + ldk-server/ldk-server/src/api/onchain_send.rs | 2 +- .../ldk-server/src/api/splice_channel.rs | 68 +++++++++++++++++++ ldk-server/ldk-server/src/service.rs | 6 +- 9 files changed, 239 insertions(+), 5 deletions(-) create mode 100644 ldk-server/ldk-server/src/api/splice_channel.rs diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index a45ec6ea9..caa43e776 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -8,7 +8,7 @@ use ldk_server_client::ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, Bolt12SendRequest, CloseChannelRequest, ForceCloseChannelRequest, GetBalancesRequest, GetNodeInfoRequest, ListChannelsRequest, ListPaymentsRequest, OnchainReceiveRequest, OnchainSendRequest, - OpenChannelRequest, + OpenChannelRequest, SpliceInRequest, SpliceOutRequest, }; use ldk_server_client::ldk_server_protos::types::{ bolt11_invoice_description, Bolt11InvoiceDescription, PageToken, Payment, @@ -102,6 +102,24 @@ enum Commands { #[arg(long)] announce_channel: bool, }, + SpliceIn { + #[arg(short, long)] + user_channel_id: String, + #[arg(short, long)] + counterparty_node_id: String, + #[arg(long)] + splice_amount_sats: u64, + }, + SpliceOut { + #[arg(short, long)] + user_channel_id: String, + #[arg(short, long)] + counterparty_node_id: String, + #[arg(short, long)] + address: Option, + #[arg(long)] + splice_amount_sats: u64, + }, ListChannels, ListPayments { #[arg(short, long)] @@ -227,6 +245,34 @@ async fn main() { .await, ); }, + Commands::SpliceIn { user_channel_id, counterparty_node_id, splice_amount_sats } => { + handle_response_result( + client + .splice_in(SpliceInRequest { + user_channel_id, + counterparty_node_id, + splice_amount_sats, + }) + .await, + ); + }, + Commands::SpliceOut { + user_channel_id, + counterparty_node_id, + address, + splice_amount_sats, + } => { + handle_response_result( + client + .splice_out(SpliceOutRequest { + user_channel_id, + counterparty_node_id, + address, + splice_amount_sats, + }) + .await, + ); + }, Commands::ListChannels => { handle_response_result(client.list_channels(ListChannelsRequest {}).await); }, diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index 0b081a27f..237264b8e 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -11,13 +11,14 @@ use ldk_server_protos::api::{ GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse, ListChannelsRequest, ListChannelsResponse, ListPaymentsRequest, ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, - OpenChannelRequest, OpenChannelResponse, + OpenChannelRequest, OpenChannelResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest, + SpliceOutResponse, }; 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, LIST_CHANNELS_PATH, LIST_PAYMENTS_PATH, ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, - OPEN_CHANNEL_PATH, + OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH, }; use ldk_server_protos::error::{ErrorCode, ErrorResponse}; use reqwest::header::CONTENT_TYPE; @@ -119,6 +120,24 @@ impl LdkServerClient { self.post_request(&request, &url).await } + /// Splices funds into the channel specified by given request. + /// For API contract/usage, refer to docs for [`SpliceInRequest`] and [`SpliceInResponse`]. + pub async fn splice_in( + &self, request: SpliceInRequest, + ) -> Result { + let url = format!("http://{}/{SPLICE_IN_PATH}", self.base_url); + self.post_request(&request, &url).await + } + + /// Splices funds out of the channel specified by given request. + /// For API contract/usage, refer to docs for [`SpliceOutRequest`] and [`SpliceOutResponse`]. + pub async fn splice_out( + &self, request: SpliceOutRequest, + ) -> Result { + let url = format!("http://{}/{SPLICE_OUT_PATH}", self.base_url); + self.post_request(&request, &url).await + } + /// Closes the channel specified by given request. /// For API contract/usage, refer to docs for [`CloseChannelRequest`] and [`CloseChannelResponse`]. pub async fn close_channel( diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index d89283b6c..ebd4ade8a 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -249,6 +249,55 @@ pub struct OpenChannelResponse { #[prost(string, tag = "1")] pub user_channel_id: ::prost::alloc::string::String, } +/// Increases the channel balance by the given amount. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SpliceInRequest { + /// The local `user_channel_id` of the channel. + #[prost(string, tag = "1")] + pub user_channel_id: ::prost::alloc::string::String, + /// The hex-encoded public key of the channel's counterparty node. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// The amount of sats to splice into the channel. + #[prost(uint64, tag = "3")] + pub splice_amount_sats: u64, +} +/// The response `content` for the `SpliceIn` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SpliceInResponse {} +/// Decreases the channel balance by the given amount. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SpliceOutRequest { + /// The local `user_channel_id` of this channel. + #[prost(string, tag = "1")] + pub user_channel_id: ::prost::alloc::string::String, + /// The hex-encoded public key of the channel's counterparty node. + #[prost(string, tag = "2")] + pub counterparty_node_id: ::prost::alloc::string::String, + /// A Bitcoin on-chain address to send the spliced-out funds. + /// + /// If not set, an address from the node's on-chain wallet will be used. + #[prost(string, optional, tag = "3")] + pub address: ::core::option::Option<::prost::alloc::string::String>, + /// The amount of sats to splice out of the channel. + #[prost(uint64, tag = "4")] + pub splice_amount_sats: u64, +} +/// The response `content` for the `SpliceOut` API, when HttpStatusCode is OK (200). +/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SpliceOutResponse { + /// The Bitcoin on-chain address where the funds will be sent. + #[prost(string, tag = "1")] + pub address: ::prost::alloc::string::String, +} /// Update the config for a previously opened channel. /// See more: #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/ldk-server/ldk-server-protos/src/endpoints.rs b/ldk-server/ldk-server-protos/src/endpoints.rs index ef0c46563..d5990187c 100644 --- a/ldk-server/ldk-server-protos/src/endpoints.rs +++ b/ldk-server/ldk-server-protos/src/endpoints.rs @@ -7,6 +7,8 @@ pub const BOLT11_SEND_PATH: &str = "Bolt11Send"; pub const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive"; pub const BOLT12_SEND_PATH: &str = "Bolt12Send"; pub const OPEN_CHANNEL_PATH: &str = "OpenChannel"; +pub const SPLICE_IN_PATH: &str = "SpliceIn"; +pub const SPLICE_OUT_PATH: &str = "SpliceOut"; pub const CLOSE_CHANNEL_PATH: &str = "CloseChannel"; pub const FORCE_CLOSE_CHANNEL_PATH: &str = "ForceCloseChannel"; pub const LIST_CHANNELS_PATH: &str = "ListChannels"; diff --git a/ldk-server/ldk-server-protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto index 32be3c374..60c1ab44f 100644 --- a/ldk-server/ldk-server-protos/src/proto/api.proto +++ b/ldk-server/ldk-server-protos/src/proto/api.proto @@ -241,6 +241,51 @@ message OpenChannelResponse { string user_channel_id = 1; } +// Increases the channel balance by the given amount. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.splice_in +message SpliceInRequest { + + // The local `user_channel_id` of the channel. + string user_channel_id = 1; + + // The hex-encoded public key of the channel's counterparty node. + string counterparty_node_id = 2; + + // The amount of sats to splice into the channel. + uint64 splice_amount_sats = 3; +} + +// The response `content` for the `SpliceIn` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. +message SpliceInResponse {} + +// Decreases the channel balance by the given amount. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.splice_out +message SpliceOutRequest { + + // The local `user_channel_id` of this channel. + string user_channel_id = 1; + + // The hex-encoded public key of the channel's counterparty node. + string counterparty_node_id = 2; + + // A Bitcoin on-chain address to send the spliced-out funds. + // + // If not set, an address from the node's on-chain wallet will be used. + optional string address = 3; + + // The amount of sats to splice out of the channel. + uint64 splice_amount_sats = 4; +} + +// The response `content` for the `SpliceOut` API, when HttpStatusCode is OK (200). +// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. +message SpliceOutResponse { + + // The Bitcoin on-chain address where the funds will be sent. + string address = 1; +} + // Update the config for a previously opened channel. // See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.update_channel_config message UpdateChannelConfigRequest { diff --git a/ldk-server/ldk-server/src/api/mod.rs b/ldk-server/ldk-server/src/api/mod.rs index c1b0fa2ec..f80a4f554 100644 --- a/ldk-server/ldk-server/src/api/mod.rs +++ b/ldk-server/ldk-server/src/api/mod.rs @@ -13,4 +13,5 @@ pub(crate) mod list_payments; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; pub(crate) mod open_channel; +pub(crate) mod splice_channel; pub(crate) mod update_channel_config; diff --git a/ldk-server/ldk-server/src/api/onchain_send.rs b/ldk-server/ldk-server/src/api/onchain_send.rs index d169cb1ac..b84c671dd 100644 --- a/ldk-server/ldk-server/src/api/onchain_send.rs +++ b/ldk-server/ldk-server/src/api/onchain_send.rs @@ -14,7 +14,7 @@ pub(crate) fn handle_onchain_send_request( .map_err(|_| { LdkServerError::new( InvalidRequestError, - "Address is not valid for LdkServer's configured network.".to_string(), + "Address is not valid for the configured network.".to_string(), ) })?; diff --git a/ldk-server/ldk-server/src/api/splice_channel.rs b/ldk-server/ldk-server/src/api/splice_channel.rs new file mode 100644 index 000000000..cab921077 --- /dev/null +++ b/ldk-server/ldk-server/src/api/splice_channel.rs @@ -0,0 +1,68 @@ +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; +use crate::service::Context; +use ldk_node::bitcoin::secp256k1::PublicKey; +use ldk_node::bitcoin::Address; +use ldk_node::UserChannelId; +use ldk_server_protos::api::{ + SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse, +}; +use std::str::FromStr; + +pub(crate) fn handle_splice_in_request( + context: Context, request: SpliceInRequest, +) -> Result { + let user_channel_id = parse_user_channel_id(&request.user_channel_id)?; + let counterparty_node_id = parse_counterparty_node_id(&request.counterparty_node_id)?; + + context.node.splice_in(&user_channel_id, counterparty_node_id, request.splice_amount_sats)?; + + Ok(SpliceInResponse {}) +} + +pub(crate) fn handle_splice_out_request( + context: Context, request: SpliceOutRequest, +) -> Result { + let user_channel_id = parse_user_channel_id(&request.user_channel_id)?; + let counterparty_node_id = parse_counterparty_node_id(&request.counterparty_node_id)?; + + let address = request + .address + .map(|address| { + Address::from_str(&address) + .and_then(|address| address.require_network(context.node.config().network)) + .map_err(|_| ldk_node::NodeError::InvalidAddress) + }) + .unwrap_or_else(|| context.node.onchain_payment().new_address()) + .map_err(|_| { + LdkServerError::new( + InvalidRequestError, + "Address is not valid for the configured network.".to_string(), + ) + })?; + + context.node.splice_out( + &user_channel_id, + counterparty_node_id, + &address, + request.splice_amount_sats, + )?; + + Ok(SpliceOutResponse { address: address.to_string() }) +} + +fn parse_user_channel_id(id: &str) -> Result { + let parsed = id.parse::().map_err(|_| { + LdkServerError::new(InvalidRequestError, "Invalid UserChannelId.".to_string()) + })?; + Ok(UserChannelId(parsed)) +} + +fn parse_counterparty_node_id(id: &str) -> Result { + PublicKey::from_str(id).map_err(|e| { + LdkServerError::new( + InvalidRequestError, + format!("Invalid counterparty node ID, error: {}", e), + ) + }) +} diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index f71380b64..b1144a7da 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -9,7 +9,8 @@ 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, UPDATE_CHANNEL_CONFIG_PATH, + ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH, + UPDATE_CHANNEL_CONFIG_PATH, }; use prost::Message; @@ -30,6 +31,7 @@ use crate::api::list_payments::handle_list_payments_request; use crate::api::onchain_receive::handle_onchain_receive_request; use crate::api::onchain_send::handle_onchain_send_request; use crate::api::open_channel::handle_open_channel; +use crate::api::splice_channel::{handle_splice_in_request, handle_splice_out_request}; use crate::api::update_channel_config::handle_update_channel_config_request; use crate::io::persist::paginated_kv_store::PaginatedKVStore; use crate::util::proto_adapter::to_error_response; @@ -91,6 +93,8 @@ impl Service> for NodeService { }, BOLT12_SEND_PATH => Box::pin(handle_request(context, req, handle_bolt12_send_request)), OPEN_CHANNEL_PATH => Box::pin(handle_request(context, req, handle_open_channel)), + SPLICE_IN_PATH => Box::pin(handle_request(context, req, handle_splice_in_request)), + SPLICE_OUT_PATH => Box::pin(handle_request(context, req, handle_splice_out_request)), CLOSE_CHANNEL_PATH => { Box::pin(handle_request(context, req, handle_close_channel_request)) }, From 85cde3c395ade9caf783118143a0bc33b68ef5be Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 9 Dec 2025 18:27:45 -0600 Subject: [PATCH 170/203] Add ChannelConfig options to open channel cli command These were available on the server side but not in the cli. Not all options are given as they aren't likely to be used and more likely to be confusing to users. --- ldk-server/ldk-server-cli/src/main.rs | 52 +++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index a45ec6ea9..d1de29ca0 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -11,7 +11,8 @@ use ldk_server_client::ldk_server_protos::api::{ OpenChannelRequest, }; use ldk_server_client::ldk_server_protos::types::{ - bolt11_invoice_description, Bolt11InvoiceDescription, PageToken, Payment, + bolt11_invoice_description, channel_config, Bolt11InvoiceDescription, ChannelConfig, PageToken, + Payment, }; use std::fmt::Debug; @@ -101,6 +102,22 @@ enum Commands { push_to_counterparty_msat: Option, #[arg(long)] announce_channel: bool, + // Channel config options + #[arg( + long, + help = "Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound over the channel. This can be updated by using update-channel-config." + )] + forwarding_fee_proportional_millionths: Option, + #[arg( + long, + help = "Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in excess of forwarding_fee_proportional_millionths. This can be updated by using update-channel-config." + )] + forwarding_fee_base_msat: Option, + #[arg( + long, + help = "The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over the channel. This can be updated by using update-channel-config." + )] + cltv_expiry_delta: Option, }, ListChannels, ListPayments { @@ -213,7 +230,16 @@ async fn main() { channel_amount_sats, push_to_counterparty_msat, announce_channel, + forwarding_fee_proportional_millionths, + forwarding_fee_base_msat, + cltv_expiry_delta, } => { + let channel_config = build_open_channel_config( + forwarding_fee_proportional_millionths, + forwarding_fee_base_msat, + cltv_expiry_delta, + ); + handle_response_result( client .open_channel(OpenChannelRequest { @@ -221,7 +247,7 @@ async fn main() { address, channel_amount_sats, push_to_counterparty_msat, - channel_config: None, + channel_config, announce_channel, }) .await, @@ -236,6 +262,28 @@ async fn main() { } } +fn build_open_channel_config( + forwarding_fee_proportional_millionths: Option, forwarding_fee_base_msat: Option, + cltv_expiry_delta: Option, +) -> Option { + // Only create a config if at least one field is set + if forwarding_fee_proportional_millionths.is_none() + && forwarding_fee_base_msat.is_none() + && cltv_expiry_delta.is_none() + { + return None; + } + + Some(ChannelConfig { + forwarding_fee_proportional_millionths, + forwarding_fee_base_msat, + cltv_expiry_delta, + force_close_avoidance_max_fee_satoshis: None, + accept_underpaying_htlcs: None, + max_dust_htlc_exposure: None, + }) +} + async fn list_n_payments( client: LdkServerClient, number_of_payments: Option, ) -> Result, LdkServerError> { From 0fe905b1a0bb5c820a3a2a83d7e7acd41fe7ad5b Mon Sep 17 00:00:00 2001 From: benthecarman Date: Wed, 10 Dec 2025 18:34:32 -0600 Subject: [PATCH 171/203] Add update channel config cli command This was hooked up on the backend but not in the client or cli --- ldk-server/ldk-server-cli/src/main.rs | 49 +++++++++++++++++++++- ldk-server/ldk-server-client/src/client.rs | 13 +++++- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 7385c9d64..f9efe39f8 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -8,7 +8,7 @@ use ldk_server_client::ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, Bolt12SendRequest, CloseChannelRequest, ForceCloseChannelRequest, GetBalancesRequest, GetNodeInfoRequest, ListChannelsRequest, ListPaymentsRequest, OnchainReceiveRequest, OnchainSendRequest, - OpenChannelRequest, SpliceInRequest, SpliceOutRequest, + OpenChannelRequest, SpliceInRequest, SpliceOutRequest, UpdateChannelConfigRequest, }; use ldk_server_client::ldk_server_protos::types::RouteParametersConfig; use ldk_server_client::ldk_server_protos::types::{ @@ -169,6 +169,27 @@ enum Commands { )] number_of_payments: Option, }, + UpdateChannelConfig { + #[arg(short, long)] + user_channel_id: String, + #[arg(short, long)] + counterparty_node_id: String, + #[arg( + long, + help = "Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound over the channel. This can be updated by using update-channel-config." + )] + forwarding_fee_proportional_millionths: Option, + #[arg( + long, + help = "Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in excess of forwarding_fee_proportional_millionths. This can be updated by using update-channel-config." + )] + forwarding_fee_base_msat: Option, + #[arg( + long, + help = "The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over the channel." + )] + cltv_expiry_delta: Option, + }, } #[tokio::main] @@ -374,6 +395,32 @@ async fn main() { Commands::ListPayments { number_of_payments } => { handle_response_result(list_n_payments(client, number_of_payments).await); }, + Commands::UpdateChannelConfig { + user_channel_id, + counterparty_node_id, + forwarding_fee_proportional_millionths, + forwarding_fee_base_msat, + cltv_expiry_delta, + } => { + let channel_config = ChannelConfig { + forwarding_fee_proportional_millionths, + forwarding_fee_base_msat, + cltv_expiry_delta, + force_close_avoidance_max_fee_satoshis: None, + accept_underpaying_htlcs: None, + max_dust_htlc_exposure: None, + }; + + handle_response_result( + client + .update_channel_config(UpdateChannelConfigRequest { + user_channel_id, + counterparty_node_id, + channel_config: Some(channel_config), + }) + .await, + ); + }, } } diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index 237264b8e..7fbe5dfa6 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -12,13 +12,13 @@ use ldk_server_protos::api::{ ListChannelsRequest, ListChannelsResponse, ListPaymentsRequest, ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, OpenChannelResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest, - SpliceOutResponse, + 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, LIST_CHANNELS_PATH, LIST_PAYMENTS_PATH, ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, - OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH, + OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH, UPDATE_CHANNEL_CONFIG_PATH, }; use ldk_server_protos::error::{ErrorCode, ErrorResponse}; use reqwest::header::CONTENT_TYPE; @@ -174,6 +174,15 @@ impl LdkServerClient { self.post_request(&request, &url).await } + /// Updates the config for a previously opened channel. + /// For API contract/usage, refer to docs for [`UpdateChannelConfigRequest`] and [`UpdateChannelConfigResponse`]. + pub async fn update_channel_config( + &self, request: UpdateChannelConfigRequest, + ) -> Result { + let url = format!("http://{}/{UPDATE_CHANNEL_CONFIG_PATH}", self.base_url); + self.post_request(&request, &url).await + } + async fn post_request( &self, request: &Rq, url: &str, ) -> Result { From 0e4064ddf2ea9134f8fc0f2fe5fce05c5029d61b Mon Sep 17 00:00:00 2001 From: benthecarman Date: Mon, 8 Dec 2025 18:32:04 -0600 Subject: [PATCH 172/203] Make cli output json Previously we would output the debug format of each of our return times which worked, but was not very usable. You could not easily pipe results with cli tools or anything like that. This changes the results to be output to json to make it easier to use and more similiar to what people expect. --- ldk-server/Cargo.lock | 8 ++- ldk-server/ldk-server-cli/Cargo.toml | 5 +- ldk-server/ldk-server-cli/src/main.rs | 81 +++++++++++++++------- ldk-server/ldk-server-client/Cargo.toml | 4 ++ ldk-server/ldk-server-protos/Cargo.toml | 8 ++- ldk-server/ldk-server-protos/build.rs | 5 ++ ldk-server/ldk-server-protos/src/api.rs | 76 +++++++++++++++++++- ldk-server/ldk-server-protos/src/error.rs | 4 ++ ldk-server/ldk-server-protos/src/events.rs | 12 ++++ ldk-server/ldk-server-protos/src/types.rs | 78 +++++++++++++++++++++ 10 files changed, 249 insertions(+), 32 deletions(-) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 828cb3ca6..ba02fb5ed 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -546,6 +546,9 @@ name = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +dependencies = [ + "serde", +] [[package]] name = "cbc" @@ -1739,7 +1742,8 @@ version = "0.1.0" dependencies = [ "clap", "ldk-server-client", - "prost", + "serde", + "serde_json", "tokio", ] @@ -1756,8 +1760,10 @@ dependencies = [ name = "ldk-server-protos" version = "0.1.0" dependencies = [ + "bytes", "prost", "prost-build", + "serde", ] [[package]] diff --git a/ldk-server/ldk-server-cli/Cargo.toml b/ldk-server/ldk-server-cli/Cargo.toml index a38ca83b8..bc77d1d4a 100644 --- a/ldk-server/ldk-server-cli/Cargo.toml +++ b/ldk-server/ldk-server-cli/Cargo.toml @@ -4,7 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] -ldk-server-client = { path = "../ldk-server-client" } +ldk-server-client = { path = "../ldk-server-client", features = ["serde"] } clap = { version = "4.0.5", default-features = false, features = ["derive", "std", "error-context", "suggestions", "help"] } tokio = { version = "1.38.0", default-features = false, features = ["rt-multi-thread", "macros"] } -prost = { version = "0.11.6", default-features = false} +serde = "1.0" +serde_json = "1.0" diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index f9efe39f8..18394e383 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -5,17 +5,20 @@ use ldk_server_client::error::LdkServerErrorCode::{ AuthError, InternalError, InternalServerError, InvalidRequestError, LightningError, }; use ldk_server_client::ldk_server_protos::api::{ - Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, Bolt12SendRequest, - CloseChannelRequest, ForceCloseChannelRequest, GetBalancesRequest, GetNodeInfoRequest, - ListChannelsRequest, ListPaymentsRequest, OnchainReceiveRequest, OnchainSendRequest, - OpenChannelRequest, SpliceInRequest, SpliceOutRequest, UpdateChannelConfigRequest, + Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse, + Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, + CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse, + GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse, + ListChannelsRequest, ListChannelsResponse, ListPaymentsRequest, ListPaymentsResponse, + OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, + OpenChannelRequest, OpenChannelResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest, + SpliceOutResponse, UpdateChannelConfigRequest, UpdateChannelConfigResponse, }; -use ldk_server_client::ldk_server_protos::types::RouteParametersConfig; use ldk_server_client::ldk_server_protos::types::{ - bolt11_invoice_description, channel_config, Bolt11InvoiceDescription, ChannelConfig, PageToken, - Payment, + bolt11_invoice_description, Bolt11InvoiceDescription, ChannelConfig, PageToken, Payment, + RouteParametersConfig, }; -use std::fmt::Debug; +use serde::Serialize; // Having these default values as constants in the Proto file and // importing/reusing them here might be better, but Proto3 removed @@ -199,16 +202,22 @@ async fn main() { match cli.command { Commands::GetNodeInfo => { - handle_response_result(client.get_node_info(GetNodeInfoRequest {}).await); + handle_response_result::<_, GetNodeInfoResponse>( + client.get_node_info(GetNodeInfoRequest {}).await, + ); }, Commands::GetBalances => { - handle_response_result(client.get_balances(GetBalancesRequest {}).await); + handle_response_result::<_, GetBalancesResponse>( + client.get_balances(GetBalancesRequest {}).await, + ); }, Commands::OnchainReceive => { - handle_response_result(client.onchain_receive(OnchainReceiveRequest {}).await); + handle_response_result::<_, OnchainReceiveResponse>( + client.onchain_receive(OnchainReceiveRequest {}).await, + ); }, Commands::OnchainSend { address, amount_sats, send_all, fee_rate_sat_per_vb } => { - handle_response_result( + handle_response_result::<_, OnchainSendResponse>( client .onchain_send(OnchainSendRequest { address, @@ -239,7 +248,9 @@ async fn main() { let request = Bolt11ReceiveRequest { description: invoice_description, expiry_secs, amount_msat }; - handle_response_result(client.bolt11_receive(request).await); + handle_response_result::<_, Bolt11ReceiveResponse>( + client.bolt11_receive(request).await, + ); }, Commands::Bolt11Send { invoice, @@ -257,7 +268,7 @@ async fn main() { max_channel_saturation_power_of_half: max_channel_saturation_power_of_half .unwrap_or(DEFAULT_MAX_CHANNEL_SATURATION_POWER_OF_HALF), }; - handle_response_result( + handle_response_result::<_, Bolt11SendResponse>( client .bolt11_send(Bolt11SendRequest { invoice, @@ -268,7 +279,7 @@ async fn main() { ); }, Commands::Bolt12Receive { description, amount_msat, expiry_secs, quantity } => { - handle_response_result( + handle_response_result::<_, Bolt12ReceiveResponse>( client .bolt12_receive(Bolt12ReceiveRequest { description, @@ -298,7 +309,7 @@ async fn main() { .unwrap_or(DEFAULT_MAX_CHANNEL_SATURATION_POWER_OF_HALF), }; - handle_response_result( + handle_response_result::<_, Bolt12SendResponse>( client .bolt12_send(Bolt12SendRequest { offer, @@ -311,7 +322,7 @@ async fn main() { ); }, Commands::CloseChannel { user_channel_id, counterparty_node_id } => { - handle_response_result( + handle_response_result::<_, CloseChannelResponse>( client .close_channel(CloseChannelRequest { user_channel_id, counterparty_node_id }) .await, @@ -322,7 +333,7 @@ async fn main() { counterparty_node_id, force_close_reason, } => { - handle_response_result( + handle_response_result::<_, ForceCloseChannelResponse>( client .force_close_channel(ForceCloseChannelRequest { user_channel_id, @@ -348,7 +359,7 @@ async fn main() { cltv_expiry_delta, ); - handle_response_result( + handle_response_result::<_, OpenChannelResponse>( client .open_channel(OpenChannelRequest { node_pubkey, @@ -362,7 +373,7 @@ async fn main() { ); }, Commands::SpliceIn { user_channel_id, counterparty_node_id, splice_amount_sats } => { - handle_response_result( + handle_response_result::<_, SpliceInResponse>( client .splice_in(SpliceInRequest { user_channel_id, @@ -378,7 +389,7 @@ async fn main() { address, splice_amount_sats, } => { - handle_response_result( + handle_response_result::<_, SpliceOutResponse>( client .splice_out(SpliceOutRequest { user_channel_id, @@ -390,10 +401,17 @@ async fn main() { ); }, Commands::ListChannels => { - handle_response_result(client.list_channels(ListChannelsRequest {}).await); + handle_response_result::<_, ListChannelsResponse>( + client.list_channels(ListChannelsRequest {}).await, + ); }, Commands::ListPayments { number_of_payments } => { - handle_response_result(list_n_payments(client, number_of_payments).await); + handle_response_result::<_, ListPaymentsResponse>( + list_n_payments(client, number_of_payments) + .await + // todo: handle pagination properly + .map(|payments| ListPaymentsResponse { payments, next_page_token: None }), + ); }, Commands::UpdateChannelConfig { user_channel_id, @@ -411,7 +429,7 @@ async fn main() { max_dust_htlc_exposure: None, }; - handle_response_result( + handle_response_result::<_, UpdateChannelConfigResponse>( client .update_channel_config(UpdateChannelConfigRequest { user_channel_id, @@ -466,10 +484,21 @@ async fn list_n_payments( Ok(payments) } -fn handle_response_result(response: Result) { +fn handle_response_result(response: Result) +where + Rs: Into, + Js: Serialize + std::fmt::Debug, +{ match response { Ok(response) => { - println!("Success: {:?}", response); + let json_response: Js = response.into(); + match serde_json::to_string_pretty(&json_response) { + Ok(json) => println!("{json}"), + Err(e) => { + eprintln!("Error serializing response ({json_response:?}) to JSON: {e}"); + std::process::exit(1); + }, + } }, Err(e) => { handle_error(e); diff --git a/ldk-server/ldk-server-client/Cargo.toml b/ldk-server/ldk-server-client/Cargo.toml index 9db5fc2fc..ca0ffadb1 100644 --- a/ldk-server/ldk-server-client/Cargo.toml +++ b/ldk-server/ldk-server-client/Cargo.toml @@ -3,6 +3,10 @@ name = "ldk-server-client" version = "0.1.0" edition = "2021" +[features] +default = [] +serde = ["ldk-server-protos/serde"] + [dependencies] ldk-server-protos = { path = "../ldk-server-protos" } reqwest = { version = "0.11.13", default-features = false, features = ["rustls-tls"] } diff --git a/ldk-server/ldk-server-protos/Cargo.toml b/ldk-server/ldk-server-protos/Cargo.toml index 5d164846c..894abe90e 100644 --- a/ldk-server/ldk-server-protos/Cargo.toml +++ b/ldk-server/ldk-server-protos/Cargo.toml @@ -5,8 +5,14 @@ edition = "2021" build = "build.rs" +[features] +default = [] +serde = ["dep:serde", "dep:bytes"] + [dependencies] prost = { version = "0.11.6", default-features = false, features = ["std", "prost-derive"] } +serde = { version = "1.0", features = ["derive"], optional = true } +bytes = { version = "1", features = ["serde"], optional = true } [target.'cfg(genproto)'.build-dependencies] -prost-build = { version = "0.11.6" , default-features = false} +prost-build = { version = "0.11.6", default-features = false } diff --git a/ldk-server/ldk-server-protos/build.rs b/ldk-server/ldk-server-protos/build.rs index 76eb77a2e..5ffcf7acb 100644 --- a/ldk-server/ldk-server-protos/build.rs +++ b/ldk-server/ldk-server-protos/build.rs @@ -14,6 +14,11 @@ fn main() { fn generate_protos() { prost_build::Config::new() .bytes(&["."]) + .type_attribute( + ".", + "#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]", + ) + .type_attribute(".", "#[cfg_attr(feature = \"serde\", serde(rename_all = \"snake_case\"))]") .compile_protos( &[ "src/proto/api.proto", diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index 1f7b67c95..d146a7e93 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -2,11 +2,15 @@ /// 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 GetNodeInfoRequest {} /// The response `content` for the `GetNodeInfo` 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 GetNodeInfoResponse { @@ -49,11 +53,15 @@ pub struct GetNodeInfoResponse { } /// Retrieve a new on-chain funding address. /// 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 OnchainReceiveRequest {} /// The response `content` for the `OnchainReceive` 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 OnchainReceiveResponse { @@ -62,6 +70,8 @@ pub struct OnchainReceiveResponse { pub address: ::prost::alloc::string::String, } /// Send an on-chain payment to the given address. +#[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 OnchainSendRequest { @@ -90,6 +100,8 @@ pub struct OnchainSendRequest { } /// The response `content` for the `OnchainSend` 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 OnchainSendResponse { @@ -103,6 +115,8 @@ pub struct OnchainSendResponse { /// 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 Bolt11ReceiveRequest { @@ -119,6 +133,8 @@ pub struct Bolt11ReceiveRequest { } /// The response `content` for the `Bolt11Receive` 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 Bolt11ReceiveResponse { @@ -130,6 +146,8 @@ pub struct Bolt11ReceiveResponse { } /// Send a payment for a BOLT11 invoice. /// 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 Bolt11SendRequest { @@ -147,6 +165,8 @@ pub struct Bolt11SendRequest { } /// The response `content` for the `Bolt11Send` 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 Bolt11SendResponse { @@ -159,6 +179,8 @@ pub struct Bolt11SendResponse { /// 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 Bolt12ReceiveRequest { @@ -178,6 +200,8 @@ pub struct Bolt12ReceiveRequest { } /// The response `content` for the `Bolt12Receive` 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 Bolt12ReceiveResponse { @@ -191,6 +215,8 @@ pub struct Bolt12ReceiveResponse { /// 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 Bolt12SendRequest { @@ -214,6 +240,8 @@ pub struct Bolt12SendRequest { } /// The response `content` for the `Bolt12Send` 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 Bolt12SendResponse { @@ -223,6 +251,8 @@ pub struct Bolt12SendResponse { } /// Creates a new outbound channel to the given remote node. /// 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 OpenChannelRequest { @@ -248,6 +278,8 @@ pub struct OpenChannelRequest { } /// The response `content` for the `OpenChannel` 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 OpenChannelResponse { @@ -256,7 +288,9 @@ pub struct OpenChannelResponse { pub user_channel_id: ::prost::alloc::string::String, } /// Increases the channel balance by the given amount. -/// See more: +/// 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 SpliceInRequest { @@ -272,11 +306,15 @@ pub struct SpliceInRequest { } /// The response `content` for the `SpliceIn` 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 SpliceInResponse {} /// Decreases the channel balance by the given amount. -/// See more: +/// 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 SpliceOutRequest { @@ -297,6 +335,8 @@ pub struct SpliceOutRequest { } /// The response `content` for the `SpliceOut` 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 SpliceOutResponse { @@ -306,6 +346,8 @@ pub struct SpliceOutResponse { } /// Update the config for a previously opened channel. /// 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 UpdateChannelConfigRequest { @@ -321,11 +363,15 @@ pub struct UpdateChannelConfigRequest { } /// The response `content` for the `UpdateChannelConfig` 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 UpdateChannelConfigResponse {} /// Closes the channel specified by given request. /// 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 CloseChannelRequest { @@ -338,11 +384,15 @@ pub struct CloseChannelRequest { } /// The response `content` for the `CloseChannel` 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 CloseChannelResponse {} /// Force closes the channel specified by given request. /// 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 ForceCloseChannelRequest { @@ -358,16 +408,22 @@ pub struct ForceCloseChannelRequest { } /// The response `content` for the `ForceCloseChannel` 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 ForceCloseChannelResponse {} /// Returns a list of known channels. /// 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 ListChannelsRequest {} /// The response `content` for the `ListChannels` 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 ListChannelsResponse { @@ -377,6 +433,8 @@ pub struct ListChannelsResponse { } /// Returns payment details for a given payment_id. /// 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 GetPaymentDetailsRequest { @@ -386,6 +444,8 @@ pub struct GetPaymentDetailsRequest { } /// The response `content` for the `GetPaymentDetails` 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 GetPaymentDetailsResponse { @@ -396,6 +456,8 @@ pub struct GetPaymentDetailsResponse { } /// Retrieves list of all payments. /// 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 ListPaymentsRequest { @@ -410,6 +472,8 @@ pub struct ListPaymentsRequest { } /// The response `content` for the `ListPayments` 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 ListPaymentsResponse { @@ -434,6 +498,8 @@ pub struct ListPaymentsResponse { } /// Retrieves list of all forwarded payments. /// 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 ListForwardedPaymentsRequest { @@ -448,6 +514,8 @@ pub struct ListForwardedPaymentsRequest { } /// The response `content` for the `ListForwardedPayments` 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 ListForwardedPaymentsResponse { @@ -472,11 +540,15 @@ pub struct ListForwardedPaymentsResponse { } /// Retrieves an overview of all known balances. /// 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 GetBalancesRequest {} /// The response `content` for the `GetBalances` 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 GetBalancesResponse { diff --git a/ldk-server/ldk-server-protos/src/error.rs b/ldk-server/ldk-server-protos/src/error.rs index bd76d36da..4ea5d8e11 100644 --- a/ldk-server/ldk-server-protos/src/error.rs +++ b/ldk-server/ldk-server-protos/src/error.rs @@ -1,5 +1,7 @@ /// When HttpStatusCode is not ok (200), the response `content` contains a serialized `ErrorResponse` /// with the relevant ErrorCode and `message` +#[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 ErrorResponse { @@ -17,6 +19,8 @@ pub struct ErrorResponse { #[prost(enumeration = "ErrorCode", tag = "2")] pub error_code: i32, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum ErrorCode { diff --git a/ldk-server/ldk-server-protos/src/events.rs b/ldk-server/ldk-server-protos/src/events.rs index a9e9000aa..0fa5f09d8 100644 --- a/ldk-server/ldk-server-protos/src/events.rs +++ b/ldk-server/ldk-server-protos/src/events.rs @@ -1,4 +1,6 @@ /// EventEnvelope wraps different event types in a single message to be used by EventPublisher. +#[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 EventEnvelope { @@ -7,6 +9,8 @@ pub struct EventEnvelope { } /// Nested message and enum types in `EventEnvelope`. pub mod event_envelope { + #[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::Oneof)] pub enum Event { @@ -21,6 +25,8 @@ pub mod event_envelope { } } /// PaymentReceived indicates a payment has been received. +#[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 PaymentReceived { @@ -29,6 +35,8 @@ pub struct PaymentReceived { pub payment: ::core::option::Option, } /// PaymentSuccessful indicates a sent payment was successful. +#[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 PaymentSuccessful { @@ -37,6 +45,8 @@ pub struct PaymentSuccessful { pub payment: ::core::option::Option, } /// PaymentFailed indicates a sent payment has failed. +#[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 PaymentFailed { @@ -45,6 +55,8 @@ pub struct PaymentFailed { pub payment: ::core::option::Option, } /// PaymentForwarded indicates a payment was forwarded through the node. +#[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 PaymentForwarded { diff --git a/ldk-server/ldk-server-protos/src/types.rs b/ldk-server/ldk-server-protos/src/types.rs index 3251bc452..a92ab57c4 100644 --- a/ldk-server/ldk-server-protos/src/types.rs +++ b/ldk-server/ldk-server-protos/src/types.rs @@ -1,5 +1,7 @@ /// Represents a payment. /// 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 Payment { @@ -28,6 +30,8 @@ pub struct Payment { #[prost(uint64, tag = "6")] pub latest_update_timestamp: u64, } +#[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 PaymentKind { @@ -36,6 +40,8 @@ pub struct PaymentKind { } /// Nested message and enum types in `PaymentKind`. pub mod payment_kind { + #[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::Oneof)] pub enum Kind { @@ -54,6 +60,8 @@ pub mod payment_kind { } } /// Represents an on-chain payment. +#[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 Onchain { @@ -64,6 +72,8 @@ pub struct Onchain { #[prost(message, optional, tag = "2")] pub status: ::core::option::Option, } +#[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 ConfirmationStatus { @@ -72,6 +82,8 @@ pub struct ConfirmationStatus { } /// Nested message and enum types in `ConfirmationStatus`. pub mod confirmation_status { + #[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::Oneof)] pub enum Status { @@ -82,6 +94,8 @@ pub mod confirmation_status { } } /// The on-chain transaction is confirmed in the best chain. +#[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 Confirmed { @@ -96,10 +110,14 @@ pub struct Confirmed { pub timestamp: u64, } /// The on-chain transaction is unconfirmed. +#[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 Unconfirmed {} /// Represents a BOLT 11 payment. +#[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 Bolt11 { @@ -114,6 +132,8 @@ pub struct Bolt11 { pub secret: ::core::option::Option<::prost::bytes::Bytes>, } /// Represents a BOLT 11 payment intended to open an LSPS 2 just-in-time channel. +#[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 Bolt11Jit { @@ -142,6 +162,8 @@ pub struct Bolt11Jit { pub counterparty_skimmed_fee_msat: ::core::option::Option, } /// Represents a BOLT 12 ‘offer’ payment, i.e., a payment for an Offer. +#[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 Bolt12Offer { @@ -169,6 +191,8 @@ pub struct Bolt12Offer { pub quantity: ::core::option::Option, } /// Represents a BOLT 12 ‘refund’ payment, i.e., a payment for a Refund. +#[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 Bolt12Refund { @@ -193,6 +217,8 @@ pub struct Bolt12Refund { pub quantity: ::core::option::Option, } /// Represents a spontaneous (“keysend”) payment. +#[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 Spontaneous { @@ -207,6 +233,8 @@ pub struct Spontaneous { /// See \[`LdkChannelConfig::accept_underpaying_htlcs`\] for more information. /// /// \[`LdkChannelConfig::accept_underpaying_htlcs`\]: lightning::util::config::ChannelConfig::accept_underpaying_htlcs +#[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 LspFeeLimits { @@ -221,6 +249,8 @@ pub struct LspFeeLimits { } /// A forwarded payment through our node. /// 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 ForwardedPayment { @@ -271,6 +301,8 @@ pub struct ForwardedPayment { #[prost(uint64, optional, tag = "8")] pub outbound_amount_forwarded_msat: ::core::option::Option, } +#[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 Channel { @@ -403,6 +435,8 @@ pub struct Channel { } /// ChannelConfig represents the configuration settings for a channel in a Lightning Network node. /// 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 ChannelConfig { @@ -446,6 +480,8 @@ pub mod channel_config { /// and fees on commitment transaction(s) broadcasted by our counterparty in excess of /// our own fee estimate. /// 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::Oneof)] pub enum MaxDustHtlcExposure { @@ -460,6 +496,8 @@ pub mod channel_config { } } /// Represent a transaction outpoint. +#[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 OutPoint { @@ -470,6 +508,8 @@ pub struct OutPoint { #[prost(uint32, tag = "2")] pub vout: u32, } +#[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 BestBlock { @@ -481,6 +521,8 @@ pub struct BestBlock { pub height: u32, } /// Details about the status of a known Lightning balance. +#[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 LightningBalance { @@ -489,6 +531,8 @@ pub struct LightningBalance { } /// Nested message and enum types in `LightningBalance`. pub mod lightning_balance { + #[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::Oneof)] pub enum BalanceType { @@ -509,6 +553,8 @@ pub mod lightning_balance { /// The channel is not yet closed (or the commitment or closing transaction has not yet appeared in a block). /// The given balance is claimable (less on-chain fees) if the channel is force-closed now. /// 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 ClaimableOnChannelClose { @@ -564,6 +610,8 @@ pub struct ClaimableOnChannelClose { } /// The channel has been closed, and the given balance is ours but awaiting confirmations until we consider it spendable. /// 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 ClaimableAwaitingConfirmations { @@ -588,6 +636,8 @@ pub struct ClaimableAwaitingConfirmations { /// Once the spending transaction confirms, before it has reached enough confirmations to be considered safe from chain /// reorganizations, the balance will instead be provided via `LightningBalance::ClaimableAwaitingConfirmations`. /// 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 ContentiousClaimable { @@ -614,6 +664,8 @@ pub struct ContentiousClaimable { /// HTLCs which we sent to our counterparty which are claimable after a timeout (less on-chain fees) if the counterparty /// does not know the preimage for the HTLCs. These are somewhat likely to be claimed by our counterparty before we do. /// 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 MaybeTimeoutClaimableHtlc { @@ -641,6 +693,8 @@ pub struct MaybeTimeoutClaimableHtlc { /// This will only be claimable if we receive the preimage from the node to which we forwarded this HTLC before the /// timeout. /// 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 MaybePreimageClaimableHtlc { @@ -667,6 +721,8 @@ pub struct MaybePreimageClaimableHtlc { /// Thus, we’re able to claim all outputs in the commitment transaction, one of which has the following amount. /// /// 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 CounterpartyRevokedOutputClaimable { @@ -681,6 +737,8 @@ pub struct CounterpartyRevokedOutputClaimable { pub amount_satoshis: u64, } /// Details about the status of a known balance currently being swept to our on-chain wallet. +#[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 PendingSweepBalance { @@ -689,6 +747,8 @@ pub struct PendingSweepBalance { } /// Nested message and enum types in `PendingSweepBalance`. pub mod pending_sweep_balance { + #[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::Oneof)] pub enum BalanceType { @@ -702,6 +762,8 @@ pub mod pending_sweep_balance { } /// The spendable output is about to be swept, but a spending transaction has yet to be generated and broadcast. /// 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 PendingBroadcast { @@ -714,6 +776,8 @@ pub struct PendingBroadcast { } /// A spending transaction has been generated and broadcast and is awaiting confirmation on-chain. /// 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 BroadcastAwaitingConfirmation { @@ -734,6 +798,8 @@ pub struct BroadcastAwaitingConfirmation { /// /// It will be considered irrevocably confirmed after reaching `ANTI_REORG_DELAY`. /// 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 AwaitingThresholdConfirmations { @@ -754,6 +820,8 @@ pub struct AwaitingThresholdConfirmations { pub amount_satoshis: u64, } /// Token used to determine start of next page in paginated APIs. +#[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 PageToken { @@ -762,6 +830,8 @@ pub struct PageToken { #[prost(int64, tag = "2")] pub index: i64, } +#[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 Bolt11InvoiceDescription { @@ -770,6 +840,8 @@ pub struct Bolt11InvoiceDescription { } /// Nested message and enum types in `Bolt11InvoiceDescription`. pub mod bolt11_invoice_description { + #[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::Oneof)] pub enum Kind { @@ -781,6 +853,8 @@ pub mod bolt11_invoice_description { } /// Configuration options for payment routing and pathfinding. /// See for more details on each field. +#[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 RouteParametersConfig { @@ -803,6 +877,8 @@ pub struct RouteParametersConfig { pub max_channel_saturation_power_of_half: u32, } /// Represents the direction of a payment. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum PaymentDirection { @@ -832,6 +908,8 @@ impl PaymentDirection { } } /// Represents the current status of a payment. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum PaymentStatus { From 23f79ef0873b06382e0e2a94fa37cd5c5b0636b4 Mon Sep 17 00:00:00 2001 From: elnosh Date: Sat, 13 Dec 2025 14:18:52 -0500 Subject: [PATCH 173/203] Make expiry_secs optional for bolt11-receive --- ldk-server/ldk-server-cli/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index f9efe39f8..6f5ab3b80 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -23,6 +23,7 @@ use std::fmt::Debug; const DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA: u32 = 1008; const DEFAULT_MAX_PATH_COUNT: u32 = 10; const DEFAULT_MAX_CHANNEL_SATURATION_POWER_OF_HALF: u32 = 2; +const DEFAULT_EXPIRY_SECS: u32 = 86_400; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -55,7 +56,7 @@ enum Commands { #[arg(long)] description_hash: Option, #[arg(short, long)] - expiry_secs: u32, + expiry_secs: Option, #[arg(long)] amount_msat: Option, }, @@ -236,6 +237,7 @@ async fn main() { (None, None) => None, }; + let expiry_secs = expiry_secs.unwrap_or(DEFAULT_EXPIRY_SECS); let request = Bolt11ReceiveRequest { description: invoice_description, expiry_secs, amount_msat }; From 6fac8462003c381aab785ad5735fc7cc98cec30f Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Wed, 17 Dec 2025 13:33:07 +0100 Subject: [PATCH 174/203] Add licensing headers to all Rust files .. we just add the usual licensing headers. --- ldk-server/ldk-server-cli/src/main.rs | 9 +++++++++ ldk-server/ldk-server-client/src/client.rs | 9 +++++++++ ldk-server/ldk-server-client/src/error.rs | 9 +++++++++ ldk-server/ldk-server-client/src/lib.rs | 9 +++++++++ ldk-server/ldk-server-protos/build.rs | 9 +++++++++ ldk-server/ldk-server-protos/src/api.rs | 9 +++++++++ ldk-server/ldk-server-protos/src/endpoints.rs | 9 +++++++++ ldk-server/ldk-server-protos/src/error.rs | 9 +++++++++ ldk-server/ldk-server-protos/src/events.rs | 9 +++++++++ ldk-server/ldk-server-protos/src/lib.rs | 9 +++++++++ ldk-server/ldk-server-protos/src/types.rs | 9 +++++++++ ldk-server/ldk-server/src/api/bolt11_receive.rs | 9 +++++++++ ldk-server/ldk-server/src/api/bolt11_send.rs | 9 +++++++++ ldk-server/ldk-server/src/api/bolt12_receive.rs | 9 +++++++++ ldk-server/ldk-server/src/api/bolt12_send.rs | 9 +++++++++ ldk-server/ldk-server/src/api/close_channel.rs | 9 +++++++++ ldk-server/ldk-server/src/api/error.rs | 9 +++++++++ ldk-server/ldk-server/src/api/get_balances.rs | 9 +++++++++ ldk-server/ldk-server/src/api/get_node_info.rs | 9 +++++++++ ldk-server/ldk-server/src/api/get_payment_details.rs | 9 +++++++++ ldk-server/ldk-server/src/api/list_channels.rs | 9 +++++++++ ldk-server/ldk-server/src/api/list_forwarded_payments.rs | 9 +++++++++ ldk-server/ldk-server/src/api/list_payments.rs | 9 +++++++++ ldk-server/ldk-server/src/api/mod.rs | 9 +++++++++ ldk-server/ldk-server/src/api/onchain_receive.rs | 9 +++++++++ ldk-server/ldk-server/src/api/onchain_send.rs | 9 +++++++++ ldk-server/ldk-server/src/api/open_channel.rs | 9 +++++++++ ldk-server/ldk-server/src/api/splice_channel.rs | 9 +++++++++ ldk-server/ldk-server/src/api/update_channel_config.rs | 9 +++++++++ ldk-server/ldk-server/src/io/events/event_publisher.rs | 9 +++++++++ ldk-server/ldk-server/src/io/events/mod.rs | 9 +++++++++ ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs | 9 +++++++++ ldk-server/ldk-server/src/io/mod.rs | 9 +++++++++ ldk-server/ldk-server/src/io/persist/mod.rs | 9 +++++++++ .../ldk-server/src/io/persist/paginated_kv_store.rs | 9 +++++++++ ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs | 9 +++++++++ ldk-server/ldk-server/src/io/utils.rs | 9 +++++++++ ldk-server/ldk-server/src/main.rs | 9 +++++++++ ldk-server/ldk-server/src/service.rs | 9 +++++++++ ldk-server/ldk-server/src/util/config.rs | 9 +++++++++ ldk-server/ldk-server/src/util/logger.rs | 9 +++++++++ ldk-server/ldk-server/src/util/mod.rs | 9 +++++++++ ldk-server/ldk-server/src/util/proto_adapter.rs | 9 +++++++++ 43 files changed, 387 insertions(+) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index cac4697cb..304f3c887 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -1,3 +1,12 @@ +// 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 clap::{Parser, Subcommand}; use ldk_server_client::client::LdkServerClient; use ldk_server_client::error::LdkServerError; diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index 7fbe5dfa6..99831517d 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -1,3 +1,12 @@ +// 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 prost::Message; use crate::error::LdkServerError; diff --git a/ldk-server/ldk-server-client/src/error.rs b/ldk-server/ldk-server-client/src/error.rs index 8dc16f665..67cba37d7 100644 --- a/ldk-server/ldk-server-client/src/error.rs +++ b/ldk-server/ldk-server-client/src/error.rs @@ -1,3 +1,12 @@ +// 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 std::fmt; /// Represents an error returned by the LDK server. diff --git a/ldk-server/ldk-server-client/src/lib.rs b/ldk-server/ldk-server-client/src/lib.rs index 19540ee24..098c7087f 100644 --- a/ldk-server/ldk-server-client/src/lib.rs +++ b/ldk-server/ldk-server-client/src/lib.rs @@ -1,3 +1,12 @@ +// 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. + //! Client-side library to interact with LDK Server. #![deny(rustdoc::broken_intra_doc_links)] diff --git a/ldk-server/ldk-server-protos/build.rs b/ldk-server/ldk-server-protos/build.rs index 5ffcf7acb..32b9f6b01 100644 --- a/ldk-server/ldk-server-protos/build.rs +++ b/ldk-server/ldk-server-protos/build.rs @@ -1,3 +1,12 @@ +// 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. + #[cfg(genproto)] extern crate prost_build; diff --git a/ldk-server/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index d146a7e93..439a403de 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/ldk-server-protos/src/api.rs @@ -1,3 +1,12 @@ +// 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. + /// Retrieve the latest node info like `node_id`, `current_best_block` etc. /// See more: /// - diff --git a/ldk-server/ldk-server-protos/src/endpoints.rs b/ldk-server/ldk-server-protos/src/endpoints.rs index d5990187c..c7ed1c26a 100644 --- a/ldk-server/ldk-server-protos/src/endpoints.rs +++ b/ldk-server/ldk-server-protos/src/endpoints.rs @@ -1,3 +1,12 @@ +// 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. + pub const GET_NODE_INFO_PATH: &str = "GetNodeInfo"; pub const GET_BALANCES_PATH: &str = "GetBalances"; pub const ONCHAIN_RECEIVE_PATH: &str = "OnchainReceive"; diff --git a/ldk-server/ldk-server-protos/src/error.rs b/ldk-server/ldk-server-protos/src/error.rs index 4ea5d8e11..41e73ee42 100644 --- a/ldk-server/ldk-server-protos/src/error.rs +++ b/ldk-server/ldk-server-protos/src/error.rs @@ -1,3 +1,12 @@ +// 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. + /// When HttpStatusCode is not ok (200), the response `content` contains a serialized `ErrorResponse` /// with the relevant ErrorCode and `message` #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] diff --git a/ldk-server/ldk-server-protos/src/events.rs b/ldk-server/ldk-server-protos/src/events.rs index 0fa5f09d8..08a605bed 100644 --- a/ldk-server/ldk-server-protos/src/events.rs +++ b/ldk-server/ldk-server-protos/src/events.rs @@ -1,3 +1,12 @@ +// 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. + /// EventEnvelope wraps different event types in a single message to be used by EventPublisher. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] diff --git a/ldk-server/ldk-server-protos/src/lib.rs b/ldk-server/ldk-server-protos/src/lib.rs index 1999d0609..24a735256 100644 --- a/ldk-server/ldk-server-protos/src/lib.rs +++ b/ldk-server/ldk-server-protos/src/lib.rs @@ -1,3 +1,12 @@ +// 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. + pub mod api; pub mod endpoints; pub mod error; diff --git a/ldk-server/ldk-server-protos/src/types.rs b/ldk-server/ldk-server-protos/src/types.rs index a92ab57c4..238f4b5d1 100644 --- a/ldk-server/ldk-server-protos/src/types.rs +++ b/ldk-server/ldk-server-protos/src/types.rs @@ -1,3 +1,12 @@ +// 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. + /// Represents a payment. /// See more: #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] diff --git a/ldk-server/ldk-server/src/api/bolt11_receive.rs b/ldk-server/ldk-server/src/api/bolt11_receive.rs index 024404b87..ea1d99a28 100644 --- a/ldk-server/ldk-server/src/api/bolt11_receive.rs +++ b/ldk-server/ldk-server/src/api/bolt11_receive.rs @@ -1,3 +1,12 @@ +// 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 crate::util::proto_adapter::proto_to_bolt11_description; diff --git a/ldk-server/ldk-server/src/api/bolt11_send.rs b/ldk-server/ldk-server/src/api/bolt11_send.rs index f5204c82c..d3fbf1b9d 100644 --- a/ldk-server/ldk-server/src/api/bolt11_send.rs +++ b/ldk-server/ldk-server/src/api/bolt11_send.rs @@ -1,3 +1,12 @@ +// 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::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; diff --git a/ldk-server/ldk-server/src/api/bolt12_receive.rs b/ldk-server/ldk-server/src/api/bolt12_receive.rs index 9749baff4..4f33d5ef2 100644 --- a/ldk-server/ldk-server/src/api/bolt12_receive.rs +++ b/ldk-server/ldk-server/src/api/bolt12_receive.rs @@ -1,3 +1,12 @@ +// 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_server_protos::api::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; diff --git a/ldk-server/ldk-server/src/api/bolt12_send.rs b/ldk-server/ldk-server/src/api/bolt12_send.rs index 908107abf..2c69831f5 100644 --- a/ldk-server/ldk-server/src/api/bolt12_send.rs +++ b/ldk-server/ldk-server/src/api/bolt12_send.rs @@ -1,3 +1,12 @@ +// 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::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; diff --git a/ldk-server/ldk-server/src/api/close_channel.rs b/ldk-server/ldk-server/src/api/close_channel.rs index 268cb6de7..a55b7134a 100644 --- a/ldk-server/ldk-server/src/api/close_channel.rs +++ b/ldk-server/ldk-server/src/api/close_channel.rs @@ -1,3 +1,12 @@ +// 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::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; diff --git a/ldk-server/ldk-server/src/api/error.rs b/ldk-server/ldk-server/src/api/error.rs index c9103da08..304a8aa13 100644 --- a/ldk-server/ldk-server/src/api/error.rs +++ b/ldk-server/ldk-server/src/api/error.rs @@ -1,3 +1,12 @@ +// 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 ldk_node::NodeError; use std::fmt; diff --git a/ldk-server/ldk-server/src/api/get_balances.rs b/ldk-server/ldk-server/src/api/get_balances.rs index dce81ef14..dbaa3f55a 100644 --- a/ldk-server/ldk-server/src/api/get_balances.rs +++ b/ldk-server/ldk-server/src/api/get_balances.rs @@ -1,3 +1,12 @@ +// 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 crate::util::proto_adapter::{lightning_balance_to_proto, pending_sweep_balance_to_proto}; diff --git a/ldk-server/ldk-server/src/api/get_node_info.rs b/ldk-server/ldk-server/src/api/get_node_info.rs index 5763bea9d..61cdd1fa2 100644 --- a/ldk-server/ldk-server/src/api/get_node_info.rs +++ b/ldk-server/ldk-server/src/api/get_node_info.rs @@ -1,3 +1,12 @@ +// 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_server_protos::api::{GetNodeInfoRequest, GetNodeInfoResponse}; diff --git a/ldk-server/ldk-server/src/api/get_payment_details.rs b/ldk-server/ldk-server/src/api/get_payment_details.rs index d0b6fc22d..afb74691c 100644 --- a/ldk-server/ldk-server/src/api/get_payment_details.rs +++ b/ldk-server/ldk-server/src/api/get_payment_details.rs @@ -1,3 +1,12 @@ +// 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::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; diff --git a/ldk-server/ldk-server/src/api/list_channels.rs b/ldk-server/ldk-server/src/api/list_channels.rs index 046fad645..aa8302579 100644 --- a/ldk-server/ldk-server/src/api/list_channels.rs +++ b/ldk-server/ldk-server/src/api/list_channels.rs @@ -1,3 +1,12 @@ +// 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 crate::util::proto_adapter::channel_to_proto; diff --git a/ldk-server/ldk-server/src/api/list_forwarded_payments.rs b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs index b11996194..989e8491e 100644 --- a/ldk-server/ldk-server/src/api/list_forwarded_payments.rs +++ b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs @@ -1,3 +1,12 @@ +// 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::api::error::LdkServerErrorCode::InternalServerError; use crate::io::persist::{ diff --git a/ldk-server/ldk-server/src/api/list_payments.rs b/ldk-server/ldk-server/src/api/list_payments.rs index 2b6f8ff1f..0077bdab4 100644 --- a/ldk-server/ldk-server/src/api/list_payments.rs +++ b/ldk-server/ldk-server/src/api/list_payments.rs @@ -1,3 +1,12 @@ +// 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::api::error::LdkServerErrorCode::InternalServerError; use crate::io::persist::{ diff --git a/ldk-server/ldk-server/src/api/mod.rs b/ldk-server/ldk-server/src/api/mod.rs index 487ab1e9e..b34fef55e 100644 --- a/ldk-server/ldk-server/src/api/mod.rs +++ b/ldk-server/ldk-server/src/api/mod.rs @@ -1,3 +1,12 @@ +// 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::api::error::LdkServerErrorCode::InvalidRequestError; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; diff --git a/ldk-server/ldk-server/src/api/onchain_receive.rs b/ldk-server/ldk-server/src/api/onchain_receive.rs index 3196801f7..913c6a8eb 100644 --- a/ldk-server/ldk-server/src/api/onchain_receive.rs +++ b/ldk-server/ldk-server/src/api/onchain_receive.rs @@ -1,3 +1,12 @@ +// 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_server_protos::api::{OnchainReceiveRequest, OnchainReceiveResponse}; diff --git a/ldk-server/ldk-server/src/api/onchain_send.rs b/ldk-server/ldk-server/src/api/onchain_send.rs index b84c671dd..c5272a9ad 100644 --- a/ldk-server/ldk-server/src/api/onchain_send.rs +++ b/ldk-server/ldk-server/src/api/onchain_send.rs @@ -1,3 +1,12 @@ +// 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::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; diff --git a/ldk-server/ldk-server/src/api/open_channel.rs b/ldk-server/ldk-server/src/api/open_channel.rs index 02fcfed78..53d6ac131 100644 --- a/ldk-server/ldk-server/src/api/open_channel.rs +++ b/ldk-server/ldk-server/src/api/open_channel.rs @@ -1,3 +1,12 @@ +// 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::build_channel_config_from_proto; use crate::api::error::LdkServerError; use crate::service::Context; diff --git a/ldk-server/ldk-server/src/api/splice_channel.rs b/ldk-server/ldk-server/src/api/splice_channel.rs index cab921077..3710e72d2 100644 --- a/ldk-server/ldk-server/src/api/splice_channel.rs +++ b/ldk-server/ldk-server/src/api/splice_channel.rs @@ -1,3 +1,12 @@ +// 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::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; diff --git a/ldk-server/ldk-server/src/api/update_channel_config.rs b/ldk-server/ldk-server/src/api/update_channel_config.rs index 2a8954103..a80ed739f 100644 --- a/ldk-server/ldk-server/src/api/update_channel_config.rs +++ b/ldk-server/ldk-server/src/api/update_channel_config.rs @@ -1,3 +1,12 @@ +// 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::build_channel_config_from_proto; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::{InvalidRequestError, LightningError}; diff --git a/ldk-server/ldk-server/src/io/events/event_publisher.rs b/ldk-server/ldk-server/src/io/events/event_publisher.rs index f333bb310..7a9041183 100644 --- a/ldk-server/ldk-server/src/io/events/event_publisher.rs +++ b/ldk-server/ldk-server/src/io/events/event_publisher.rs @@ -1,3 +1,12 @@ +// 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 async_trait::async_trait; use ldk_server_protos::events::EventEnvelope; diff --git a/ldk-server/ldk-server/src/io/events/mod.rs b/ldk-server/ldk-server/src/io/events/mod.rs index d15753293..f944b7e30 100644 --- a/ldk-server/ldk-server/src/io/events/mod.rs +++ b/ldk-server/ldk-server/src/io/events/mod.rs @@ -1,3 +1,12 @@ +// 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. + pub(crate) mod event_publisher; #[cfg(feature = "events-rabbitmq")] diff --git a/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs b/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs index 481f6b063..08b0e4b10 100644 --- a/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs +++ b/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs @@ -1,3 +1,12 @@ +// 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::api::error::LdkServerErrorCode::InternalServerError; use crate::io::events::event_publisher::EventPublisher; diff --git a/ldk-server/ldk-server/src/io/mod.rs b/ldk-server/ldk-server/src/io/mod.rs index 8b022008e..ab1df5f66 100644 --- a/ldk-server/ldk-server/src/io/mod.rs +++ b/ldk-server/ldk-server/src/io/mod.rs @@ -1,3 +1,12 @@ +// 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. + pub(crate) mod events; pub(crate) mod persist; pub(crate) mod utils; diff --git a/ldk-server/ldk-server/src/io/persist/mod.rs b/ldk-server/ldk-server/src/io/persist/mod.rs index da342acc4..6c01795bc 100644 --- a/ldk-server/ldk-server/src/io/persist/mod.rs +++ b/ldk-server/ldk-server/src/io/persist/mod.rs @@ -1,3 +1,12 @@ +// 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. + pub(crate) mod paginated_kv_store; pub(crate) mod sqlite_store; diff --git a/ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs b/ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs index d036c2ef7..ff381b1bd 100644 --- a/ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs +++ b/ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs @@ -1,3 +1,12 @@ +// 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 std::io; /// Provides an interface that allows storage and retrieval of persisted values that are associated diff --git a/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs b/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs index 9e53db3a5..c473cb54e 100644 --- a/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs +++ b/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs @@ -1,3 +1,12 @@ +// 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::io::persist::paginated_kv_store::{ListResponse, PaginatedKVStore}; use crate::io::utils::check_namespace_key_validity; use ldk_node::lightning::types::string::PrintableString; diff --git a/ldk-server/ldk-server/src/io/utils.rs b/ldk-server/ldk-server/src/io/utils.rs index b9bfe59ab..4b81d8a2c 100644 --- a/ldk-server/ldk-server/src/io/utils.rs +++ b/ldk-server/ldk-server/src/io/utils.rs @@ -1,3 +1,12 @@ +// 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 ldk_node::lightning::types::string::PrintableString; use ldk_node::lightning::util::persist::{ KVSTORE_NAMESPACE_KEY_ALPHABET, KVSTORE_NAMESPACE_KEY_MAX_LEN, diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 72f5fb129..e16d5f0cf 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -1,3 +1,12 @@ +// 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. + mod api; mod io; mod service; diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index b1144a7da..6048a106a 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -1,3 +1,12 @@ +// 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 ldk_node::Node; use http_body_util::{BodyExt, Full, Limited}; diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index b2d896c0d..79fda3585 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -1,3 +1,12 @@ +// 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 ldk_node::bitcoin::Network; use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_node::lightning::routing::gossip::NodeAlias; diff --git a/ldk-server/ldk-server/src/util/logger.rs b/ldk-server/ldk-server/src/util/logger.rs index 66a236ca3..170f3622f 100644 --- a/ldk-server/ldk-server/src/util/logger.rs +++ b/ldk-server/ldk-server/src/util/logger.rs @@ -1,3 +1,12 @@ +// 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 log::{Level, LevelFilter, Log, Metadata, Record}; use std::fs::{self, File, OpenOptions}; use std::io::{self, BufWriter, Write}; diff --git a/ldk-server/ldk-server/src/util/mod.rs b/ldk-server/ldk-server/src/util/mod.rs index 2bcbee65e..8bcf1c114 100644 --- a/ldk-server/ldk-server/src/util/mod.rs +++ b/ldk-server/ldk-server/src/util/mod.rs @@ -1,3 +1,12 @@ +// 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. + pub(crate) mod config; pub(crate) mod logger; pub(crate) mod proto_adapter; diff --git a/ldk-server/ldk-server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs index c645242d9..360d3944f 100644 --- a/ldk-server/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -1,3 +1,12 @@ +// 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::api::error::LdkServerErrorCode::{ AuthError, InternalServerError, InvalidRequestError, LightningError, From c7fe1d0106beab88f93f669319bf5d8d5b41e3c7 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Wed, 10 Dec 2025 19:13:54 -0600 Subject: [PATCH 175/203] Implement proper pagination for list-payments cli --- ldk-server/ldk-server-cli/src/main.rs | 70 +++++++++++++++++++------- ldk-server/ldk-server-cli/src/types.rs | 41 +++++++++++++++ 2 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 ldk-server/ldk-server-cli/src/types.rs diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 304f3c887..019739c75 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -24,10 +24,13 @@ use ldk_server_client::ldk_server_protos::api::{ SpliceOutResponse, UpdateChannelConfigRequest, UpdateChannelConfigResponse, }; use ldk_server_client::ldk_server_protos::types::{ - bolt11_invoice_description, Bolt11InvoiceDescription, ChannelConfig, PageToken, Payment, + bolt11_invoice_description, Bolt11InvoiceDescription, ChannelConfig, PageToken, RouteParametersConfig, }; use serde::Serialize; +use types::CliListPaymentsResponse; + +mod types; // Having these default values as constants in the Proto file and // importing/reusing them here might be better, but Proto3 removed @@ -178,9 +181,12 @@ enum Commands { ListPayments { #[arg(short, long)] #[arg( - help = "Minimum number of payments to return. If not provided, only the first page of the paginated list is returned." + help = "Fetch at least this many payments by iterating through multiple pages. Returns combined results with the last page token. If not provided, returns only a single page." )] number_of_payments: Option, + #[arg(long)] + #[arg(help = "Page token to continue from a previous page (format: token:index)")] + page_token: Option, }, UpdateChannelConfig { #[arg(short, long)] @@ -416,12 +422,15 @@ async fn main() { client.list_channels(ListChannelsRequest {}).await, ); }, - Commands::ListPayments { number_of_payments } => { - handle_response_result::<_, ListPaymentsResponse>( - list_n_payments(client, number_of_payments) - .await - // todo: handle pagination properly - .map(|payments| ListPaymentsResponse { payments, next_page_token: None }), + Commands::ListPayments { number_of_payments, page_token } => { + let page_token = if let Some(token_str) = page_token { + Some(parse_page_token(&token_str).unwrap_or_else(|e| handle_error(e))) + } else { + None + }; + + handle_response_result::<_, CliListPaymentsResponse>( + handle_list_payments(client, number_of_payments, page_token).await, ); }, Commands::UpdateChannelConfig { @@ -475,24 +484,37 @@ fn build_open_channel_config( }) } +async fn handle_list_payments( + client: LdkServerClient, number_of_payments: Option, initial_page_token: Option, +) -> Result { + if let Some(count) = number_of_payments { + list_n_payments(client, count, initial_page_token).await + } else { + // Fetch single page + client.list_payments(ListPaymentsRequest { page_token: initial_page_token }).await + } +} + async fn list_n_payments( - client: LdkServerClient, number_of_payments: Option, -) -> Result, LdkServerError> { - let mut payments = Vec::new(); - let mut page_token: Option = None; - // If no count is specified, just list the first page. - let target_count = number_of_payments.unwrap_or(0); + client: LdkServerClient, target_count: u64, initial_page_token: Option, +) -> Result { + let mut payments = Vec::with_capacity(target_count as usize); + let mut page_token = initial_page_token; + let mut next_page_token; loop { let response = client.list_payments(ListPaymentsRequest { page_token }).await?; payments.extend(response.payments); - if payments.len() >= target_count as usize || response.next_page_token.is_none() { + next_page_token = response.next_page_token; + + if payments.len() >= target_count as usize || next_page_token.is_none() { break; } - page_token = response.next_page_token; + page_token = next_page_token; } - Ok(payments) + + Ok(ListPaymentsResponse { payments, next_page_token }) } fn handle_response_result(response: Result) @@ -517,6 +539,20 @@ where } } +fn parse_page_token(token_str: &str) -> Result { + let parts: Vec<&str> = token_str.split(':').collect(); + if parts.len() != 2 { + return Err(LdkServerError::new( + InternalError, + "Page token must be in format 'token:index'".to_string(), + )); + } + let index = parts[1] + .parse::() + .map_err(|_| LdkServerError::new(InternalError, "Invalid page token index".to_string()))?; + Ok(PageToken { token: parts[0].to_string(), index }) +} + fn handle_error(e: LdkServerError) -> ! { let error_type = match e.error_code { InvalidRequestError => "Invalid Request", diff --git a/ldk-server/ldk-server-cli/src/types.rs b/ldk-server/ldk-server-cli/src/types.rs new file mode 100644 index 000000000..a482f794d --- /dev/null +++ b/ldk-server/ldk-server-cli/src/types.rs @@ -0,0 +1,41 @@ +// 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. + +//! CLI-specific type wrappers for API responses. +//! +//! This file contains wrapper types that customize the serialization format +//! of API responses for CLI output. These wrappers ensure that the CLI's output +//! format matches what users expect and what the CLI can parse back as input. + +use ldk_server_client::ldk_server_protos::api::ListPaymentsResponse; +use ldk_server_client::ldk_server_protos::types::{PageToken, Payment}; +use serde::Serialize; + +/// CLI-specific wrapper for ListPaymentsResponse that formats the page token +/// as "token:idx" instead of a JSON object. +#[derive(Debug, Clone, Serialize)] +pub struct CliListPaymentsResponse { + /// List of payments. + pub payments: Vec, + /// Next page token formatted as "token:idx", or None if no more pages. + #[serde(skip_serializing_if = "Option::is_none")] + pub next_page_token: Option, +} + +impl From for CliListPaymentsResponse { + fn from(response: ListPaymentsResponse) -> Self { + let next_page_token = response.next_page_token.map(format_page_token); + + CliListPaymentsResponse { payments: response.payments, next_page_token } + } +} + +fn format_page_token(token: PageToken) -> String { + format!("{}:{}", token.token, token.index) +} From fe11463a9da7b797bd0cba101f66f8881630e721 Mon Sep 17 00:00:00 2001 From: Leo Nash Date: Sat, 20 Dec 2025 00:37:57 +0000 Subject: [PATCH 176/203] Do not use buffered writers to write lines to the log file When tailing the log file, we do not expect any buffering as the lines get written. --- ldk-server/ldk-server/src/util/logger.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ldk-server/ldk-server/src/util/logger.rs b/ldk-server/ldk-server/src/util/logger.rs index 170f3622f..add0d24fa 100644 --- a/ldk-server/ldk-server/src/util/logger.rs +++ b/ldk-server/ldk-server/src/util/logger.rs @@ -9,7 +9,7 @@ use log::{Level, LevelFilter, Log, Metadata, Record}; use std::fs::{self, File, OpenOptions}; -use std::io::{self, BufWriter, Write}; +use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; @@ -29,7 +29,7 @@ pub struct ServerLogger { /// The maximum log level to display level: LevelFilter, /// The file to write logs to, protected by a mutex for thread-safe access - file: Mutex>, + file: Mutex, /// Path to the log file for reopening on SIGHUP log_file_path: PathBuf, } @@ -155,9 +155,8 @@ fn format_level(level: Level) -> &'static str { } } -fn open_log_file(log_file_path: &Path) -> Result, io::Error> { - let file = OpenOptions::new().create(true).append(true).open(log_file_path)?; - Ok(BufWriter::new(file)) +fn open_log_file(log_file_path: &Path) -> Result { + OpenOptions::new().create(true).append(true).open(log_file_path) } /// Wrapper to allow Arc to implement Log trait From b3b861fe21c3dc9305e7c695cfbd45fa3e47bff7 Mon Sep 17 00:00:00 2001 From: Leo Nash Date: Sat, 20 Dec 2025 01:26:34 +0000 Subject: [PATCH 177/203] Add electrum chain source --- ldk-server/ldk-server/ldk-server-config.toml | 5 ++ ldk-server/ldk-server/src/main.rs | 3 + ldk-server/ldk-server/src/util/config.rs | 70 ++++++++++++++++++-- 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml index 45967f542..e4343b6e1 100644 --- a/ldk-server/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -20,6 +20,11 @@ rpc_address = "127.0.0.1:18444" # RPC endpoint rpc_user = "polaruser" # RPC username rpc_password = "polarpass" # RPC password +# Electrum settings +[electrum] +server_url = "ssl://electrum.blockstream.info:50002" # Electrum endpoint +# server_url = "tcp://electrum.blockstream.info:50001" + # Esplora settings [esplora] server_url = "https://mempool.space/api" # Esplora endpoint diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index e16d5f0cf..70fad7e0a 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -123,6 +123,9 @@ fn main() { rpc_password, ); }, + ChainSource::Electrum { server_url } => { + builder.set_chain_source_electrum(server_url, None); + }, ChainSource::Esplora { server_url } => { builder.set_chain_source_esplora(server_url, None); }, diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 79fda3585..98a78f4e8 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -37,6 +37,7 @@ pub struct Config { #[derive(Debug)] pub enum ChainSource { Rpc { rpc_address: SocketAddr, rpc_user: String, rpc_password: String }, + Electrum { server_url: String }, Esplora { server_url: String }, } @@ -58,9 +59,12 @@ impl TryFrom for Config { format!("Invalid rest service address configured: {}", e), ) })?; - let chain_source = match (toml_config.esplora, toml_config.bitcoind) { - (Some(EsploraConfig { server_url }), None) => ChainSource::Esplora { server_url }, - (None, Some(BitcoindConfig { rpc_address, rpc_user, rpc_password })) => { + let chain_source = match (toml_config.esplora, toml_config.electrum, toml_config.bitcoind) { + (Some(EsploraConfig { server_url }), None, None) => ChainSource::Esplora { server_url }, + (None, Some(ElectrumConfig { server_url }), None) => { + ChainSource::Electrum { server_url } + }, + (None, None, Some(BitcoindConfig { rpc_address, rpc_user, rpc_password })) => { let rpc_address = SocketAddr::from_str(&rpc_address).map_err(|e| { io::Error::new( io::ErrorKind::InvalidInput, @@ -69,16 +73,18 @@ impl TryFrom for Config { })?; ChainSource::Rpc { rpc_address, rpc_user, rpc_password } }, - (Some(_), Some(_)) => { + (None, None, None) => { return Err(io::Error::new( io::ErrorKind::InvalidInput, - format!("Must set a single chain source, multiple were configured"), + format!( + "At least one chain source must be set, either esplora, electrum, or bitcoind" + ), )) }, - (None, None) => { + _ => { return Err(io::Error::new( io::ErrorKind::InvalidInput, - format!("At least one chain source must be set, either bitcoind or esplora"), + format!("Must set a single chain source, multiple were configured"), )) }, }; @@ -161,6 +167,7 @@ pub struct TomlConfig { node: NodeConfig, storage: StorageConfig, bitcoind: Option, + electrum: Option, esplora: Option, rabbitmq: Option, liquidity: Option, @@ -192,6 +199,11 @@ struct BitcoindConfig { rpc_password: String, } +#[derive(Deserialize, Serialize)] +struct ElectrumConfig { + server_url: String, +} + #[derive(Deserialize, Serialize)] struct EsploraConfig { server_url: String, @@ -370,6 +382,50 @@ mod tests { #[cfg(feature = "experimental-lsps2-support")] assert_eq!(config.lsps2_service_config.is_some(), expected.lsps2_service_config.is_some()); + // Test case where only electrum is set + + let toml_config = r#" + [node] + network = "regtest" + listening_address = "localhost:3001" + rest_service_address = "127.0.0.1:3002" + alias = "LDK Server" + + [storage.disk] + dir_path = "/tmp" + + [log] + level = "Trace" + file = "/var/log/ldk-server.log" + + [electrum] + server_url = "ssl://electrum.blockstream.info:50002" + + [rabbitmq] + connection_string = "rabbitmq_connection_string" + exchange_name = "rabbitmq_exchange_name" + + [liquidity.lsps2_service] + advertise_service = false + channel_opening_fee_ppm = 1000 # 0.1% fee + channel_over_provisioning_ppm = 500000 # 50% extra capacity + min_channel_opening_fee_msat = 10000000 # 10,000 satoshis + min_channel_lifetime = 4320 # ~30 days + max_client_to_self_delay = 1440 # ~10 days + min_payment_size_msat = 10000000 # 10,000 satoshis + max_payment_size_msat = 25000000000 # 0.25 BTC + client_trusts_lsp = true + "#; + + fs::write(storage_path.join(config_file_name), toml_config).unwrap(); + let config = load_config(storage_path.join(config_file_name)).unwrap(); + + let ChainSource::Electrum { server_url } = config.chain_source else { + panic!("unexpected chain source"); + }; + + assert_eq!(server_url, "ssl://electrum.blockstream.info:50002"); + // Test case where only bitcoind is set let toml_config = r#" From e72c6f5f3e13b16114eb2fd076da71a200ce0e1e Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 16 Dec 2025 18:37:21 -0600 Subject: [PATCH 178/203] Fix clippy issues, enforce in CI We weren't checking for any clippy issues. This fixes most of them and adds a few exceptions for ones not worth fixing or ones that will be fixed with future changes. --- ldk-server/.github/workflows/build.yml | 4 + ldk-server/ldk-server-protos/Cargo.toml | 7 ++ ldk-server/ldk-server/src/api/bolt11_send.rs | 2 +- ldk-server/ldk-server/src/api/bolt12_send.rs | 2 +- ldk-server/ldk-server/src/api/error.rs | 5 +- .../ldk-server/src/api/get_payment_details.rs | 4 +- .../ldk-server/src/api/list_channels.rs | 2 +- ldk-server/ldk-server/src/api/onchain_send.rs | 2 +- .../src/io/events/event_publisher.rs | 3 + .../src/io/persist/paginated_kv_store.rs | 19 ---- .../src/io/persist/sqlite_store/mod.rs | 103 +++--------------- ldk-server/ldk-server/src/io/utils.rs | 10 +- ldk-server/ldk-server/src/main.rs | 10 +- ldk-server/ldk-server/src/util/config.rs | 61 +++++------ ldk-server/ldk-server/src/util/logger.rs | 18 ++- .../ldk-server/src/util/proto_adapter.rs | 59 +++++----- 16 files changed, 113 insertions(+), 198 deletions(-) diff --git a/ldk-server/.github/workflows/build.yml b/ldk-server/.github/workflows/build.yml index d406e0c74..b6f8a9fa1 100644 --- a/ldk-server/.github/workflows/build.yml +++ b/ldk-server/.github/workflows/build.yml @@ -28,6 +28,7 @@ jobs: run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ matrix.toolchain }} rustup override set ${{ matrix.toolchain }} + if [ "${{ matrix.msrv }}" = "true" ]; then rustup component add clippy; fi - name: Check formatting if: matrix.check-fmt run: rustup component add rustfmt && cargo fmt --all -- --check @@ -37,6 +38,9 @@ jobs: echo "No packages need pinning for MSRV ${{ matrix.toolchain }}" - name: Build on Rust ${{ matrix.toolchain }} run: cargo build --verbose --color always + - name: Check clippy if on msrv + if: matrix.msrv + run: cargo clippy --all-features -- -D warnings - name: Test on Rust ${{ matrix.toolchain }} run: cargo test - name: Cargo check release on Rust ${{ matrix.toolchain }} diff --git a/ldk-server/ldk-server-protos/Cargo.toml b/ldk-server/ldk-server-protos/Cargo.toml index 894abe90e..c971d6f52 100644 --- a/ldk-server/ldk-server-protos/Cargo.toml +++ b/ldk-server/ldk-server-protos/Cargo.toml @@ -5,6 +5,13 @@ edition = "2021" build = "build.rs" +# We use a cfg instead of a feature for genproto to prevent it from being +# enabled with --all-features. Proto generation is a developer-only tool that +# requires external dependencies (protoc) and shouldn't be triggered accidentally. +# This lint configuration tells Cargo that genproto is an expected custom cfg. +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(genproto)'] } + [features] default = [] serde = ["dep:serde", "dep:bytes"] diff --git a/ldk-server/ldk-server/src/api/bolt11_send.rs b/ldk-server/ldk-server/src/api/bolt11_send.rs index d3fbf1b9d..210004daa 100644 --- a/ldk-server/ldk-server/src/api/bolt11_send.rs +++ b/ldk-server/ldk-server/src/api/bolt11_send.rs @@ -18,7 +18,7 @@ use std::str::FromStr; pub(crate) fn handle_bolt11_send_request( context: Context, request: Bolt11SendRequest, ) -> Result { - let invoice = Bolt11Invoice::from_str(&request.invoice.as_str()) + let invoice = Bolt11Invoice::from_str(request.invoice.as_str()) .map_err(|_| ldk_node::NodeError::InvalidInvoice)?; let route_parameters = match request.route_parameters { diff --git a/ldk-server/ldk-server/src/api/bolt12_send.rs b/ldk-server/ldk-server/src/api/bolt12_send.rs index 2c69831f5..a212ca98d 100644 --- a/ldk-server/ldk-server/src/api/bolt12_send.rs +++ b/ldk-server/ldk-server/src/api/bolt12_send.rs @@ -19,7 +19,7 @@ pub(crate) fn handle_bolt12_send_request( context: Context, request: Bolt12SendRequest, ) -> Result { let offer = - Offer::from_str(&request.offer.as_str()).map_err(|_| ldk_node::NodeError::InvalidOffer)?; + Offer::from_str(request.offer.as_str()).map_err(|_| ldk_node::NodeError::InvalidOffer)?; let route_parameters = match request.route_parameters { Some(params) => { diff --git a/ldk-server/ldk-server/src/api/error.rs b/ldk-server/ldk-server/src/api/error.rs index 304a8aa13..cacb0f068 100644 --- a/ldk-server/ldk-server/src/api/error.rs +++ b/ldk-server/ldk-server/src/api/error.rs @@ -38,13 +38,11 @@ impl fmt::Display for LdkServerError { } #[derive(Clone, Debug, PartialEq, Eq)] +#[allow(clippy::enum_variant_names)] pub(crate) enum LdkServerErrorCode { /// Please refer to [`protos::error::ErrorCode::InvalidRequestError`]. InvalidRequestError, - /// Please refer to [`protos::error::ErrorCode::AuthError`]. - AuthError, - /// Please refer to [`protos::error::ErrorCode::LightningError`]. LightningError, @@ -56,7 +54,6 @@ impl fmt::Display for LdkServerErrorCode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { LdkServerErrorCode::InvalidRequestError => write!(f, "InvalidRequestError"), - LdkServerErrorCode::AuthError => write!(f, "AuthError"), LdkServerErrorCode::LightningError => write!(f, "LightningError"), LdkServerErrorCode::InternalServerError => write!(f, "InternalServerError"), } diff --git a/ldk-server/ldk-server/src/api/get_payment_details.rs b/ldk-server/ldk-server/src/api/get_payment_details.rs index afb74691c..bb0fb8257 100644 --- a/ldk-server/ldk-server/src/api/get_payment_details.rs +++ b/ldk-server/ldk-server/src/api/get_payment_details.rs @@ -28,9 +28,7 @@ pub(crate) fn handle_get_payment_details_request( let payment_details = context.node.payment(&PaymentId(payment_id_bytes)); - let response = GetPaymentDetailsResponse { - payment: payment_details.map(|payment| payment_to_proto(payment)), - }; + let response = GetPaymentDetailsResponse { payment: payment_details.map(payment_to_proto) }; Ok(response) } diff --git a/ldk-server/ldk-server/src/api/list_channels.rs b/ldk-server/ldk-server/src/api/list_channels.rs index aa8302579..cf7cd4ad9 100644 --- a/ldk-server/ldk-server/src/api/list_channels.rs +++ b/ldk-server/ldk-server/src/api/list_channels.rs @@ -15,7 +15,7 @@ use ldk_server_protos::api::{ListChannelsRequest, ListChannelsResponse}; pub(crate) fn handle_list_channels_request( context: Context, _request: ListChannelsRequest, ) -> Result { - let channels = context.node.list_channels().into_iter().map(|c| channel_to_proto(c)).collect(); + let channels = context.node.list_channels().into_iter().map(channel_to_proto).collect(); let response = ListChannelsResponse { channels }; Ok(response) diff --git a/ldk-server/ldk-server/src/api/onchain_send.rs b/ldk-server/ldk-server/src/api/onchain_send.rs index c5272a9ad..efc4f7d09 100644 --- a/ldk-server/ldk-server/src/api/onchain_send.rs +++ b/ldk-server/ldk-server/src/api/onchain_send.rs @@ -27,7 +27,7 @@ pub(crate) fn handle_onchain_send_request( ) })?; - let fee_rate = request.fee_rate_sat_per_vb.map(FeeRate::from_sat_per_vb).flatten(); + let fee_rate = request.fee_rate_sat_per_vb.and_then(FeeRate::from_sat_per_vb); let txid = match (request.amount_sats, request.send_all) { (Some(amount_sats), None) => { context.node.onchain_payment().send_to_address(&address, amount_sats, fee_rate)? diff --git a/ldk-server/ldk-server/src/io/events/event_publisher.rs b/ldk-server/ldk-server/src/io/events/event_publisher.rs index 7a9041183..f32678570 100644 --- a/ldk-server/ldk-server/src/io/events/event_publisher.rs +++ b/ldk-server/ldk-server/src/io/events/event_publisher.rs @@ -50,9 +50,12 @@ pub trait EventPublisher: Send + Sync { async fn publish(&self, event: EventEnvelope) -> Result<(), LdkServerError>; } +/// A no-op implementation of the [`EventPublisher`] trait. +#[cfg(not(feature = "events-rabbitmq"))] pub(crate) struct NoopEventPublisher; #[async_trait] +#[cfg(not(feature = "events-rabbitmq"))] impl EventPublisher for NoopEventPublisher { /// Publishes an event to a no-op sink, effectively discarding it. /// diff --git a/ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs b/ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs index ff381b1bd..7a7f66b82 100644 --- a/ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs +++ b/ldk-server/ldk-server/src/io/persist/paginated_kv_store.rs @@ -58,25 +58,6 @@ pub trait PaginatedKVStore: Send + Sync { &self, primary_namespace: &str, secondary_namespace: &str, key: &str, time: i64, buf: &[u8], ) -> Result<(), io::Error>; - /// Removes any data that had previously been persisted under the given `key`. - /// - /// If the `lazy` flag is set to `true`, the backend implementation might choose to lazily - /// remove the given `key` at some point in time after the method returns, e.g., as part of an - /// eventual batch deletion of multiple keys. As a consequence, subsequent calls to - /// [`PaginatedKVStore::list`] might include the removed key until the changes are actually persisted. - /// - /// Note that while setting the `lazy` flag reduces the I/O burden of multiple subsequent - /// `remove` calls, it also influences the atomicity guarantees as lazy `remove`s could - /// potentially get lost on crash after the method returns. Therefore, this flag should only be - /// set for `remove` operations that can be safely replayed at a later time. - /// - /// Returns successfully if no data will be stored for the given `primary_namespace`, - /// `secondary_namespace`, and `key`, independently of whether it was present before its - /// invocation or not. - fn remove( - &self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool, - ) -> Result<(), io::Error>; - /// Returns a paginated list of keys that are stored under the given `secondary_namespace` in /// `primary_namespace`, ordered in descending order of `time`. /// diff --git a/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs b/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs index c473cb54e..6217b21aa 100644 --- a/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs +++ b/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs @@ -29,7 +29,6 @@ const LIST_KEYS_MAX_PAGE_SIZE: i32 = 100; pub struct SqliteStore { connection: Arc>, - data_dir: PathBuf, paginated_kv_table_name: String, } @@ -53,18 +52,18 @@ impl SqliteStore { data_dir.display(), e ); - io::Error::new(io::ErrorKind::Other, msg) + io::Error::other(msg) })?; - let mut db_file_path = data_dir.clone(); + let mut db_file_path = data_dir; db_file_path.push(db_file_name); let connection = Connection::open(db_file_path.clone()).map_err(|e| { let msg = format!("Failed to open/create database file {}: {}", db_file_path.display(), e); - io::Error::new(io::ErrorKind::Other, msg) + io::Error::other(msg) })?; - let sql = format!("SELECT user_version FROM pragma_user_version"); + let sql = "SELECT user_version FROM pragma_user_version".to_string(); let version_res: u16 = connection.query_row(&sql, [], |row| row.get(0)).unwrap(); if version_res == 0 { @@ -78,14 +77,14 @@ impl SqliteStore { ) .map_err(|e| { let msg = format!("Failed to set PRAGMA user_version: {}", e); - io::Error::new(io::ErrorKind::Other, msg) + io::Error::other(msg) })?; } else if version_res > SCHEMA_USER_VERSION { let msg = format!( "Failed to open database: incompatible schema version {}. Expected: {}", version_res, SCHEMA_USER_VERSION ); - return Err(io::Error::new(io::ErrorKind::Other, msg)); + return Err(io::Error::other(msg)); } let create_paginated_kv_table_sql = format!( @@ -101,7 +100,7 @@ impl SqliteStore { connection.execute(&create_paginated_kv_table_sql, []).map_err(|e| { let msg = format!("Failed to create table {}: {}", paginated_kv_table_name, e); - io::Error::new(io::ErrorKind::Other, msg) + io::Error::other(msg) })?; let index_creation_time_sql = format!( @@ -114,16 +113,11 @@ impl SqliteStore { "Failed to create index on creation_time, table {}: {}", paginated_kv_table_name, e ); - io::Error::new(io::ErrorKind::Other, msg) + io::Error::other(msg) })?; let connection = Arc::new(Mutex::new(connection)); - Ok(Self { connection, data_dir, paginated_kv_table_name }) - } - - /// Returns the data directory. - pub fn get_data_dir(&self) -> PathBuf { - self.data_dir.clone() + Ok(Self { connection, paginated_kv_table_name }) } fn read_internal( @@ -138,7 +132,7 @@ impl SqliteStore { let mut stmt = locked_conn.prepare_cached(&sql).map_err(|e| { let msg = format!("Failed to prepare statement: {}", e); - io::Error::new(io::ErrorKind::Other, msg) + io::Error::other(msg) })?; let res = stmt @@ -168,43 +162,11 @@ impl SqliteStore { PrintableString(key), e ); - io::Error::new(io::ErrorKind::Other, msg) + io::Error::other(msg) }, })?; Ok(res) } - - fn remove_internal( - &self, kv_table_name: &str, primary_namespace: &str, secondary_namespace: &str, key: &str, - ) -> io::Result<()> { - check_namespace_key_validity(primary_namespace, secondary_namespace, Some(key), "remove")?; - - let locked_conn = self.connection.lock().unwrap(); - - let sql = format!("DELETE FROM {} WHERE primary_namespace=:primary_namespace AND secondary_namespace=:secondary_namespace AND key=:key;", kv_table_name); - - let mut stmt = locked_conn.prepare_cached(&sql).map_err(|e| { - let msg = format!("Failed to prepare statement: {}", e); - io::Error::new(io::ErrorKind::Other, msg) - })?; - - stmt.execute(named_params! { - ":primary_namespace": primary_namespace, - ":secondary_namespace": secondary_namespace, - ":key": key, - }) - .map_err(|e| { - let msg = format!( - "Failed to delete key {}/{}/{}: {}", - PrintableString(primary_namespace), - PrintableString(secondary_namespace), - PrintableString(key), - e - ); - io::Error::new(io::ErrorKind::Other, msg) - })?; - Ok(()) - } } impl PaginatedKVStore for SqliteStore { @@ -236,7 +198,7 @@ impl PaginatedKVStore for SqliteStore { let mut stmt = locked_conn.prepare_cached(&sql).map_err(|e| { let msg = format!("Failed to prepare statement: {}", e); - io::Error::new(io::ErrorKind::Other, msg) + io::Error::other(msg) })?; stmt.execute(named_params! { @@ -255,21 +217,10 @@ impl PaginatedKVStore for SqliteStore { PrintableString(key), e ); - io::Error::new(io::ErrorKind::Other, msg) + io::Error::other(msg) }) } - fn remove( - &self, primary_namespace: &str, secondary_namespace: &str, key: &str, _lazy: bool, - ) -> io::Result<()> { - self.remove_internal( - &self.paginated_kv_table_name, - primary_namespace, - secondary_namespace, - key, - ) - } - fn list( &self, primary_namespace: &str, secondary_namespace: &str, page_token: Option<(String, i64)>, @@ -287,7 +238,7 @@ impl PaginatedKVStore for SqliteStore { let mut stmt = locked_conn.prepare_cached(&sql).map_err(|e| { let msg = format!("Failed to prepare statement: {}", e); - io::Error::new(io::ErrorKind::Other, msg) + io::Error::other(msg) })?; let mut keys: Vec = Vec::new(); @@ -310,14 +261,14 @@ impl PaginatedKVStore for SqliteStore { ) .map_err(|e| { let msg = format!("Failed to retrieve queried rows: {}", e); - io::Error::new(io::ErrorKind::Other, msg) + io::Error::other(msg) })?; let mut last_creation_time: Option = None; for r in rows_iter { let (k, ct) = r.map_err(|e| { let msg = format!("Failed to retrieve queried rows: {}", e); - io::Error::new(io::ErrorKind::Other, msg) + io::Error::other(msg) })?; keys.push(k); last_creation_time = Some(ct); @@ -342,15 +293,6 @@ mod tests { use rand::{thread_rng, Rng}; use std::panic::RefUnwindSafe; - impl Drop for SqliteStore { - fn drop(&mut self) { - match fs::remove_dir_all(&self.data_dir) { - Err(e) => println!("Failed to remove test store directory: {}", e), - _ => {}, - } - } - } - #[test] fn read_write_remove_list_persist() { let mut temp_path = random_storage_path(); @@ -422,14 +364,8 @@ mod tests { let read_data = kv_store.read(primary_namespace, secondary_namespace, testkey).unwrap(); assert_eq!(data, &*read_data); - kv_store.remove(primary_namespace, secondary_namespace, testkey, false).unwrap(); - - let listed_keys = list_all_keys(primary_namespace, secondary_namespace); - assert_eq!(listed_keys.len(), 109); - // Ensure we have no issue operating with primary_namespace/secondary_namespace/key being KVSTORE_NAMESPACE_KEY_MAX_LEN - let max_chars: String = - std::iter::repeat('A').take(KVSTORE_NAMESPACE_KEY_MAX_LEN).collect(); + let max_chars: String = "A".repeat(KVSTORE_NAMESPACE_KEY_MAX_LEN); kv_store.write(&max_chars, &max_chars, &max_chars, 0, &data).unwrap(); println!("{:?}", listed_keys); @@ -440,10 +376,5 @@ mod tests { let read_data = kv_store.read(&max_chars, &max_chars, &max_chars).unwrap(); assert_eq!(data, &*read_data); - - kv_store.remove(&max_chars, &max_chars, &max_chars, false).unwrap(); - - let listed_keys = list_all_keys(&max_chars, &max_chars); - assert_eq!(listed_keys.len(), 0); } } diff --git a/ldk-server/ldk-server/src/io/utils.rs b/ldk-server/ldk-server/src/io/utils.rs index 4b81d8a2c..d3571cc8e 100644 --- a/ldk-server/ldk-server/src/io/utils.rs +++ b/ldk-server/ldk-server/src/io/utils.rs @@ -32,7 +32,7 @@ pub(crate) fn check_namespace_key_validity( PrintableString(secondary_namespace), PrintableString(key) ); - return Err(std::io::Error::new(std::io::ErrorKind::Other, msg)); + return Err(std::io::Error::other(msg)); } if primary_namespace.is_empty() && !secondary_namespace.is_empty() { @@ -45,7 +45,7 @@ pub(crate) fn check_namespace_key_validity( "Failed to {} {}/{}/{}: primary namespace may not be empty if a non-empty secondary namespace is given.", operation, PrintableString(primary_namespace), PrintableString(secondary_namespace), PrintableString(key) ); - return Err(std::io::Error::new(std::io::ErrorKind::Other, msg)); + return Err(std::io::Error::other(msg)); } if !is_valid_kvstore_str(primary_namespace) @@ -67,7 +67,7 @@ pub(crate) fn check_namespace_key_validity( PrintableString(secondary_namespace), PrintableString(key) ); - return Err(std::io::Error::new(std::io::ErrorKind::Other, msg)); + return Err(std::io::Error::other(msg)); } } else { if primary_namespace.is_empty() && !secondary_namespace.is_empty() { @@ -79,7 +79,7 @@ pub(crate) fn check_namespace_key_validity( "Failed to {} {}/{}: primary namespace may not be empty if a non-empty secondary namespace is given.", operation, PrintableString(primary_namespace), PrintableString(secondary_namespace) ); - return Err(std::io::Error::new(std::io::ErrorKind::Other, msg)); + return Err(std::io::Error::other(msg)); } if !is_valid_kvstore_str(primary_namespace) || !is_valid_kvstore_str(secondary_namespace) { debug_assert!( @@ -95,7 +95,7 @@ pub(crate) fn check_namespace_key_validity( PrintableString(primary_namespace), PrintableString(secondary_namespace) ); - return Err(std::io::Error::new(std::io::ErrorKind::Other, msg)); + return Err(std::io::Error::other(msg)); } } diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 70fad7e0a..f5c86ae86 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -22,7 +22,7 @@ use tokio::signal::unix::SignalKind; use hyper::server::conn::http1; use hyper_util::rt::TokioIo; -use crate::io::events::event_publisher::{EventPublisher, NoopEventPublisher}; +use crate::io::events::event_publisher::EventPublisher; use crate::io::events::get_event_name; #[cfg(feature = "events-rabbitmq")] use crate::io::events::rabbitmq::{RabbitMqConfig, RabbitMqEventPublisher}; @@ -81,7 +81,7 @@ fn main() { }, }; - let log_file_path = config_file.log_file_path.map(|p| PathBuf::from(p)).unwrap_or_else(|| { + let log_file_path = config_file.log_file_path.map(PathBuf::from).unwrap_or_else(|| { let mut default_log_path = PathBuf::from(&config_file.storage_dir_path); default_log_path.push("ldk-server.log"); default_log_path @@ -164,7 +164,9 @@ fn main() { }, }); - let event_publisher: Arc = Arc::new(NoopEventPublisher); + #[cfg(not(feature = "events-rabbitmq"))] + let event_publisher: Arc = + Arc::new(crate::io::events::event_publisher::NoopEventPublisher); #[cfg(feature = "events-rabbitmq")] let event_publisher: Arc = { @@ -275,7 +277,7 @@ fn main() { let payment = payment_to_proto(payment_details); upsert_payment_details(&event_node, Arc::clone(&paginated_store), &payment); } else { - error!("Unable to find payment with paymentId: {}", payment_id.to_string()); + error!("Unable to find payment with paymentId: {payment_id}"); } }, Event::PaymentForwarded { diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 98a78f4e8..f09ca867f 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -76,15 +76,14 @@ impl TryFrom for Config { (None, None, None) => { return Err(io::Error::new( io::ErrorKind::InvalidInput, - format!( "At least one chain source must be set, either esplora, electrum, or bitcoind" - ), + .to_string(), )) }, _ => { return Err(io::Error::new( io::ErrorKind::InvalidInput, - format!("Must set a single chain source, multiple were configured"), + "Must set a single chain source, multiple were configured".to_string(), )) }, }; @@ -240,32 +239,32 @@ struct LSPS2ServiceTomlConfig { require_token: Option, } -impl Into for LSPS2ServiceTomlConfig { - fn into(self) -> LSPS2ServiceConfig { - match self { - LSPS2ServiceTomlConfig { - advertise_service, - channel_opening_fee_ppm, - channel_over_provisioning_ppm, - min_channel_opening_fee_msat, - min_channel_lifetime, - max_client_to_self_delay, - min_payment_size_msat, - max_payment_size_msat, - client_trusts_lsp, - require_token, - } => LSPS2ServiceConfig { - advertise_service, - channel_opening_fee_ppm, - channel_over_provisioning_ppm, - min_channel_opening_fee_msat, - min_channel_lifetime, - min_payment_size_msat, - max_client_to_self_delay, - max_payment_size_msat, - client_trusts_lsp, - require_token, - }, +impl From for LSPS2ServiceConfig { + fn from(val: LSPS2ServiceTomlConfig) -> Self { + let LSPS2ServiceTomlConfig { + advertise_service, + channel_opening_fee_ppm, + channel_over_provisioning_ppm, + min_channel_opening_fee_msat, + min_channel_lifetime, + max_client_to_self_delay, + min_payment_size_msat, + max_payment_size_msat, + client_trusts_lsp, + require_token, + } = val; + + Self { + advertise_service, + channel_opening_fee_ppm, + channel_over_provisioning_ppm, + min_channel_opening_fee_msat, + min_channel_lifetime, + min_payment_size_msat, + max_client_to_self_delay, + max_payment_size_msat, + client_trusts_lsp, + require_token, } } } @@ -285,7 +284,7 @@ pub fn load_config>(config_path: P) -> io::Result { format!("Config file contains invalid TOML format: {}", e), ) })?; - Ok(Config::try_from(toml_config)?) + Config::try_from(toml_config) } #[cfg(test)] @@ -336,7 +335,7 @@ mod tests { let mut bytes = [0u8; 32]; let alias = "LDK Server"; - bytes[..alias.as_bytes().len()].copy_from_slice(alias.as_bytes()); + bytes[..alias.len()].copy_from_slice(alias.as_bytes()); let config = load_config(storage_path.join(config_file_name)).unwrap(); let expected = Config { diff --git a/ldk-server/ldk-server/src/util/logger.rs b/ldk-server/ldk-server/src/util/logger.rs index add0d24fa..d0c5e2455 100644 --- a/ldk-server/ldk-server/src/util/logger.rs +++ b/ldk-server/ldk-server/src/util/logger.rs @@ -58,7 +58,7 @@ impl ServerLogger { }); log::set_boxed_logger(Box::new(LoggerWrapper(Arc::clone(&logger)))) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + .map_err(io::Error::other)?; log::set_max_level(level); Ok(logger) } @@ -73,9 +73,7 @@ impl ServerLogger { *file = new_file; Ok(()) }, - Err(e) => { - Err(io::Error::new(io::ErrorKind::Other, format!("Failed to acquire lock: {}", e))) - }, + Err(e) => Err(io::Error::other(format!("Failed to acquire lock: {e}"))), } } } @@ -93,9 +91,9 @@ impl Log for ServerLogger { // Log to console let _ = match record.level() { Level::Error => { - write!( + writeln!( io::stderr(), - "[{} {} {}:{}] {}\n", + "[{} {} {}:{}] {}", format_timestamp(), level_str, record.target(), @@ -104,9 +102,9 @@ impl Log for ServerLogger { ) }, _ => { - write!( + writeln!( io::stdout(), - "[{} {} {}:{}] {}\n", + "[{} {} {}:{}] {}", format_timestamp(), level_str, record.target(), @@ -118,9 +116,9 @@ impl Log for ServerLogger { // Log to file if let Ok(mut file) = self.file.lock() { - let _ = write!( + let _ = writeln!( file, - "[{} {} {}:{}] {}\n", + "[{} {} {}:{}] {}", format_timestamp(), level_str, record.target(), diff --git a/ldk-server/ldk-server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs index 360d3944f..7fb72553b 100644 --- a/ldk-server/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -9,7 +9,7 @@ use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::{ - AuthError, InternalServerError, InvalidRequestError, LightningError, + InternalServerError, InvalidRequestError, LightningError, }; use bytes::Bytes; use hex::prelude::*; @@ -105,37 +105,33 @@ pub(crate) fn channel_config_to_proto( } pub(crate) fn payment_to_proto(payment: PaymentDetails) -> Payment { - match payment { - PaymentDetails { - id, - kind, - amount_msat, - fee_paid_msat, - direction, - status, - latest_update_timestamp, - } => Payment { - id: id.to_string(), - kind: Some(payment_kind_to_proto(kind)), - amount_msat, - fee_paid_msat, - direction: match direction { - PaymentDirection::Inbound => { - ldk_server_protos::types::PaymentDirection::Inbound.into() - }, - PaymentDirection::Outbound => { - ldk_server_protos::types::PaymentDirection::Outbound.into() - }, - }, - status: match status { - PaymentStatus::Pending => ldk_server_protos::types::PaymentStatus::Pending.into(), - PaymentStatus::Succeeded => { - ldk_server_protos::types::PaymentStatus::Succeeded.into() - }, - PaymentStatus::Failed => ldk_server_protos::types::PaymentStatus::Failed.into(), + let PaymentDetails { + id, + kind, + amount_msat, + fee_paid_msat, + direction, + status, + latest_update_timestamp, + } = payment; + + Payment { + id: id.to_string(), + kind: Some(payment_kind_to_proto(kind)), + amount_msat, + fee_paid_msat, + direction: match direction { + PaymentDirection::Inbound => ldk_server_protos::types::PaymentDirection::Inbound.into(), + PaymentDirection::Outbound => { + ldk_server_protos::types::PaymentDirection::Outbound.into() }, - latest_update_timestamp, }, + status: match status { + PaymentStatus::Pending => ldk_server_protos::types::PaymentStatus::Pending.into(), + PaymentStatus::Succeeded => ldk_server_protos::types::PaymentStatus::Succeeded.into(), + PaymentStatus::Failed => ldk_server_protos::types::PaymentStatus::Failed.into(), + }, + latest_update_timestamp, } } @@ -387,6 +383,7 @@ pub(crate) fn pending_sweep_balance_to_proto( } } +#[allow(clippy::too_many_arguments)] pub(crate) fn forwarded_payment_to_proto( prev_channel_id: ChannelId, next_channel_id: ChannelId, prev_user_channel_id: Option, next_user_channel_id: Option, @@ -446,14 +443,12 @@ pub(crate) fn proto_to_bolt11_description( pub(crate) fn to_error_response(ldk_error: LdkServerError) -> (ErrorResponse, StatusCode) { let error_code = match ldk_error.error_code { InvalidRequestError => ErrorCode::InvalidRequestError, - AuthError => ErrorCode::AuthError, LightningError => ErrorCode::LightningError, InternalServerError => ErrorCode::InternalServerError, } as i32; let status = match ldk_error.error_code { InvalidRequestError => StatusCode::BAD_REQUEST, - AuthError => StatusCode::UNAUTHORIZED, LightningError => StatusCode::INTERNAL_SERVER_ERROR, InternalServerError => StatusCode::INTERNAL_SERVER_ERROR, }; From 2efa91b48a362362c600a0ab20f360352ec8a593 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Fri, 9 Jan 2026 14:09:26 -0600 Subject: [PATCH 179/203] Fix clippy issue from #84 Silent merge conflict from #84, we were not enforcing clippy in CI when this was opened so it never ran. --- ldk-server/ldk-server-cli/src/main.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 019739c75..6cbfcd8e9 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -423,11 +423,8 @@ async fn main() { ); }, Commands::ListPayments { number_of_payments, page_token } => { - let page_token = if let Some(token_str) = page_token { - Some(parse_page_token(&token_str).unwrap_or_else(|e| handle_error(e))) - } else { - None - }; + let page_token = page_token + .map(|token_str| parse_page_token(&token_str).unwrap_or_else(|e| handle_error(e))); handle_response_result::<_, CliListPaymentsResponse>( handle_list_payments(client, number_of_payments, page_token).await, From 457e92aef4a9f2d3a381311dfa169f3dc47903b8 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Wed, 17 Dec 2025 23:16:55 -0600 Subject: [PATCH 180/203] Add HMAC-based authentication for RPC/CLI Implements time-based HMAC-SHA256 authentication using a shared API key. Each request includes a timestamp and HMAC in the X-Auth header, preventing replay attacks with a 60-second tolerance window. Co-Authored-By: Claude Opus 4.5 --- ldk-server/Cargo.lock | 2 + ldk-server/README.md | 4 +- ldk-server/ldk-server-cli/src/main.rs | 5 +- ldk-server/ldk-server-client/Cargo.toml | 1 + ldk-server/ldk-server-client/src/client.rs | 28 +- ldk-server/ldk-server/Cargo.toml | 1 + ldk-server/ldk-server/ldk-server-config.toml | 1 + ldk-server/ldk-server/src/api/error.rs | 4 + ldk-server/ldk-server/src/main.rs | 2 +- ldk-server/ldk-server/src/service.rs | 388 +++++++++++++++--- ldk-server/ldk-server/src/util/config.rs | 37 +- .../ldk-server/src/util/proto_adapter.rs | 4 +- 12 files changed, 409 insertions(+), 68 deletions(-) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index ba02fb5ed..69dbd04b9 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -1717,6 +1717,7 @@ name = "ldk-server" version = "0.1.0" dependencies = [ "async-trait", + "base64 0.21.7", "bytes", "chrono", "futures-util", @@ -1751,6 +1752,7 @@ dependencies = [ name = "ldk-server-client" version = "0.1.0" dependencies = [ + "bitcoin_hashes 0.14.0", "ldk-server-protos", "prost", "reqwest 0.11.27", diff --git a/ldk-server/README.md b/ldk-server/README.md index 8ea707130..e3358c47b 100644 --- a/ldk-server/README.md +++ b/ldk-server/README.md @@ -51,6 +51,6 @@ cargo run --bin ldk-server ./ldk-server/ldk-server-config.toml Interact with the node using CLI: ``` -./target/debug/ldk-server-cli -b localhost:3002 onchain-receive # To generate onchain-receive address. -./target/debug/ldk-server-cli -b localhost:3002 help # To print help/available commands. +./target/debug/ldk-server-cli -b localhost:3002 --api-key your-secret-api-key onchain-receive # To generate onchain-receive address. +./target/debug/ldk-server-cli -b localhost:3002 --api-key your-secret-api-key help # To print help/available commands. ``` diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 6cbfcd8e9..58be09549 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -46,6 +46,9 @@ struct Cli { #[arg(short, long, default_value = "localhost:3000")] base_url: String, + #[arg(short, long, required(true))] + api_key: String, + #[command(subcommand)] command: Commands, } @@ -214,7 +217,7 @@ enum Commands { #[tokio::main] async fn main() { let cli = Cli::parse(); - let client = LdkServerClient::new(cli.base_url); + let client = LdkServerClient::new(cli.base_url, cli.api_key); match cli.command { Commands::GetNodeInfo => { diff --git a/ldk-server/ldk-server-client/Cargo.toml b/ldk-server/ldk-server-client/Cargo.toml index ca0ffadb1..13916fa3f 100644 --- a/ldk-server/ldk-server-client/Cargo.toml +++ b/ldk-server/ldk-server-client/Cargo.toml @@ -11,3 +11,4 @@ serde = ["ldk-server-protos/serde"] ldk-server-protos = { path = "../ldk-server-protos" } reqwest = { version = "0.11.13", default-features = false, features = ["rustls-tls"] } prost = { version = "0.11.6", default-features = false, features = ["std", "prost-derive"] } +bitcoin_hashes = "0.14" diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index 99831517d..3c76060ea 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -13,6 +13,8 @@ use crate::error::LdkServerError; use crate::error::LdkServerErrorCode::{ AuthError, InternalError, InternalServerError, InvalidRequestError, LightningError, }; +use bitcoin_hashes::hmac::{Hmac, HmacEngine}; +use bitcoin_hashes::{sha256, Hash, HashEngine}; use ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse, Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, @@ -32,6 +34,7 @@ use ldk_server_protos::endpoints::{ use ldk_server_protos::error::{ErrorCode, ErrorResponse}; use reqwest::header::CONTENT_TYPE; use reqwest::Client; +use std::time::{SystemTime, UNIX_EPOCH}; const APPLICATION_OCTET_STREAM: &str = "application/octet-stream"; @@ -40,12 +43,31 @@ const APPLICATION_OCTET_STREAM: &str = "application/octet-stream"; pub struct LdkServerClient { base_url: String, client: Client, + api_key: String, } impl LdkServerClient { /// Constructs a [`LdkServerClient`] using `base_url` as the ldk-server endpoint. - pub fn new(base_url: String) -> Self { - Self { base_url, client: Client::new() } + /// `api_key` is used for HMAC-based authentication. + pub fn new(base_url: String, api_key: String) -> Self { + Self { base_url, client: Client::new(), api_key } + } + + /// Computes the HMAC-SHA256 authentication header value. + /// Format: "HMAC :" + fn compute_auth_header(&self, body: &[u8]) -> String { + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("System time should be after Unix epoch") + .as_secs(); + + // Compute HMAC-SHA256(api_key, timestamp_bytes || body) + let mut hmac_engine: HmacEngine = HmacEngine::new(self.api_key.as_bytes()); + hmac_engine.input(×tamp.to_be_bytes()); + hmac_engine.input(body); + let hmac_result = Hmac::::from_engine(hmac_engine); + + format!("HMAC {}:{}", timestamp, hmac_result) } /// Retrieve the latest node info like `node_id`, `current_best_block` etc. @@ -196,10 +218,12 @@ impl LdkServerClient { &self, request: &Rq, url: &str, ) -> Result { let request_body = request.encode_to_vec(); + let auth_header = self.compute_auth_header(&request_body); let response_raw = self .client .post(url) .header(CONTENT_TYPE, APPLICATION_OCTET_STREAM) + .header("X-Auth", auth_header) .body(request_body) .send() .await diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index e1053f778..62f82d3a8 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -20,6 +20,7 @@ async-trait = { version = "0.1.85", default-features = false } toml = { version = "0.8.9", default-features = false, features = ["parse"] } chrono = { version = "0.4", default-features = false, features = ["clock"] } log = "0.4.28" +base64 = { version = "0.21", default-features = false, features = ["std"] } # Required for RabittMQ based EventPublisher. Only enabled for `events-rabbitmq` feature. lapin = { version = "2.4.0", features = ["rustls"], default-features = false, optional = true } diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml index e4343b6e1..f419aede9 100644 --- a/ldk-server/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -3,6 +3,7 @@ network = "regtest" # Bitcoin network to use listening_address = "localhost:3001" # Lightning node listening address rest_service_address = "127.0.0.1:3002" # LDK Server REST address +api_key = "your-secret-api-key" # API key for authenticating REST requests # Storage settings [storage.disk] diff --git a/ldk-server/ldk-server/src/api/error.rs b/ldk-server/ldk-server/src/api/error.rs index cacb0f068..15a5bca19 100644 --- a/ldk-server/ldk-server/src/api/error.rs +++ b/ldk-server/ldk-server/src/api/error.rs @@ -43,6 +43,9 @@ pub(crate) enum LdkServerErrorCode { /// Please refer to [`protos::error::ErrorCode::InvalidRequestError`]. InvalidRequestError, + /// Please refer to [`protos::error::ErrorCode::AuthError`]. + AuthError, + /// Please refer to [`protos::error::ErrorCode::LightningError`]. LightningError, @@ -54,6 +57,7 @@ impl fmt::Display for LdkServerErrorCode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { LdkServerErrorCode::InvalidRequestError => write!(f, "InvalidRequestError"), + LdkServerErrorCode::AuthError => write!(f, "AuthError"), LdkServerErrorCode::LightningError => write!(f, "LightningError"), LdkServerErrorCode::InternalServerError => write!(f, "InternalServerError"), } diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index f5c86ae86..a18f0bb0a 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -356,7 +356,7 @@ fn main() { match res { Ok((stream, _)) => { let io_stream = TokioIo::new(stream); - let node_service = NodeService::new(Arc::clone(&node), Arc::clone(&paginated_store)); + let node_service = NodeService::new(Arc::clone(&node), Arc::clone(&paginated_store), config_file.api_key.clone()); runtime.spawn(async move { if let Err(err) = http1::Builder::new().serve_connection(io_stream, node_service).await { error!("Failed to serve connection: {}", err); diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index 6048a106a..041997c0e 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -7,6 +7,8 @@ // You may not use this file except in accordance with one or both of these // licenses. +use ldk_node::bitcoin::hashes::hmac::{Hmac, HmacEngine}; +use ldk_node::bitcoin::hashes::{sha256, Hash, HashEngine}; use ldk_node::Node; use http_body_util::{BodyExt, Full, Limited}; @@ -30,7 +32,7 @@ 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::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::InvalidRequestError; +use crate::api::error::LdkServerErrorCode::{AuthError, InvalidRequestError}; use crate::api::get_balances::handle_get_balances_request; use crate::api::get_node_info::handle_get_node_info_request; use crate::api::get_payment_details::handle_get_payment_details_request; @@ -56,14 +58,86 @@ const MAX_BODY_SIZE: usize = 10 * 1024 * 1024; pub struct NodeService { node: Arc, paginated_kv_store: Arc, + api_key: String, } impl NodeService { - pub(crate) fn new(node: Arc, paginated_kv_store: Arc) -> Self { - Self { node, paginated_kv_store } + pub(crate) fn new( + node: Arc, paginated_kv_store: Arc, api_key: String, + ) -> Self { + Self { node, paginated_kv_store, api_key } } } +// Maximum allowed time difference between client timestamp and server time (1 minute) +const AUTH_TIMESTAMP_TOLERANCE_SECS: u64 = 60; + +#[derive(Debug, Clone)] +pub(crate) struct AuthParams { + timestamp: u64, + hmac_hex: String, +} + +/// Extracts authentication parameters from request headers. +/// Returns (timestamp, hmac_hex) if valid format, or error. +fn extract_auth_params(req: &Request) -> Result { + let auth_header = req + .headers() + .get("X-Auth") + .and_then(|v| v.to_str().ok()) + .ok_or_else(|| LdkServerError::new(AuthError, "Missing X-Auth header"))?; + + // Format: "HMAC :" + let auth_data = auth_header + .strip_prefix("HMAC ") + .ok_or_else(|| LdkServerError::new(AuthError, "Invalid X-Auth header format"))?; + + let (timestamp_str, hmac_hex) = auth_data + .split_once(':') + .ok_or_else(|| LdkServerError::new(AuthError, "Invalid X-Auth header format"))?; + + let timestamp = timestamp_str + .parse::() + .map_err(|_| LdkServerError::new(AuthError, "Invalid timestamp in X-Auth header"))?; + + // validate hmac_hex is valid hex + if hmac_hex.len() != 64 || !hmac_hex.chars().all(|c| c.is_ascii_hexdigit()) { + return Err(LdkServerError::new(AuthError, "Invalid HMAC in X-Auth header")); + } + + Ok(AuthParams { timestamp, hmac_hex: hmac_hex.to_string() }) +} + +/// Validates the HMAC authentication after the request body has been read. +fn validate_hmac_auth( + timestamp: u64, provided_hmac_hex: &str, body: &[u8], api_key: &str, +) -> Result<(), LdkServerError> { + // Validate timestamp is within acceptable window + let now = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map_err(|_| LdkServerError::new(AuthError, "System time error"))? + .as_secs(); + + let time_diff = now.abs_diff(timestamp); + if time_diff > AUTH_TIMESTAMP_TOLERANCE_SECS { + return Err(LdkServerError::new(AuthError, "Request timestamp expired")); + } + + // Compute expected HMAC: HMAC-SHA256(api_key, timestamp_bytes || body) + let mut hmac_engine: HmacEngine = HmacEngine::new(api_key.as_bytes()); + hmac_engine.input(×tamp.to_be_bytes()); + hmac_engine.input(body); + let expected_hmac = Hmac::::from_engine(hmac_engine); + + // Compare HMACs (constant-time comparison via Hash equality) + let expected_hex = expected_hmac.to_string(); + if expected_hex != provided_hmac_hex { + return Err(LdkServerError::new(AuthError, "Invalid credentials")); + } + + Ok(()) +} + pub(crate) struct Context { pub(crate) node: Arc, pub(crate) paginated_kv_store: Arc, @@ -75,56 +149,151 @@ impl Service> for NodeService { type Future = Pin> + Send>>; fn call(&self, req: Request) -> Self::Future { + // Extract auth params from headers (validation happens after body is read) + let auth_params = match extract_auth_params(&req) { + Ok(params) => params, + Err(e) => { + let (error_response, status_code) = to_error_response(e); + return Box::pin(async move { + Ok(Response::builder() + .status(status_code) + .body(Full::new(Bytes::from(error_response.encode_to_vec()))) + // unwrap safety: body only errors when previous chained calls failed. + .unwrap()) + }); + }, + }; + let context = Context { node: Arc::clone(&self.node), paginated_kv_store: Arc::clone(&self.paginated_kv_store), }; + let api_key = self.api_key.clone(); + // Exclude '/' from path pattern matching. match &req.uri().path()[1..] { - GET_NODE_INFO_PATH => { - Box::pin(handle_request(context, req, handle_get_node_info_request)) - }, - GET_BALANCES_PATH => { - Box::pin(handle_request(context, req, handle_get_balances_request)) - }, - ONCHAIN_RECEIVE_PATH => { - Box::pin(handle_request(context, req, handle_onchain_receive_request)) - }, - ONCHAIN_SEND_PATH => { - Box::pin(handle_request(context, req, handle_onchain_send_request)) - }, - BOLT11_RECEIVE_PATH => { - Box::pin(handle_request(context, req, handle_bolt11_receive_request)) - }, - BOLT11_SEND_PATH => Box::pin(handle_request(context, req, handle_bolt11_send_request)), - BOLT12_RECEIVE_PATH => { - Box::pin(handle_request(context, req, handle_bolt12_receive_request)) - }, - BOLT12_SEND_PATH => Box::pin(handle_request(context, req, handle_bolt12_send_request)), - OPEN_CHANNEL_PATH => Box::pin(handle_request(context, req, handle_open_channel)), - SPLICE_IN_PATH => Box::pin(handle_request(context, req, handle_splice_in_request)), - SPLICE_OUT_PATH => Box::pin(handle_request(context, req, handle_splice_out_request)), - CLOSE_CHANNEL_PATH => { - Box::pin(handle_request(context, req, handle_close_channel_request)) - }, - FORCE_CLOSE_CHANNEL_PATH => { - Box::pin(handle_request(context, req, handle_force_close_channel_request)) - }, - LIST_CHANNELS_PATH => { - Box::pin(handle_request(context, req, handle_list_channels_request)) - }, - UPDATE_CHANNEL_CONFIG_PATH => { - Box::pin(handle_request(context, req, handle_update_channel_config_request)) - }, - GET_PAYMENT_DETAILS_PATH => { - Box::pin(handle_request(context, req, handle_get_payment_details_request)) - }, - LIST_PAYMENTS_PATH => { - Box::pin(handle_request(context, req, handle_list_payments_request)) - }, - LIST_FORWARDED_PAYMENTS_PATH => { - Box::pin(handle_request(context, req, handle_list_forwarded_payments_request)) + GET_NODE_INFO_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_get_node_info_request, + )), + GET_BALANCES_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_get_balances_request, + )), + ONCHAIN_RECEIVE_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_onchain_receive_request, + )), + ONCHAIN_SEND_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_onchain_send_request, + )), + BOLT11_RECEIVE_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_bolt11_receive_request, + )), + BOLT11_SEND_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_bolt11_send_request, + )), + BOLT12_RECEIVE_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_bolt12_receive_request, + )), + BOLT12_SEND_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_bolt12_send_request, + )), + OPEN_CHANNEL_PATH => { + Box::pin(handle_request(context, req, auth_params, api_key, handle_open_channel)) }, + SPLICE_IN_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_splice_in_request, + )), + SPLICE_OUT_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_splice_out_request, + )), + CLOSE_CHANNEL_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_close_channel_request, + )), + FORCE_CLOSE_CHANNEL_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_force_close_channel_request, + )), + LIST_CHANNELS_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_list_channels_request, + )), + UPDATE_CHANNEL_CONFIG_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_update_channel_config_request, + )), + GET_PAYMENT_DETAILS_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_get_payment_details_request, + )), + LIST_PAYMENTS_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_list_payments_request, + )), + LIST_FORWARDED_PAYMENTS_PATH => Box::pin(handle_request( + context, + req, + auth_params, + api_key, + handle_list_forwarded_payments_request, + )), path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async { @@ -144,7 +313,8 @@ async fn handle_request< R: Message, F: Fn(Context, T) -> Result, >( - context: Context, request: Request, handler: F, + context: Context, request: Request, auth_params: AuthParams, api_key: String, + handler: F, ) -> Result<>>::Response, hyper::Error> { // Limit the size of the request body to prevent abuse let limited_body = Limited::new(request.into_body(), MAX_BODY_SIZE); @@ -163,6 +333,18 @@ async fn handle_request< }, }; + // Validate HMAC authentication with the request body + if let Err(e) = + validate_hmac_auth(auth_params.timestamp, &auth_params.hmac_hex, &bytes, &api_key) + { + let (error_response, status_code) = to_error_response(e); + return Ok(Response::builder() + .status(status_code) + .body(Full::new(Bytes::from(error_response.encode_to_vec()))) + // unwrap safety: body only errors when previous chained calls failed. + .unwrap()); + } + match T::decode(bytes) { Ok(request) => match handler(context, request) { Ok(response) => Ok(Response::builder() @@ -189,3 +371,115 @@ async fn handle_request< }, } } + +#[cfg(test)] +mod tests { + use super::*; + + fn compute_hmac(api_key: &str, timestamp: u64, body: &[u8]) -> String { + let mut hmac_engine: HmacEngine = HmacEngine::new(api_key.as_bytes()); + hmac_engine.input(×tamp.to_be_bytes()); + hmac_engine.input(body); + Hmac::::from_engine(hmac_engine).to_string() + } + + fn create_test_request(auth_header: Option) -> Request<()> { + let mut builder = Request::builder(); + if let Some(header) = auth_header { + builder = builder.header("X-Auth", header); + } + builder.body(()).unwrap() + } + + #[test] + fn test_extract_auth_params_success() { + let timestamp = + std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(); + let hmac = "8f5a33c2c68fb253899a588308fd13dcaf162d2788966a1fb6cc3aa2e0c51a93"; + let auth_header = format!("HMAC {timestamp}:{hmac}"); + + let req = create_test_request(Some(auth_header)); + + let result = extract_auth_params(&req); + assert!(result.is_ok()); + let AuthParams { timestamp: ts, hmac_hex } = result.unwrap(); + assert_eq!(ts, timestamp); + assert_eq!(hmac_hex, hmac); + } + + #[test] + fn test_extract_auth_params_missing_header() { + let req = create_test_request(None); + + let result = extract_auth_params(&req); + assert!(result.is_err()); + assert_eq!(result.unwrap_err().error_code, AuthError); + } + + #[test] + fn test_extract_auth_params_invalid_format() { + // Missing "HMAC " prefix + let req = create_test_request(Some("12345:deadbeef".to_string())); + + let result = extract_auth_params(&req); + assert!(result.is_err()); + assert_eq!(result.unwrap_err().error_code, AuthError); + } + + #[test] + fn test_validate_hmac_auth_success() { + let api_key = "test_api_key".to_string(); + let body = b"test request body"; + let timestamp = + std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(); + let hmac = compute_hmac(&api_key, timestamp, body); + + let result = validate_hmac_auth(timestamp, &hmac, body, &api_key); + assert!(result.is_ok()); + } + + #[test] + fn test_validate_hmac_auth_wrong_key() { + let api_key = "test_api_key".to_string(); + let body = b"test request body"; + let timestamp = + std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(); + // Compute HMAC with wrong key + let hmac = compute_hmac("wrong_key", timestamp, body); + + let result = validate_hmac_auth(timestamp, &hmac, body, &api_key); + assert!(result.is_err()); + assert_eq!(result.unwrap_err().error_code, AuthError); + } + + #[test] + fn test_validate_hmac_auth_expired_timestamp() { + let api_key = "test_api_key".to_string(); + let body = b"test request body"; + // Use a timestamp from 10 minutes ago + let timestamp = + std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() + - 600; + let hmac = compute_hmac(&api_key, timestamp, body); + + let result = validate_hmac_auth(timestamp, &hmac, body, &api_key); + assert!(result.is_err()); + assert_eq!(result.unwrap_err().error_code, AuthError); + } + + #[test] + fn test_validate_hmac_auth_tampered_body() { + let api_key = "test_api_key".to_string(); + let original_body = b"test request body"; + let tampered_body = b"tampered body"; + let timestamp = + std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(); + // Compute HMAC with original body + let hmac = compute_hmac(&api_key, timestamp, original_body); + + // Try to validate with tampered body + let result = validate_hmac_auth(timestamp, &hmac, tampered_body, &api_key); + assert!(result.is_err()); + assert_eq!(result.unwrap_err().error_code, AuthError); + } +} diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index f09ca867f..6f7a006e0 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -24,6 +24,7 @@ pub struct Config { pub listening_addr: SocketAddress, pub alias: Option, pub network: Network, + pub api_key: String, pub rest_service_addr: SocketAddr, pub storage_dir_path: String, pub chain_source: ChainSource, @@ -149,6 +150,7 @@ impl TryFrom for Config { network: toml_config.node.network, alias, rest_service_addr, + api_key: toml_config.node.api_key, storage_dir_path: toml_config.storage.disk.dir_path, chain_source, rabbitmq_connection_string, @@ -179,6 +181,7 @@ struct NodeConfig { listening_address: String, rest_service_address: String, alias: Option, + api_key: String, } #[derive(Deserialize, Serialize)] @@ -304,17 +307,18 @@ mod tests { listening_address = "localhost:3001" rest_service_address = "127.0.0.1:3002" alias = "LDK Server" - + api_key = "test_api_key" + [storage.disk] dir_path = "/tmp" [log] level = "Trace" file = "/var/log/ldk-server.log" - + [esplora] server_url = "https://mempool.space/api" - + [rabbitmq] connection_string = "rabbitmq_connection_string" exchange_name = "rabbitmq_exchange_name" @@ -343,6 +347,7 @@ mod tests { alias: Some(NodeAlias(bytes)), network: Network::Regtest, rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(), + api_key: "test_api_key".to_string(), storage_dir_path: "/tmp".to_string(), chain_source: ChainSource::Esplora { server_url: String::from("https://mempool.space/api"), @@ -368,6 +373,7 @@ mod tests { assert_eq!(config.listening_addr, expected.listening_addr); assert_eq!(config.network, expected.network); assert_eq!(config.rest_service_addr, expected.rest_service_addr); + assert_eq!(config.api_key, expected.api_key); assert_eq!(config.storage_dir_path, expected.storage_dir_path); let ChainSource::Esplora { server_url } = config.chain_source else { panic!("unexpected config chain source"); @@ -389,21 +395,22 @@ mod tests { listening_address = "localhost:3001" rest_service_address = "127.0.0.1:3002" alias = "LDK Server" - + api_key = "test_api_key" + [storage.disk] dir_path = "/tmp" [log] level = "Trace" file = "/var/log/ldk-server.log" - + [electrum] server_url = "ssl://electrum.blockstream.info:50002" - + [rabbitmq] connection_string = "rabbitmq_connection_string" exchange_name = "rabbitmq_exchange_name" - + [liquidity.lsps2_service] advertise_service = false channel_opening_fee_ppm = 1000 # 0.1% fee @@ -433,19 +440,20 @@ mod tests { listening_address = "localhost:3001" rest_service_address = "127.0.0.1:3002" alias = "LDK Server" - + api_key = "test_api_key" + [storage.disk] dir_path = "/tmp" [log] level = "Trace" file = "/var/log/ldk-server.log" - + [bitcoind] rpc_address = "127.0.0.1:8332" # RPC endpoint rpc_user = "bitcoind-testuser" rpc_password = "bitcoind-testpassword" - + [rabbitmq] connection_string = "rabbitmq_connection_string" exchange_name = "rabbitmq_exchange_name" @@ -481,22 +489,23 @@ mod tests { listening_address = "localhost:3001" rest_service_address = "127.0.0.1:3002" alias = "LDK Server" - + api_key = "test_api_key" + [storage.disk] dir_path = "/tmp" [log] level = "Trace" file = "/var/log/ldk-server.log" - + [bitcoind] rpc_address = "127.0.0.1:8332" # RPC endpoint rpc_user = "bitcoind-testuser" rpc_password = "bitcoind-testpassword" - + [esplora] server_url = "https://mempool.space/api" - + [rabbitmq] connection_string = "rabbitmq_connection_string" exchange_name = "rabbitmq_exchange_name" diff --git a/ldk-server/ldk-server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs index 7fb72553b..6e42a881f 100644 --- a/ldk-server/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -9,7 +9,7 @@ use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::{ - InternalServerError, InvalidRequestError, LightningError, + AuthError, InternalServerError, InvalidRequestError, LightningError, }; use bytes::Bytes; use hex::prelude::*; @@ -443,12 +443,14 @@ pub(crate) fn proto_to_bolt11_description( pub(crate) fn to_error_response(ldk_error: LdkServerError) -> (ErrorResponse, StatusCode) { let error_code = match ldk_error.error_code { InvalidRequestError => ErrorCode::InvalidRequestError, + AuthError => ErrorCode::AuthError, LightningError => ErrorCode::LightningError, InternalServerError => ErrorCode::InternalServerError, } as i32; let status = match ldk_error.error_code { InvalidRequestError => StatusCode::BAD_REQUEST, + AuthError => StatusCode::UNAUTHORIZED, LightningError => StatusCode::INTERNAL_SERVER_ERROR, InternalServerError => StatusCode::INTERNAL_SERVER_ERROR, }; From e6b51e5bd797f03c8958bf23af8955cf7abca847 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Tue, 13 Jan 2026 11:27:09 +0100 Subject: [PATCH 181/203] Bump ldk-node to latest main Update to ldk-node git rev d1bbf978 which requires passing NodeEntropy explicitly to the builder. Also adds handling for new NodeError variants HrnParsingFailed and InvalidScriptPubKey. Co-Authored-By: Claude Opus 4.5 --- ldk-server/Cargo.lock | 89 +++++++++++++++----------- ldk-server/ldk-server/Cargo.toml | 2 +- ldk-server/ldk-server/src/api/error.rs | 4 +- ldk-server/ldk-server/src/main.rs | 12 +++- 4 files changed, 65 insertions(+), 42 deletions(-) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 69dbd04b9..6378e8a80 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -455,6 +455,18 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" +[[package]] +name = "bitcoin-payment-instructions" +version = "0.6.0" +source = "git+https://github.com/tnull/bitcoin-payment-instructions?rev=fdca6c62f2fe2c53427d3e51e322a49aa7323ee2#fdca6c62f2fe2c53427d3e51e322a49aa7323ee2" +dependencies = [ + "bitcoin", + "dnssec-prover", + "getrandom 0.3.4", + "lightning", + "lightning-invoice", +] + [[package]] name = "bitcoin-units" version = "0.1.2" @@ -817,6 +829,10 @@ name = "dnssec-prover" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec4f825369fc7134da70ca4040fddc8e03b80a46d249ae38d9c1c39b7b4476bf" +dependencies = [ + "bitcoin_hashes 0.14.0", + "tokio", +] [[package]] name = "doc-comment" @@ -1672,9 +1688,8 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "ldk-node" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830ef2d6b00f089fb6e3ac845370ebf0f35f9d11ce81b3a097c1580d2dce358" +version = "0.8.0+git" +source = "git+https://github.com/lightningdevkit/ldk-node?rev=d1bbf978c8b7abe87ae2e40793556c1fe4e7ea49#d1bbf978c8b7abe87ae2e40793556c1fe4e7ea49" dependencies = [ "base64 0.22.1", "bdk_chain", @@ -1684,6 +1699,7 @@ dependencies = [ "bip21", "bip39", "bitcoin", + "bitcoin-payment-instructions", "chrono", "electrum-client", "esplora-client", @@ -1793,9 +1809,8 @@ dependencies = [ [[package]] name = "lightning" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4342d07db2b3fe7c9a73849e94d012ebcfa3588c25097daf0b5ff2857c04e0e1" +version = "0.3.0+git" +source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" dependencies = [ "bech32", "bitcoin", @@ -1805,14 +1820,14 @@ dependencies = [ "lightning-invoice", "lightning-macros", "lightning-types", + "musig2", "possiblyrandom", ] [[package]] name = "lightning-background-processor" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abdc5450264184deba88b1dc61fa8d2ca905e21748bad556915757ac73d91103" +version = "0.2.0+git" +source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" dependencies = [ "bitcoin", "bitcoin-io", @@ -1825,9 +1840,8 @@ dependencies = [ [[package]] name = "lightning-block-sync" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee5069846b07a62aaecdaf25233e067bc69f245b7c8fd00cc9c217053221f875" +version = "0.3.0+git" +source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" dependencies = [ "bitcoin", "chunked_transfer", @@ -1838,9 +1852,8 @@ dependencies = [ [[package]] name = "lightning-invoice" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b85e5e14bcdb30d746e9785b04f27938292e8944f78f26517e01e91691f6b3f2" +version = "0.34.0+git" +source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" dependencies = [ "bech32", "bitcoin", @@ -1850,9 +1863,8 @@ dependencies = [ [[package]] name = "lightning-liquidity" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58a6480d4d7726c49b4cd170b18a39563bbe897d0b8960be11d5e4a0cebd43b0" +version = "0.2.0+git" +source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" dependencies = [ "bitcoin", "chrono", @@ -1866,9 +1878,8 @@ dependencies = [ [[package]] name = "lightning-macros" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80bd6063f4d0c34320f1db9193138c878e64142e6d1c42bd5f0124936e8764ec" +version = "0.2.0+git" +source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" dependencies = [ "proc-macro2", "quote", @@ -1877,9 +1888,8 @@ dependencies = [ [[package]] name = "lightning-net-tokio" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8055737e3d2d06240a3fdf10e26b2716110fcea90011a0839e8e82fc6e58ff5e" +version = "0.2.0+git" +source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" dependencies = [ "bitcoin", "lightning", @@ -1888,9 +1898,8 @@ dependencies = [ [[package]] name = "lightning-persister" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d78990de56ca75c5535c3f8e6f86b183a1aa8f521eb32afb9e8181f3bd91d7" +version = "0.2.0+git" +source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" dependencies = [ "bitcoin", "lightning", @@ -1900,9 +1909,8 @@ dependencies = [ [[package]] name = "lightning-rapid-gossip-sync" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b094f79f22713aa95194a166c77b2f6c7d68f9d76622a43552a29b8fe6fa92d0" +version = "0.2.0+git" +source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" dependencies = [ "bitcoin", "bitcoin-io", @@ -1912,9 +1920,8 @@ dependencies = [ [[package]] name = "lightning-transaction-sync" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f16c2cc74a73e29295bb5c0de61f4a0e6fe7151562ebdd48ee9935fcaa59bd8" +version = "0.2.0+git" +source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" dependencies = [ "bitcoin", "electrum-client", @@ -1926,9 +1933,8 @@ dependencies = [ [[package]] name = "lightning-types" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5681708d3075bdff3a1b4daa400590e2703e7871bdc14e94ee7334fb6314ae40" +version = "0.3.0+git" +source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" dependencies = [ "bitcoin", ] @@ -2024,6 +2030,14 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +[[package]] +name = "musig2" +version = "0.1.0" +source = "git+https://github.com/arik-so/rust-musig2?rev=6f95a05718cbb44d8fe3fa6021aea8117aa38d50#6f95a05718cbb44d8fe3fa6021aea8117aa38d50" +dependencies = [ + "bitcoin", +] + [[package]] name = "nom" version = "7.1.3" @@ -2285,8 +2299,7 @@ dependencies = [ [[package]] name = "possiblyrandom" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b122a615d72104fb3d8b26523fdf9232cd8ee06949fb37e4ce3ff964d15dffd" +source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" dependencies = [ "getrandom 0.2.16", ] diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index 62f82d3a8..d9398e683 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -ldk-node = { version = "0.7.0" } +ldk-node = { git = "https://github.com/lightningdevkit/ldk-node", rev = "d1bbf978c8b7abe87ae2e40793556c1fe4e7ea49" } serde = { version = "1.0.203", default-features = false, features = ["derive"] } hyper = { version = "1", default-features = false, features = ["server", "http1"] } http-body-util = { version = "0.1", default-features = false } diff --git a/ldk-server/ldk-server/src/api/error.rs b/ldk-server/ldk-server/src/api/error.rs index 15a5bca19..2a834607b 100644 --- a/ldk-server/ldk-server/src/api/error.rs +++ b/ldk-server/ldk-server/src/api/error.rs @@ -93,7 +93,6 @@ impl From for LdkServerError { | NodeError::AsyncPaymentServicesDisabled => { (error.to_string(), LdkServerErrorCode::InvalidRequestError) }, - NodeError::ConnectionFailed | NodeError::InvoiceCreationFailed | NodeError::InvoiceRequestCreationFailed @@ -109,8 +108,8 @@ impl From for LdkServerError { | NodeError::DuplicatePayment | NodeError::InsufficientFunds | NodeError::UnsupportedCurrency + | NodeError::HrnParsingFailed | NodeError::LiquidityFeeTooHigh => (error.to_string(), LdkServerErrorCode::LightningError), - NodeError::AlreadyRunning | NodeError::NotRunning | NodeError::PersistenceFailed @@ -125,6 +124,7 @@ impl From for LdkServerError { | NodeError::OnchainTxCreationFailed | NodeError::OnchainTxSigningFailed | NodeError::TxSyncFailed + | NodeError::InvalidScriptPubKey | NodeError::TxSyncTimeout => (error.to_string(), LdkServerErrorCode::InternalServerError), }; LdkServerError::new(error_code, message) diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index a18f0bb0a..806c633ca 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -14,6 +14,7 @@ mod util; use crate::service::NodeService; +use ldk_node::entropy::NodeEntropy; use ldk_node::{Builder, Event, Node}; use tokio::net::TcpListener; @@ -147,7 +148,16 @@ fn main() { builder.set_runtime(runtime.handle().clone()); - let node = match builder.build() { + let seed_path = format!("{}/keys_seed", config_file.storage_dir_path); + let node_entropy = match NodeEntropy::from_seed_path(seed_path) { + Ok(entropy) => entropy, + Err(e) => { + error!("Failed to load or generate seed: {e}"); + std::process::exit(-1); + }, + }; + + let node = match builder.build(node_entropy) { Ok(node) => Arc::new(node), Err(e) => { error!("Failed to build LDK Node: {e}"); From d387893d1bf9664e80e3b2377971a58ed9f2b4ae Mon Sep 17 00:00:00 2001 From: benthecarman Date: Fri, 9 Jan 2026 16:54:21 -0600 Subject: [PATCH 182/203] Add TLS support for RPC/CLI With TLS we can now have encrypted communication with the client and server. We auto generate a self signed cert on startup. Co-Authored-By: Claude Opus 4.5 --- ldk-server/Cargo.lock | 23 ++ ldk-server/ldk-server-cli/src/main.rs | 21 +- ldk-server/ldk-server-client/src/client.rs | 54 +++-- ldk-server/ldk-server/Cargo.toml | 2 + ldk-server/ldk-server/ldk-server-config.toml | 5 + ldk-server/ldk-server/src/main.rs | 34 ++- ldk-server/ldk-server/src/util/config.rs | 34 +++ ldk-server/ldk-server/src/util/mod.rs | 1 + ldk-server/ldk-server/src/util/tls.rs | 226 +++++++++++++++++++ 9 files changed, 374 insertions(+), 26 deletions(-) create mode 100644 ldk-server/ldk-server/src/util/tls.rs diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index 69dbd04b9..917d680ba 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -1731,9 +1731,11 @@ dependencies = [ "log", "prost", "rand 0.8.5", + "rcgen", "rusqlite", "serde", "tokio", + "tokio-rustls 0.26.4", "toml", ] @@ -2526,6 +2528,18 @@ dependencies = [ "cipher", ] +[[package]] +name = "rcgen" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +dependencies = [ + "ring", + "rustls-pki-types", + "time", + "yasna", +] + [[package]] name = "reactor-trait" version = "1.1.0" @@ -4040,6 +4054,15 @@ dependencies = [ "time", ] +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "yoke" version = "0.8.1" diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 58be09549..fb9559cef 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -49,6 +49,14 @@ struct Cli { #[arg(short, long, required(true))] api_key: String, + #[arg( + short, + long, + required(true), + help = "Path to the server's TLS certificate file (PEM format). Found at /tls_cert.pem" + )] + tls_cert: String, + #[command(subcommand)] command: Commands, } @@ -217,7 +225,18 @@ enum Commands { #[tokio::main] async fn main() { let cli = Cli::parse(); - let client = LdkServerClient::new(cli.base_url, cli.api_key); + + // Load server certificate for TLS verification + let server_cert_pem = std::fs::read(&cli.tls_cert).unwrap_or_else(|e| { + eprintln!("Failed to read server certificate file '{}': {}", cli.tls_cert, e); + std::process::exit(1); + }); + + let client = + LdkServerClient::new(cli.base_url, cli.api_key, &server_cert_pem).unwrap_or_else(|e| { + eprintln!("Failed to create client: {e}"); + std::process::exit(1); + }); match cli.command { Commands::GetNodeInfo => { diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index 3c76060ea..060f9bd5a 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -33,12 +33,16 @@ use ldk_server_protos::endpoints::{ }; use ldk_server_protos::error::{ErrorCode, ErrorResponse}; use reqwest::header::CONTENT_TYPE; -use reqwest::Client; +use reqwest::{Certificate, Client}; use std::time::{SystemTime, UNIX_EPOCH}; const APPLICATION_OCTET_STREAM: &str = "application/octet-stream"; /// Client to access a hosted instance of LDK Server. +/// +/// The client requires the server's TLS certificate to be provided for verification. +/// This certificate can be found at `/tls_cert.pem` after the +/// server generates it on first startup. #[derive(Clone)] pub struct LdkServerClient { base_url: String, @@ -48,9 +52,21 @@ pub struct LdkServerClient { impl LdkServerClient { /// Constructs a [`LdkServerClient`] using `base_url` as the ldk-server endpoint. + /// + /// `base_url` should not include the scheme, e.g., `localhost:3000`. /// `api_key` is used for HMAC-based authentication. - pub fn new(base_url: String, api_key: String) -> Self { - Self { base_url, client: Client::new(), api_key } + /// `server_cert_pem` is the server's TLS certificate in PEM format. This can be + /// found at `/tls_cert.pem` after the server starts. + pub fn new(base_url: String, api_key: String, server_cert_pem: &[u8]) -> Result { + let cert = Certificate::from_pem(server_cert_pem) + .map_err(|e| format!("Failed to parse server certificate: {e}"))?; + + let client = Client::builder() + .add_root_certificate(cert) + .build() + .map_err(|e| format!("Failed to build HTTP client: {e}"))?; + + Ok(Self { base_url, client, api_key }) } /// Computes the HMAC-SHA256 authentication header value. @@ -75,7 +91,7 @@ impl LdkServerClient { pub async fn get_node_info( &self, request: GetNodeInfoRequest, ) -> Result { - let url = format!("http://{}/{GET_NODE_INFO_PATH}", self.base_url); + let url = format!("https://{}/{GET_NODE_INFO_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -84,7 +100,7 @@ impl LdkServerClient { pub async fn get_balances( &self, request: GetBalancesRequest, ) -> Result { - let url = format!("http://{}/{GET_BALANCES_PATH}", self.base_url); + let url = format!("https://{}/{GET_BALANCES_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -93,7 +109,7 @@ impl LdkServerClient { pub async fn onchain_receive( &self, request: OnchainReceiveRequest, ) -> Result { - let url = format!("http://{}/{ONCHAIN_RECEIVE_PATH}", self.base_url); + let url = format!("https://{}/{ONCHAIN_RECEIVE_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -102,7 +118,7 @@ impl LdkServerClient { pub async fn onchain_send( &self, request: OnchainSendRequest, ) -> Result { - let url = format!("http://{}/{ONCHAIN_SEND_PATH}", self.base_url); + let url = format!("https://{}/{ONCHAIN_SEND_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -111,7 +127,7 @@ impl LdkServerClient { pub async fn bolt11_receive( &self, request: Bolt11ReceiveRequest, ) -> Result { - let url = format!("http://{}/{BOLT11_RECEIVE_PATH}", self.base_url); + let url = format!("https://{}/{BOLT11_RECEIVE_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -120,7 +136,7 @@ impl LdkServerClient { pub async fn bolt11_send( &self, request: Bolt11SendRequest, ) -> Result { - let url = format!("http://{}/{BOLT11_SEND_PATH}", self.base_url); + let url = format!("https://{}/{BOLT11_SEND_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -129,7 +145,7 @@ impl LdkServerClient { pub async fn bolt12_receive( &self, request: Bolt12ReceiveRequest, ) -> Result { - let url = format!("http://{}/{BOLT12_RECEIVE_PATH}", self.base_url); + let url = format!("https://{}/{BOLT12_RECEIVE_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -138,7 +154,7 @@ impl LdkServerClient { pub async fn bolt12_send( &self, request: Bolt12SendRequest, ) -> Result { - let url = format!("http://{}/{BOLT12_SEND_PATH}", self.base_url); + let url = format!("https://{}/{BOLT12_SEND_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -147,7 +163,7 @@ impl LdkServerClient { pub async fn open_channel( &self, request: OpenChannelRequest, ) -> Result { - let url = format!("http://{}/{OPEN_CHANNEL_PATH}", self.base_url); + let url = format!("https://{}/{OPEN_CHANNEL_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -156,7 +172,7 @@ impl LdkServerClient { pub async fn splice_in( &self, request: SpliceInRequest, ) -> Result { - let url = format!("http://{}/{SPLICE_IN_PATH}", self.base_url); + let url = format!("https://{}/{SPLICE_IN_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -165,7 +181,7 @@ impl LdkServerClient { pub async fn splice_out( &self, request: SpliceOutRequest, ) -> Result { - let url = format!("http://{}/{SPLICE_OUT_PATH}", self.base_url); + let url = format!("https://{}/{SPLICE_OUT_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -174,7 +190,7 @@ impl LdkServerClient { pub async fn close_channel( &self, request: CloseChannelRequest, ) -> Result { - let url = format!("http://{}/{CLOSE_CHANNEL_PATH}", self.base_url); + let url = format!("https://{}/{CLOSE_CHANNEL_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -183,7 +199,7 @@ impl LdkServerClient { pub async fn force_close_channel( &self, request: ForceCloseChannelRequest, ) -> Result { - let url = format!("http://{}/{FORCE_CLOSE_CHANNEL_PATH}", self.base_url); + let url = format!("https://{}/{FORCE_CLOSE_CHANNEL_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -192,7 +208,7 @@ impl LdkServerClient { pub async fn list_channels( &self, request: ListChannelsRequest, ) -> Result { - let url = format!("http://{}/{LIST_CHANNELS_PATH}", self.base_url); + let url = format!("https://{}/{LIST_CHANNELS_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -201,7 +217,7 @@ impl LdkServerClient { pub async fn list_payments( &self, request: ListPaymentsRequest, ) -> Result { - let url = format!("http://{}/{LIST_PAYMENTS_PATH}", self.base_url); + let url = format!("https://{}/{LIST_PAYMENTS_PATH}", self.base_url); self.post_request(&request, &url).await } @@ -210,7 +226,7 @@ impl LdkServerClient { pub async fn update_channel_config( &self, request: UpdateChannelConfigRequest, ) -> Result { - let url = format!("http://{}/{UPDATE_CHANNEL_CONFIG_PATH}", self.base_url); + let url = format!("https://{}/{UPDATE_CHANNEL_CONFIG_PATH}", self.base_url); self.post_request(&request, &url).await } diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index 62f82d3a8..3ec19feb5 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -10,6 +10,8 @@ hyper = { version = "1", default-features = false, features = ["server", "http1" http-body-util = { version = "0.1", default-features = false } hyper-util = { version = "0.1", default-features = false, features = ["server-graceful"] } tokio = { version = "1.38.0", default-features = false, features = ["time", "signal", "rt-multi-thread"] } +tokio-rustls = { version = "0.26", default-features = false, features = ["ring"] } +rcgen = { version = "0.13", default-features = false, features = ["ring"] } prost = { version = "0.11.6", default-features = false, features = ["std"] } ldk-server-protos = { path = "../ldk-server-protos" } bytes = { version = "1.4.0", default-features = false } diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml index f419aede9..f4485e9d9 100644 --- a/ldk-server/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -13,6 +13,11 @@ dir_path = "/tmp/ldk-server/" # Path for LDK and BDK data persis level = "Debug" # Log level (Error, Warn, Info, Debug, Trace) file_path = "/tmp/ldk-server/ldk-server.log" # Log file path +[tls] +#cert_path = "/path/to/tls.crt" # Path to TLS certificate, by default uses dir_path/tls.crt +#key_path = "/path/to/tls.key" # Path to TLS private key, by default uses dir_path/tls.key +hosts = ["example.com"] # Allowed hosts for TLS, will always include "localhost" and "127.0.0.1" + # Must set either bitcoind or esplora settings, but not both # Bitcoin Core settings diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index a18f0bb0a..4c0d74a9f 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -36,6 +36,7 @@ use crate::io::persist::{ use crate::util::config::{load_config, ChainSource}; use crate::util::logger::ServerLogger; use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto}; +use crate::util::tls::get_or_generate_tls_config; use hex::DisplayHex; use ldk_node::config::Config; use ldk_node::lightning::ln::channelmanager::PaymentId; @@ -155,14 +156,15 @@ fn main() { }, }; - let paginated_store: Arc = - Arc::new(match SqliteStore::new(PathBuf::from(config_file.storage_dir_path), None, None) { + let paginated_store: Arc = Arc::new( + match SqliteStore::new(PathBuf::from(&config_file.storage_dir_path), None, None) { Ok(store) => store, Err(e) => { error!("Failed to create SqliteStore: {e:?}"); std::process::exit(-1); }, - }); + }, + ); #[cfg(not(feature = "events-rabbitmq"))] let event_publisher: Arc = @@ -213,6 +215,20 @@ fn main() { let rest_svc_listener = TcpListener::bind(config_file.rest_service_addr) .await .expect("Failed to bind listening port"); + + let server_config = match get_or_generate_tls_config( + config_file.tls_config, + &config_file.storage_dir_path, + ) { + Ok(config) => config, + Err(e) => { + error!("Failed to set up TLS: {e}"); + std::process::exit(-1); + } + }; + let tls_acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(server_config)); + info!("TLS enabled for REST service on {}", config_file.rest_service_addr); + loop { select! { event = event_node.next_event_async() => { @@ -355,11 +371,17 @@ fn main() { res = rest_svc_listener.accept() => { match res { Ok((stream, _)) => { - let io_stream = TokioIo::new(stream); let node_service = NodeService::new(Arc::clone(&node), Arc::clone(&paginated_store), config_file.api_key.clone()); + let acceptor = tls_acceptor.clone(); runtime.spawn(async move { - if let Err(err) = http1::Builder::new().serve_connection(io_stream, node_service).await { - error!("Failed to serve connection: {}", err); + match acceptor.accept(stream).await { + Ok(tls_stream) => { + let io_stream = TokioIo::new(tls_stream); + if let Err(err) = http1::Builder::new().serve_connection(io_stream, node_service).await { + error!("Failed to serve TLS connection: {err}"); + } + }, + Err(e) => error!("TLS handshake failed: {e}"), } }); }, diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 6f7a006e0..2128f7842 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -25,6 +25,7 @@ pub struct Config { pub alias: Option, pub network: Network, pub api_key: String, + pub tls_config: Option, pub rest_service_addr: SocketAddr, pub storage_dir_path: String, pub chain_source: ChainSource, @@ -35,6 +36,13 @@ pub struct Config { pub log_file_path: Option, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TlsConfig { + pub cert_path: Option, + pub key_path: Option, + pub hosts: Vec, +} + #[derive(Debug)] pub enum ChainSource { Rpc { rpc_address: SocketAddr, rpc_user: String, rpc_password: String }, @@ -145,6 +153,12 @@ impl TryFrom for Config { ))? .into()); + let tls_config = toml_config.tls.map(|tls| TlsConfig { + cert_path: tls.cert_path, + key_path: tls.key_path, + hosts: tls.hosts.unwrap_or_default(), + }); + Ok(Config { listening_addr, network: toml_config.node.network, @@ -158,6 +172,7 @@ impl TryFrom for Config { lsps2_service_config, log_level, log_file_path: toml_config.log.and_then(|l| l.file), + tls_config, }) } } @@ -173,6 +188,7 @@ pub struct TomlConfig { rabbitmq: Option, liquidity: Option, log: Option, + tls: Option, } #[derive(Deserialize, Serialize)] @@ -223,6 +239,13 @@ struct RabbitmqConfig { exchange_name: String, } +#[derive(Deserialize, Serialize)] +struct TomlTlsConfig { + cert_path: Option, + key_path: Option, + hosts: Option>, +} + #[derive(Deserialize, Serialize)] struct LiquidityConfig { lsps2_service: Option, @@ -309,6 +332,11 @@ mod tests { alias = "LDK Server" api_key = "test_api_key" + [tls] + cert_path = "/path/to/tls.crt" + key_path = "/path/to/tls.key" + hosts = ["example.com", "ldk-server.local"] + [storage.disk] dir_path = "/tmp" @@ -349,6 +377,11 @@ mod tests { rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(), api_key: "test_api_key".to_string(), storage_dir_path: "/tmp".to_string(), + tls_config: Some(TlsConfig { + cert_path: Some("/path/to/tls.crt".to_string()), + key_path: Some("/path/to/tls.key".to_string()), + hosts: vec!["example.com".to_string(), "ldk-server.local".to_string()], + }), chain_source: ChainSource::Esplora { server_url: String::from("https://mempool.space/api"), }, @@ -375,6 +408,7 @@ mod tests { assert_eq!(config.rest_service_addr, expected.rest_service_addr); assert_eq!(config.api_key, expected.api_key); assert_eq!(config.storage_dir_path, expected.storage_dir_path); + assert_eq!(config.tls_config, expected.tls_config); let ChainSource::Esplora { server_url } = config.chain_source else { panic!("unexpected config chain source"); }; diff --git a/ldk-server/ldk-server/src/util/mod.rs b/ldk-server/ldk-server/src/util/mod.rs index 8bcf1c114..3662b128d 100644 --- a/ldk-server/ldk-server/src/util/mod.rs +++ b/ldk-server/ldk-server/src/util/mod.rs @@ -10,3 +10,4 @@ pub(crate) mod config; pub(crate) mod logger; pub(crate) mod proto_adapter; +pub(crate) mod tls; diff --git a/ldk-server/ldk-server/src/util/tls.rs b/ldk-server/ldk-server/src/util/tls.rs new file mode 100644 index 000000000..41a9dd7a0 --- /dev/null +++ b/ldk-server/ldk-server/src/util/tls.rs @@ -0,0 +1,226 @@ +// 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::util::config::TlsConfig; +use base64::Engine; +use rcgen::{generate_simple_self_signed, CertifiedKey}; +use std::fs; +use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer}; +use tokio_rustls::rustls::ServerConfig; + +// PEM markers +const PEM_CERT_BEGIN: &str = "-----BEGIN CERTIFICATE-----"; +const PEM_CERT_END: &str = "-----END CERTIFICATE-----"; +const PEM_KEY_BEGIN: &str = "-----BEGIN PRIVATE KEY-----"; +const PEM_KEY_END: &str = "-----END PRIVATE KEY-----"; + +/// Gets or generates TLS configuration. If custom paths are provided, uses those. +/// Otherwise, generates a self-signed certificate in the storage directory. +pub fn get_or_generate_tls_config( + tls_config: Option, storage_dir: &str, +) -> Result { + if let Some(config) = tls_config { + let cert_path = config.cert_path.unwrap_or(format!("{storage_dir}/tls.crt")); + let key_path = config.key_path.unwrap_or(format!("{storage_dir}/tls.key")); + if !fs::exists(&cert_path).unwrap_or(false) || !fs::exists(&key_path).unwrap_or(false) { + generate_self_signed_cert(&cert_path, &key_path, &config.hosts)?; + } + load_tls_config(&cert_path, &key_path) + } else { + // Check if we already have generated certs, if we don't, generate new ones + let cert_path = format!("{storage_dir}/tls.crt"); + let key_path = format!("{storage_dir}/tls.key"); + if !fs::exists(&cert_path).unwrap_or(false) || !fs::exists(&key_path).unwrap_or(false) { + generate_self_signed_cert(&cert_path, &key_path, &[])?; + } + + load_tls_config(&cert_path, &key_path) + } +} + +/// Parses a PEM-encoded certificate file and returns the DER-encoded certificates. +fn parse_pem_certs(pem_data: &str) -> Result>, String> { + let mut certs = Vec::new(); + + for block in pem_data.split(PEM_CERT_END) { + if let Some(start) = block.find(PEM_CERT_BEGIN) { + let base64_content: String = block[start + PEM_CERT_BEGIN.len()..] + .lines() + .filter(|line| !line.starts_with("-----") && !line.is_empty()) + .collect(); + + let der = base64::engine::general_purpose::STANDARD + .decode(&base64_content) + .map_err(|e| format!("Failed to decode certificate base64: {e}"))?; + + certs.push(CertificateDer::from(der)); + } + } + + Ok(certs) +} + +/// Parses a PEM-encoded PKCS#8 private key file and returns the DER-encoded key. +fn parse_pem_private_key(pem_data: &str) -> Result, String> { + let start = pem_data.find(PEM_KEY_BEGIN).ok_or("Missing BEGIN PRIVATE KEY marker")?; + let end = pem_data.find(PEM_KEY_END).ok_or("Missing END PRIVATE KEY marker")?; + + let base64_content: String = pem_data[start + PEM_KEY_BEGIN.len()..end] + .lines() + .filter(|line| !line.starts_with("-----") && !line.is_empty()) + .collect(); + + let der = base64::engine::general_purpose::STANDARD + .decode(&base64_content) + .map_err(|e| format!("Failed to decode private key base64: {e}"))?; + + Ok(PrivateKeyDer::Pkcs8(der.into())) +} + +/// Generates a self-signed TLS certificate and saves it to the storage directory. +/// Returns the paths to the generated cert and key files. +fn generate_self_signed_cert( + cert_path: &str, key_path: &str, configure_hosts: &[String], +) -> Result<(), String> { + let mut hosts = vec!["localhost".to_string(), "127.0.0.1".to_string()]; + hosts.extend_from_slice(configure_hosts); + + let CertifiedKey { cert, key_pair } = generate_simple_self_signed(hosts) + .map_err(|e| format!("Failed to generate self-signed certificate: {e}"))?; + + // Convert DER to PEM format + let cert_der = cert.der(); + let key_der = key_pair.serialize_der(); + + let cert_pem = format!( + "{PEM_CERT_BEGIN}\n{}\n{PEM_CERT_END}\n", + base64::engine::general_purpose::STANDARD + .encode(cert_der) + .as_bytes() + .chunks(64) + .map(|chunk| std::str::from_utf8(chunk).unwrap()) + .collect::>() + .join("\n") + ); + + let key_pem = format!( + "{PEM_KEY_BEGIN}\n{}\n{PEM_KEY_END}\n", + base64::engine::general_purpose::STANDARD + .encode(&key_der) + .as_bytes() + .chunks(64) + .map(|chunk| std::str::from_utf8(chunk).unwrap()) + .collect::>() + .join("\n") + ); + + fs::write(cert_path, &cert_pem) + .map_err(|e| format!("Failed to write TLS certificate to '{cert_path}': {e}"))?; + fs::write(key_path, &key_pem) + .map_err(|e| format!("Failed to write TLS key to '{key_path}': {e}"))?; + + Ok(()) +} + +/// Loads TLS configuration from provided paths. +fn load_tls_config(cert_path: &str, key_path: &str) -> Result { + let cert_pem = fs::read_to_string(cert_path) + .map_err(|e| format!("Failed to read TLS certificate file '{cert_path}': {e}"))?; + let key_pem = fs::read_to_string(key_path) + .map_err(|e| format!("Failed to read TLS key file '{key_path}': {e}"))?; + + let certs = parse_pem_certs(&cert_pem)?; + + if certs.is_empty() { + return Err("No certificates found in certificate file".to_string()); + } + + let key = parse_pem_private_key(&key_pem)?; + + ServerConfig::builder() + .with_no_client_auth() + .with_single_cert(certs, key) + .map_err(|e| format!("Failed to build TLS server config: {e}")) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_pem_certs() { + let pem = "-----BEGIN CERTIFICATE-----\nMIIBkTCB+wIJAKHBfpegPjMCMA0GCSqGSIb3DQEBCwUAMBExDzANBgNVBAMMBnVu\ndXNlZDAeFw0yMzAxMDEwMDAwMDBaFw0yNDAxMDEwMDAwMDBaMBExDzANBgNVBAMM\nBnVudXNlZDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC7o96FCEcJsggt0c0dSfEB\nmm6vv1LdCoxXnhOSCutoJgJgmCPBjU1doFFKwAtXjfOv0eSLZ3NHLu0LRKmVvOsP\nAgMBAAGjUzBRMB0GA1UdDgQWBBQK3fc0myO0psd71FJd8v7VCmDJOzAfBgNVHSME\nGDAWgBQK3fc0myO0psd71FJd8v7VCmDJOzAPBgNVHRMBAf8EBTADAQH/MA0GCSqG\nSIb3DQEBCwUAA0EAhJg0cx2pFfVfGBfbJQNFa+A4ynJBMqKYlbUnJBfWPwg13RhC\nivLjYyhKzEbnOug0TuFfVaUBGfBYbPgaJQ4BAg==\n-----END CERTIFICATE-----\n"; + + let certs = parse_pem_certs(pem).unwrap(); + assert_eq!(certs.len(), 1); + assert!(!certs[0].is_empty()); + } + + #[test] + fn test_parse_pem_certs_multiple() { + let pem = "-----BEGIN CERTIFICATE-----\nMIIBkTCB+wIJAKHBfpegPjMCMA0GCSqGSIb3DQEBCwUAMBExDzANBgNVBAMMBnVu\ndXNlZDAeFw0yMzAxMDEwMDAwMDBaFw0yNDAxMDEwMDAwMDBaMBExDzANBgNVBAMM\nBnVudXNlZDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC7o96FCEcJsggt0c0dSfEB\nmm6vv1LdCoxXnhOSCutoJgJgmCPBjU1doFFKwAtXjfOv0eSLZ3NHLu0LRKmVvOsP\nAgMBAAGjUzBRMB0GA1UdDgQWBBQK3fc0myO0psd71FJd8v7VCmDJOzAfBgNVHSME\nGDAWgBQK3fc0myO0psd71FJd8v7VCmDJOzAPBgNVHRMBAf8EBTADAQH/MA0GCSqG\nSIb3DQEBCwUAA0EAhJg0cx2pFfVfGBfbJQNFa+A4ynJBMqKYlbUnJBfWPwg13RhC\nivLjYyhKzEbnOug0TuFfVaUBGfBYbPgaJQ4BAg==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBkTCB+wIJAKHBfpegPjMCMA0GCSqGSIb3DQEBCwUAMBExDzANBgNVBAMMBnVu\ndXNlZDAeFw0yMzAxMDEwMDAwMDBaFw0yNDAxMDEwMDAwMDBaMBExDzANBgNVBAMM\nBnVudXNlZDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC7o96FCEcJsggt0c0dSfEB\nmm6vv1LdCoxXnhOSCutoJgJgmCPBjU1doFFKwAtXjfOv0eSLZ3NHLu0LRKmVvOsP\nAgMBAAGjUzBRMB0GA1UdDgQWBBQK3fc0myO0psd71FJd8v7VCmDJOzAfBgNVHSME\nGDAWgBQK3fc0myO0psd71FJd8v7VCmDJOzAPBgNVHRMBAf8EBTADAQH/MA0GCSqG\nSIb3DQEBCwUAA0EAhJg0cx2pFfVfGBfbJQNFa+A4ynJBMqKYlbUnJBfWPwg13RhC\nivLjYyhKzEbnOug0TuFfVaUBGfBYbPgaJQ4BAg==\n-----END CERTIFICATE-----\n"; + + let certs = parse_pem_certs(pem).unwrap(); + assert_eq!(certs.len(), 2); + } + + #[test] + fn test_parse_pem_certs_empty() { + let certs = parse_pem_certs("").unwrap(); + assert!(certs.is_empty()); + + let certs = parse_pem_certs("not a cert").unwrap(); + assert!(certs.is_empty()); + } + + #[test] + fn test_parse_pem_private_key_pkcs8() { + let pem = "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg2a2rwplBQLzHPDvn\nsaw8HKDP6WYBSF684gcz+D7zeVShRANCAAQq8R/E45tTNWMEpK8abYM7VzuJxpPS\nhJCi6bzjOPGHawEO8safLOWFaV7GqLJM0OdM3eu/qcz8HwgI3T8EVHQK\n-----END PRIVATE KEY-----\n"; + + let key = parse_pem_private_key(pem).unwrap(); + assert!(matches!(key, PrivateKeyDer::Pkcs8(_))); + } + + #[test] + fn test_parse_pem_private_key_invalid() { + let result = parse_pem_private_key(""); + assert!(result.is_err()); + + let result = parse_pem_private_key("not a key"); + assert!(result.is_err()); + } + + #[test] + fn test_generate_and_load_roundtrip() { + let temp_dir = std::env::temp_dir(); + let suffix: u64 = rand::random(); + let cert_path = temp_dir.join(format!("test_tls_cert_{suffix}.pem")); + let key_path = temp_dir.join(format!("test_tls_key_{suffix}.pem")); + + // Clean up any existing files to be safe + let _ = fs::remove_file(&cert_path); + let _ = fs::remove_file(&key_path); + + // Generate cert + generate_self_signed_cert(cert_path.to_str().unwrap(), key_path.to_str().unwrap(), &[]) + .unwrap(); + + // Verify files exist + assert!(cert_path.exists()); + assert!(key_path.exists()); + + // Load config + let res = load_tls_config(cert_path.to_str().unwrap(), key_path.to_str().unwrap()); + assert!(res.is_ok()); + + // Clean up + let _ = fs::remove_file(&cert_path); + let _ = fs::remove_file(&key_path); + } +} From 813260d9113c3fcaa9d83d33484eec4730957562 Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Fri, 16 Jan 2026 10:18:36 +0100 Subject: [PATCH 183/203] Update `rustfmt.toml` to support `nightly` flags In LDK Node we found a `rustfmt.toml` that enables a few nice `nightly` features (such as automatic import grouping) while being backwards compatible with `rustfmt` stable. That means that in day-to-day we can continue to just do `cargo fmt`, but then have a simple weekly `rustfmt` job that cleans up the codebase a bit more. --- ldk-server/rustfmt.toml | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ldk-server/rustfmt.toml b/ldk-server/rustfmt.toml index 4f88472be..4900e142f 100644 --- a/ldk-server/rustfmt.toml +++ b/ldk-server/rustfmt.toml @@ -4,9 +4,16 @@ hard_tabs = true use_field_init_shorthand = true max_width = 100 match_block_trailing_comma = true -# UNSTABLE: format_code_in_doc_comments = true -# UNSTABLE: overflow_delimited_expr = true -# UNSTABLE: comment_width = 100 -# UNSTABLE: format_macro_matchers = true -# UNSTABLE: format_strings = true -# UNSTABLE: group_imports = "StdExternalCrate" +format_code_in_doc_comments = true +comment_width = 100 +format_macro_matchers = true +group_imports = "StdExternalCrate" +reorder_imports = true +imports_granularity = "Module" +normalize_comments = true +normalize_doc_attributes = true +style_edition = "2021" +# TBD: do we want comment and string wrapping? +#wrap_comments = true +#format_strings = true +#overflow_delimited_expr = true From 2aa1f7bea082d64ea266a51739a78a234423340d Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Fri, 16 Jan 2026 10:27:21 +0100 Subject: [PATCH 184/203] Apply `cargo +nightly fmt` once .. mostly to show the changes. --- ldk-server/ldk-server-client/src/client.rs | 13 +++---- .../ldk-server/src/api/bolt11_receive.rs | 3 +- ldk-server/ldk-server/src/api/bolt11_send.rs | 10 +++--- .../ldk-server/src/api/bolt12_receive.rs | 3 +- ldk-server/ldk-server/src/api/bolt12_send.rs | 10 +++--- .../ldk-server/src/api/close_channel.rs | 10 +++--- ldk-server/ldk-server/src/api/error.rs | 3 +- ldk-server/ldk-server/src/api/get_balances.rs | 3 +- .../ldk-server/src/api/get_node_info.rs | 5 +-- .../ldk-server/src/api/get_payment_details.rs | 7 ++-- .../ldk-server/src/api/list_channels.rs | 3 +- .../src/api/list_forwarded_payments.rs | 9 ++--- .../ldk-server/src/api/list_payments.rs | 9 ++--- ldk-server/ldk-server/src/api/mod.rs | 5 +-- .../ldk-server/src/api/onchain_receive.rs | 3 +- ldk-server/ldk-server/src/api/onchain_send.rs | 8 +++-- ldk-server/ldk-server/src/api/open_channel.rs | 10 +++--- .../ldk-server/src/api/splice_channel.rs | 10 +++--- .../src/api/update_channel_config.rs | 12 ++++--- .../src/io/events/event_publisher.rs | 3 +- .../ldk-server/src/io/events/rabbitmq/mod.rs | 27 +++++++------- .../src/io/persist/sqlite_store/mod.rs | 16 +++++---- ldk-server/ldk-server/src/main.rs | 36 +++++++++---------- ldk-server/ldk-server/src/service.rs | 14 ++++---- ldk-server/ldk-server/src/util/config.rs | 16 +++++---- ldk-server/ldk-server/src/util/logger.rs | 3 +- .../ldk-server/src/util/proto_adapter.rs | 9 ++--- ldk-server/ldk-server/src/util/tls.rs | 6 ++-- 28 files changed, 152 insertions(+), 114 deletions(-) diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index 060f9bd5a..abf3e5ee9 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -7,12 +7,8 @@ // You may not use this file except in accordance with one or both of these // licenses. -use prost::Message; +use std::time::{SystemTime, UNIX_EPOCH}; -use crate::error::LdkServerError; -use crate::error::LdkServerErrorCode::{ - AuthError, InternalError, InternalServerError, InvalidRequestError, LightningError, -}; use bitcoin_hashes::hmac::{Hmac, HmacEngine}; use bitcoin_hashes::{sha256, Hash, HashEngine}; use ldk_server_protos::api::{ @@ -32,9 +28,14 @@ use ldk_server_protos::endpoints::{ OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH, UPDATE_CHANNEL_CONFIG_PATH, }; use ldk_server_protos::error::{ErrorCode, ErrorResponse}; +use prost::Message; use reqwest::header::CONTENT_TYPE; use reqwest::{Certificate, Client}; -use std::time::{SystemTime, UNIX_EPOCH}; + +use crate::error::LdkServerError; +use crate::error::LdkServerErrorCode::{ + AuthError, InternalError, InternalServerError, InvalidRequestError, LightningError, +}; const APPLICATION_OCTET_STREAM: &str = "application/octet-stream"; diff --git a/ldk-server/ldk-server/src/api/bolt11_receive.rs b/ldk-server/ldk-server/src/api/bolt11_receive.rs index ea1d99a28..a5e3bed5b 100644 --- a/ldk-server/ldk-server/src/api/bolt11_receive.rs +++ b/ldk-server/ldk-server/src/api/bolt11_receive.rs @@ -7,10 +7,11 @@ // You may not use this file except in accordance with one or both of these // licenses. +use ldk_server_protos::api::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; + use crate::api::error::LdkServerError; use crate::service::Context; use crate::util::proto_adapter::proto_to_bolt11_description; -use ldk_server_protos::api::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; pub(crate) fn handle_bolt11_receive_request( context: Context, request: Bolt11ReceiveRequest, diff --git a/ldk-server/ldk-server/src/api/bolt11_send.rs b/ldk-server/ldk-server/src/api/bolt11_send.rs index 210004daa..917e3230e 100644 --- a/ldk-server/ldk-server/src/api/bolt11_send.rs +++ b/ldk-server/ldk-server/src/api/bolt11_send.rs @@ -7,13 +7,15 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use std::str::FromStr; + use ldk_node::lightning::routing::router::RouteParametersConfig; use ldk_node::lightning_invoice::Bolt11Invoice; use ldk_server_protos::api::{Bolt11SendRequest, Bolt11SendResponse}; -use std::str::FromStr; + +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; +use crate::service::Context; pub(crate) fn handle_bolt11_send_request( context: Context, request: Bolt11SendRequest, diff --git a/ldk-server/ldk-server/src/api/bolt12_receive.rs b/ldk-server/ldk-server/src/api/bolt12_receive.rs index 4f33d5ef2..cc8875a8d 100644 --- a/ldk-server/ldk-server/src/api/bolt12_receive.rs +++ b/ldk-server/ldk-server/src/api/bolt12_receive.rs @@ -7,9 +7,10 @@ // You may not use this file except in accordance with one or both of these // licenses. +use ldk_server_protos::api::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; + use crate::api::error::LdkServerError; use crate::service::Context; -use ldk_server_protos::api::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; pub(crate) fn handle_bolt12_receive_request( context: Context, request: Bolt12ReceiveRequest, diff --git a/ldk-server/ldk-server/src/api/bolt12_send.rs b/ldk-server/ldk-server/src/api/bolt12_send.rs index a212ca98d..34535a04a 100644 --- a/ldk-server/ldk-server/src/api/bolt12_send.rs +++ b/ldk-server/ldk-server/src/api/bolt12_send.rs @@ -7,13 +7,15 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use std::str::FromStr; + use ldk_node::lightning::offers::offer::Offer; use ldk_node::lightning::routing::router::RouteParametersConfig; use ldk_server_protos::api::{Bolt12SendRequest, Bolt12SendResponse}; -use std::str::FromStr; + +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; +use crate::service::Context; pub(crate) fn handle_bolt12_send_request( context: Context, request: Bolt12SendRequest, diff --git a/ldk-server/ldk-server/src/api/close_channel.rs b/ldk-server/ldk-server/src/api/close_channel.rs index a55b7134a..5ae4070b6 100644 --- a/ldk-server/ldk-server/src/api/close_channel.rs +++ b/ldk-server/ldk-server/src/api/close_channel.rs @@ -7,15 +7,17 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use std::str::FromStr; + use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::UserChannelId; use ldk_server_protos::api::{ CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse, }; -use std::str::FromStr; + +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; +use crate::service::Context; pub(crate) fn handle_close_channel_request( context: Context, request: CloseChannelRequest, diff --git a/ldk-server/ldk-server/src/api/error.rs b/ldk-server/ldk-server/src/api/error.rs index 2a834607b..9117c025c 100644 --- a/ldk-server/ldk-server/src/api/error.rs +++ b/ldk-server/ldk-server/src/api/error.rs @@ -7,9 +7,10 @@ // You may not use this file except in accordance with one or both of these // licenses. -use ldk_node::NodeError; use std::fmt; +use ldk_node::NodeError; + #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct LdkServerError { // The error message containing a generic description of the error condition in English. diff --git a/ldk-server/ldk-server/src/api/get_balances.rs b/ldk-server/ldk-server/src/api/get_balances.rs index dbaa3f55a..82ab69b77 100644 --- a/ldk-server/ldk-server/src/api/get_balances.rs +++ b/ldk-server/ldk-server/src/api/get_balances.rs @@ -7,10 +7,11 @@ // You may not use this file except in accordance with one or both of these // licenses. +use ldk_server_protos::api::{GetBalancesRequest, GetBalancesResponse}; + use crate::api::error::LdkServerError; use crate::service::Context; use crate::util::proto_adapter::{lightning_balance_to_proto, pending_sweep_balance_to_proto}; -use ldk_server_protos::api::{GetBalancesRequest, GetBalancesResponse}; pub(crate) fn handle_get_balances_request( context: Context, _request: GetBalancesRequest, diff --git a/ldk-server/ldk-server/src/api/get_node_info.rs b/ldk-server/ldk-server/src/api/get_node_info.rs index 61cdd1fa2..8599cf208 100644 --- a/ldk-server/ldk-server/src/api/get_node_info.rs +++ b/ldk-server/ldk-server/src/api/get_node_info.rs @@ -7,11 +7,12 @@ // 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_server_protos::api::{GetNodeInfoRequest, GetNodeInfoResponse}; use ldk_server_protos::types::BestBlock; +use crate::api::error::LdkServerError; +use crate::service::Context; + pub(crate) fn handle_get_node_info_request( context: Context, _request: GetNodeInfoRequest, ) -> Result { diff --git a/ldk-server/ldk-server/src/api/get_payment_details.rs b/ldk-server/ldk-server/src/api/get_payment_details.rs index bb0fb8257..1d7b266a4 100644 --- a/ldk-server/ldk-server/src/api/get_payment_details.rs +++ b/ldk-server/ldk-server/src/api/get_payment_details.rs @@ -7,13 +7,14 @@ // You may not use this file except in accordance with one or both of these // licenses. +use hex::FromHex; +use ldk_node::lightning::ln::channelmanager::PaymentId; +use ldk_server_protos::api::{GetPaymentDetailsRequest, GetPaymentDetailsResponse}; + use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; use crate::util::proto_adapter::payment_to_proto; -use hex::FromHex; -use ldk_node::lightning::ln::channelmanager::PaymentId; -use ldk_server_protos::api::{GetPaymentDetailsRequest, GetPaymentDetailsResponse}; pub(crate) fn handle_get_payment_details_request( context: Context, request: GetPaymentDetailsRequest, diff --git a/ldk-server/ldk-server/src/api/list_channels.rs b/ldk-server/ldk-server/src/api/list_channels.rs index cf7cd4ad9..84d1584b9 100644 --- a/ldk-server/ldk-server/src/api/list_channels.rs +++ b/ldk-server/ldk-server/src/api/list_channels.rs @@ -7,10 +7,11 @@ // You may not use this file except in accordance with one or both of these // licenses. +use ldk_server_protos::api::{ListChannelsRequest, ListChannelsResponse}; + use crate::api::error::LdkServerError; use crate::service::Context; use crate::util::proto_adapter::channel_to_proto; -use ldk_server_protos::api::{ListChannelsRequest, ListChannelsResponse}; pub(crate) fn handle_list_channels_request( context: Context, _request: ListChannelsRequest, diff --git a/ldk-server/ldk-server/src/api/list_forwarded_payments.rs b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs index 989e8491e..78ce3dc4e 100644 --- a/ldk-server/ldk-server/src/api/list_forwarded_payments.rs +++ b/ldk-server/ldk-server/src/api/list_forwarded_payments.rs @@ -7,6 +7,11 @@ // You may not use this file except in accordance with one or both of these // licenses. +use bytes::Bytes; +use ldk_server_protos::api::{ListForwardedPaymentsRequest, ListForwardedPaymentsResponse}; +use ldk_server_protos::types::{ForwardedPayment, PageToken}; +use prost::Message; + use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InternalServerError; use crate::io::persist::{ @@ -14,10 +19,6 @@ use crate::io::persist::{ FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, }; use crate::service::Context; -use bytes::Bytes; -use ldk_server_protos::api::{ListForwardedPaymentsRequest, ListForwardedPaymentsResponse}; -use ldk_server_protos::types::{ForwardedPayment, PageToken}; -use prost::Message; pub(crate) fn handle_list_forwarded_payments_request( context: Context, request: ListForwardedPaymentsRequest, diff --git a/ldk-server/ldk-server/src/api/list_payments.rs b/ldk-server/ldk-server/src/api/list_payments.rs index 0077bdab4..fbaf7c557 100644 --- a/ldk-server/ldk-server/src/api/list_payments.rs +++ b/ldk-server/ldk-server/src/api/list_payments.rs @@ -7,16 +7,17 @@ // You may not use this file except in accordance with one or both of these // licenses. +use bytes::Bytes; +use ldk_server_protos::api::{ListPaymentsRequest, ListPaymentsResponse}; +use ldk_server_protos::types::{PageToken, Payment}; +use prost::Message; + use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InternalServerError; use crate::io::persist::{ PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, }; use crate::service::Context; -use bytes::Bytes; -use ldk_server_protos::api::{ListPaymentsRequest, ListPaymentsResponse}; -use ldk_server_protos::types::{PageToken, Payment}; -use prost::Message; pub(crate) fn handle_list_payments_request( context: Context, request: ListPaymentsRequest, diff --git a/ldk-server/ldk-server/src/api/mod.rs b/ldk-server/ldk-server/src/api/mod.rs index b34fef55e..0063d9d8a 100644 --- a/ldk-server/ldk-server/src/api/mod.rs +++ b/ldk-server/ldk-server/src/api/mod.rs @@ -7,11 +7,12 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::InvalidRequestError; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; use ldk_server_protos::types::channel_config::MaxDustHtlcExposure; +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; + pub(crate) mod bolt11_receive; pub(crate) mod bolt11_send; pub(crate) mod bolt12_receive; diff --git a/ldk-server/ldk-server/src/api/onchain_receive.rs b/ldk-server/ldk-server/src/api/onchain_receive.rs index 913c6a8eb..cad2837ed 100644 --- a/ldk-server/ldk-server/src/api/onchain_receive.rs +++ b/ldk-server/ldk-server/src/api/onchain_receive.rs @@ -7,9 +7,10 @@ // You may not use this file except in accordance with one or both of these // licenses. +use ldk_server_protos::api::{OnchainReceiveRequest, OnchainReceiveResponse}; + use crate::api::error::LdkServerError; use crate::service::Context; -use ldk_server_protos::api::{OnchainReceiveRequest, OnchainReceiveResponse}; pub(crate) fn handle_onchain_receive_request( context: Context, _request: OnchainReceiveRequest, diff --git a/ldk-server/ldk-server/src/api/onchain_send.rs b/ldk-server/ldk-server/src/api/onchain_send.rs index efc4f7d09..6eb1d63af 100644 --- a/ldk-server/ldk-server/src/api/onchain_send.rs +++ b/ldk-server/ldk-server/src/api/onchain_send.rs @@ -7,12 +7,14 @@ // You may not use this file except in accordance with one or both of these // licenses. +use std::str::FromStr; + +use ldk_node::bitcoin::{Address, FeeRate}; +use ldk_server_protos::api::{OnchainSendRequest, OnchainSendResponse}; + use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; -use ldk_node::bitcoin::{Address, FeeRate}; -use ldk_server_protos::api::{OnchainSendRequest, OnchainSendResponse}; -use std::str::FromStr; pub(crate) fn handle_onchain_send_request( context: Context, request: OnchainSendRequest, diff --git a/ldk-server/ldk-server/src/api/open_channel.rs b/ldk-server/ldk-server/src/api/open_channel.rs index 53d6ac131..6c470b71c 100644 --- a/ldk-server/ldk-server/src/api/open_channel.rs +++ b/ldk-server/ldk-server/src/api/open_channel.rs @@ -7,14 +7,16 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::api::build_channel_config_from_proto; -use crate::api::error::LdkServerError; -use crate::service::Context; +use std::str::FromStr; + use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::config::ChannelConfig; use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_server_protos::api::{OpenChannelRequest, OpenChannelResponse}; -use std::str::FromStr; + +use crate::api::build_channel_config_from_proto; +use crate::api::error::LdkServerError; +use crate::service::Context; pub(crate) fn handle_open_channel( context: Context, request: OpenChannelRequest, diff --git a/ldk-server/ldk-server/src/api/splice_channel.rs b/ldk-server/ldk-server/src/api/splice_channel.rs index 3710e72d2..5d6edfecd 100644 --- a/ldk-server/ldk-server/src/api/splice_channel.rs +++ b/ldk-server/ldk-server/src/api/splice_channel.rs @@ -7,16 +7,18 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use std::str::FromStr; + use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::bitcoin::Address; use ldk_node::UserChannelId; use ldk_server_protos::api::{ SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse, }; -use std::str::FromStr; + +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; +use crate::service::Context; pub(crate) fn handle_splice_in_request( context: Context, request: SpliceInRequest, diff --git a/ldk-server/ldk-server/src/api/update_channel_config.rs b/ldk-server/ldk-server/src/api/update_channel_config.rs index a80ed739f..780374c5d 100644 --- a/ldk-server/ldk-server/src/api/update_channel_config.rs +++ b/ldk-server/ldk-server/src/api/update_channel_config.rs @@ -7,14 +7,16 @@ // You may not use this file except in accordance with one or both of these // licenses. +use std::str::FromStr; + +use ldk_node::bitcoin::secp256k1::PublicKey; +use ldk_node::UserChannelId; +use ldk_server_protos::api::{UpdateChannelConfigRequest, UpdateChannelConfigResponse}; + use crate::api::build_channel_config_from_proto; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::{InvalidRequestError, LightningError}; use crate::service::Context; -use ldk_node::bitcoin::secp256k1::PublicKey; -use ldk_node::UserChannelId; -use ldk_server_protos::api::{UpdateChannelConfigRequest, UpdateChannelConfigResponse}; -use std::str::FromStr; pub(crate) fn handle_update_channel_config_request( context: Context, request: UpdateChannelConfigRequest, @@ -24,7 +26,7 @@ pub(crate) fn handle_update_channel_config_request( .parse::() .map_err(|_| LdkServerError::new(InvalidRequestError, "Invalid UserChannelId."))?; - //FIXME: Use ldk/ldk-node's partial config update api. + // FIXME: Use ldk/ldk-node's partial config update api. let current_config = context .node .list_channels() diff --git a/ldk-server/ldk-server/src/io/events/event_publisher.rs b/ldk-server/ldk-server/src/io/events/event_publisher.rs index f32678570..308bde257 100644 --- a/ldk-server/ldk-server/src/io/events/event_publisher.rs +++ b/ldk-server/ldk-server/src/io/events/event_publisher.rs @@ -7,10 +7,11 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::api::error::LdkServerError; use async_trait::async_trait; use ldk_server_protos::events::EventEnvelope; +use crate::api::error::LdkServerError; + /// A trait for publishing events or notifications from the LDK Server. /// /// Implementors of this trait define how events are sent to various messaging diff --git a/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs b/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs index 08b0e4b10..a20b5bd96 100644 --- a/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs +++ b/ldk-server/ldk-server/src/io/events/rabbitmq/mod.rs @@ -7,9 +7,8 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::InternalServerError; -use crate::io::events::event_publisher::EventPublisher; +use std::sync::Arc; + use ::prost::Message; use async_trait::async_trait; use lapin::options::{BasicPublishOptions, ConfirmSelectOptions, ExchangeDeclareOptions}; @@ -18,9 +17,12 @@ use lapin::{ BasicProperties, Channel, Connection, ConnectionProperties, ConnectionState, ExchangeKind, }; use ldk_server_protos::events::EventEnvelope; -use std::sync::Arc; use tokio::sync::Mutex; +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::InternalServerError; +use crate::io::events::event_publisher::EventPublisher; + /// A RabbitMQ-based implementation of the EventPublisher trait. pub struct RabbitMqEventPublisher { /// The RabbitMQ connection, used for reconnection logic. @@ -155,19 +157,20 @@ impl EventPublisher for RabbitMqEventPublisher { #[cfg(test)] #[cfg(feature = "integration-tests-events-rabbitmq")] mod integration_tests_events_rabbitmq { - use super::*; - use lapin::{ - options::{BasicAckOptions, BasicConsumeOptions, QueueBindOptions, QueueDeclareOptions}, - types::FieldTable, - Channel, Connection, + use std::io; + use std::time::Duration; + + use futures_util::stream::StreamExt; + use lapin::options::{ + BasicAckOptions, BasicConsumeOptions, QueueBindOptions, QueueDeclareOptions, }; + use lapin::types::FieldTable; + use lapin::{Channel, Connection}; use ldk_server_protos::events::event_envelope::Event; use ldk_server_protos::events::PaymentForwarded; - use std::io; - use std::time::Duration; use tokio; - use futures_util::stream::StreamExt; + use super::*; #[tokio::test] async fn test_publish_and_consume_event() { let config = RabbitMqConfig { diff --git a/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs b/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs index 6217b21aa..a52ffa46d 100644 --- a/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs +++ b/ldk-server/ldk-server/src/io/persist/sqlite_store/mod.rs @@ -7,14 +7,16 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::io::persist::paginated_kv_store::{ListResponse, PaginatedKVStore}; -use crate::io::utils::check_namespace_key_validity; -use ldk_node::lightning::types::string::PrintableString; -use rusqlite::{named_params, Connection}; use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::{fs, io}; +use ldk_node::lightning::types::string::PrintableString; +use rusqlite::{named_params, Connection}; + +use crate::io::persist::paginated_kv_store::{ListResponse, PaginatedKVStore}; +use crate::io::utils::check_namespace_key_validity; + /// The default database file name. pub const DEFAULT_SQLITE_DB_FILE_NAME: &str = "ldk_server_data.sqlite"; @@ -287,11 +289,13 @@ impl PaginatedKVStore for SqliteStore { #[cfg(test)] mod tests { - use super::*; + use std::panic::RefUnwindSafe; + use ldk_node::lightning::util::persist::KVSTORE_NAMESPACE_KEY_MAX_LEN; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; - use std::panic::RefUnwindSafe; + + use super::*; #[test] fn read_write_remove_list_persist() { diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 13cfb51f9..934098f71 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -12,17 +12,28 @@ mod io; mod service; mod util; -use crate::service::NodeService; +use std::fs; +use std::path::{Path, PathBuf}; +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; +use hex::DisplayHex; +use hyper::server::conn::http1; +use hyper_util::rt::TokioIo; +use ldk_node::config::Config; use ldk_node::entropy::NodeEntropy; +use ldk_node::lightning::ln::channelmanager::PaymentId; use ldk_node::{Builder, Event, Node}; - +use ldk_server_protos::events; +use ldk_server_protos::events::{event_envelope, EventEnvelope}; +use ldk_server_protos::types::Payment; +use log::{error, info}; +use prost::Message; +use rand::Rng; use tokio::net::TcpListener; +use tokio::select; use tokio::signal::unix::SignalKind; -use hyper::server::conn::http1; -use hyper_util::rt::TokioIo; - use crate::io::events::event_publisher::EventPublisher; use crate::io::events::get_event_name; #[cfg(feature = "events-rabbitmq")] @@ -34,24 +45,11 @@ use crate::io::persist::{ FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, }; +use crate::service::NodeService; use crate::util::config::{load_config, ChainSource}; use crate::util::logger::ServerLogger; use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto}; use crate::util::tls::get_or_generate_tls_config; -use hex::DisplayHex; -use ldk_node::config::Config; -use ldk_node::lightning::ln::channelmanager::PaymentId; -use ldk_server_protos::events; -use ldk_server_protos::events::{event_envelope, EventEnvelope}; -use ldk_server_protos::types::Payment; -use log::{error, info}; -use prost::Message; -use rand::Rng; -use std::fs; -use std::path::{Path, PathBuf}; -use std::sync::Arc; -use std::time::{SystemTime, UNIX_EPOCH}; -use tokio::select; const USAGE_GUIDE: &str = "Usage: ldk-server "; diff --git a/ldk-server/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index 041997c0e..056b2566e 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/ldk-server/src/service.rs @@ -7,15 +7,17 @@ // You may not use this file except in accordance with one or both of these // licenses. -use ldk_node::bitcoin::hashes::hmac::{Hmac, HmacEngine}; -use ldk_node::bitcoin::hashes::{sha256, Hash, HashEngine}; -use ldk_node::Node; +use std::future::Future; +use std::pin::Pin; +use std::sync::Arc; use http_body_util::{BodyExt, Full, Limited}; use hyper::body::{Bytes, Incoming}; use hyper::service::Service; use hyper::{Request, Response, StatusCode}; - +use ldk_node::bitcoin::hashes::hmac::{Hmac, HmacEngine}; +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, @@ -23,7 +25,6 @@ use ldk_server_protos::endpoints::{ ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH, UPDATE_CHANNEL_CONFIG_PATH, }; - use prost::Message; use crate::api::bolt11_receive::handle_bolt11_receive_request; @@ -46,9 +47,6 @@ use crate::api::splice_channel::{handle_splice_in_request, handle_splice_out_req use crate::api::update_channel_config::handle_update_channel_config_request; use crate::io::persist::paginated_kv_store::PaginatedKVStore; use crate::util::proto_adapter::to_error_response; -use std::future::Future; -use std::pin::Pin; -use std::sync::Arc; // Maximum request body size: 10 MB // This prevents memory exhaustion from large requests diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 2128f7842..b3fb42778 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -7,16 +7,17 @@ // You may not use this file except in accordance with one or both of these // licenses. +use std::net::SocketAddr; +use std::path::Path; +use std::str::FromStr; +use std::{fs, io}; + use ldk_node::bitcoin::Network; use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_node::lightning::routing::gossip::NodeAlias; use ldk_node::liquidity::LSPS2ServiceConfig; use log::LevelFilter; use serde::{Deserialize, Serialize}; -use std::net::SocketAddr; -use std::path::Path; -use std::str::FromStr; -use std::{fs, io}; /// Configuration for LDK Server. #[derive(Debug)] @@ -315,10 +316,13 @@ pub fn load_config>(config_path: P) -> io::Result { #[cfg(test)] mod tests { - use super::*; - use ldk_node::{bitcoin::Network, lightning::ln::msgs::SocketAddress}; use std::str::FromStr; + use ldk_node::bitcoin::Network; + use ldk_node::lightning::ln::msgs::SocketAddress; + + use super::*; + #[test] fn test_read_toml_config_from_file() { let storage_path = std::env::temp_dir(); diff --git a/ldk-server/ldk-server/src/util/logger.rs b/ldk-server/ldk-server/src/util/logger.rs index d0c5e2455..5e27a98da 100644 --- a/ldk-server/ldk-server/src/util/logger.rs +++ b/ldk-server/ldk-server/src/util/logger.rs @@ -7,12 +7,13 @@ // You may not use this file except in accordance with one or both of these // licenses. -use log::{Level, LevelFilter, Log, Metadata, Record}; use std::fs::{self, File, OpenOptions}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; +use log::{Level, LevelFilter, Log, Metadata, Record}; + /// A logger implementation that writes logs to both stderr and a file. /// /// The logger formats log messages with RFC3339 timestamps and writes them to: diff --git a/ldk-server/ldk-server/src/util/proto_adapter.rs b/ldk-server/ldk-server/src/util/proto_adapter.rs index 6e42a881f..2eece4819 100644 --- a/ldk-server/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/ldk-server/src/util/proto_adapter.rs @@ -7,10 +7,6 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::{ - AuthError, InternalServerError, InvalidRequestError, LightningError, -}; use bytes::Bytes; use hex::prelude::*; use hyper::StatusCode; @@ -39,6 +35,11 @@ use ldk_server_protos::types::{ bolt11_invoice_description, Channel, ForwardedPayment, LspFeeLimits, OutPoint, Payment, }; +use crate::api::error::LdkServerError; +use crate::api::error::LdkServerErrorCode::{ + AuthError, InternalServerError, InvalidRequestError, LightningError, +}; + pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { Channel { channel_id: channel.channel_id.0.to_lower_hex_string(), diff --git a/ldk-server/ldk-server/src/util/tls.rs b/ldk-server/ldk-server/src/util/tls.rs index 41a9dd7a0..c0d65fc72 100644 --- a/ldk-server/ldk-server/src/util/tls.rs +++ b/ldk-server/ldk-server/src/util/tls.rs @@ -7,13 +7,15 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::util::config::TlsConfig; +use std::fs; + use base64::Engine; use rcgen::{generate_simple_self_signed, CertifiedKey}; -use std::fs; use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer}; use tokio_rustls::rustls::ServerConfig; +use crate::util::config::TlsConfig; + // PEM markers const PEM_CERT_BEGIN: &str = "-----BEGIN CERTIFICATE-----"; const PEM_CERT_END: &str = "-----END CERTIFICATE-----"; From cdf90c2675047e8d2fe0adaa16fffca361d93b04 Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Fri, 16 Jan 2026 10:28:05 +0100 Subject: [PATCH 185/203] Add weekly CI job running `cargo +nightly fmt` --- .../.github/workflows/cron-weekly-rustfmt.yml | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 ldk-server/.github/workflows/cron-weekly-rustfmt.yml diff --git a/ldk-server/.github/workflows/cron-weekly-rustfmt.yml b/ldk-server/.github/workflows/cron-weekly-rustfmt.yml new file mode 100644 index 000000000..d6326f03b --- /dev/null +++ b/ldk-server/.github/workflows/cron-weekly-rustfmt.yml @@ -0,0 +1,33 @@ +name: Nightly rustfmt + +permissions: + contents: write + pull-requests: write + +on: + schedule: + - cron: "0 0 * * 0" # runs weekly on Sunday at 00:00 + workflow_dispatch: # allows manual triggering +jobs: + format: + name: Nightly rustfmt + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v5 + - uses: dtolnay/rust-toolchain@nightly + with: + components: rustfmt + - name: Run Nightly rustfmt + # Run the formatter and manually remove trailing whitespace. + run: cargo +nightly fmt && git ls-files -- '*.rs' -z | xargs sed -E -i'' -e 's/[[:space:]]+$//' + - name: Get the current date + run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_ENV + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + author: Fmt Bot + title: Automated nightly rustfmt (${{ env.date }}) + body: | + Automated nightly `rustfmt` changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action + commit-message: ${{ env.date }} automated rustfmt nightly + labels: rustfmt From e2ac23298ae84ba946e7966fa55b23398173ba07 Mon Sep 17 00:00:00 2001 From: Fmt Bot Date: Sun, 18 Jan 2026 01:53:16 +0000 Subject: [PATCH 186/203] 2026-01-18 automated rustfmt nightly --- ldk-server/ldk-server/src/util/config.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index b3fb42778..4044f6a92 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -354,7 +354,7 @@ mod tests { [rabbitmq] connection_string = "rabbitmq_connection_string" exchange_name = "rabbitmq_exchange_name" - + [liquidity.lsps2_service] advertise_service = false channel_opening_fee_ppm = 1000 # 0.1% fee @@ -495,7 +495,7 @@ mod tests { [rabbitmq] connection_string = "rabbitmq_connection_string" exchange_name = "rabbitmq_exchange_name" - + [liquidity.lsps2_service] advertise_service = false channel_opening_fee_ppm = 1000 # 0.1% fee @@ -547,7 +547,7 @@ mod tests { [rabbitmq] connection_string = "rabbitmq_connection_string" exchange_name = "rabbitmq_exchange_name" - + [liquidity.lsps2_service] advertise_service = false channel_opening_fee_ppm = 1000 # 0.1% fee From 4434bc3f7709e01915462597ce7bb77a35260c29 Mon Sep 17 00:00:00 2001 From: Leo Nash Date: Sun, 18 Jan 2026 03:00:55 +0000 Subject: [PATCH 187/203] Add announcement addresses setting --- ldk-server/ldk-server/ldk-server-config.toml | 1 + ldk-server/ldk-server/src/main.rs | 1 + ldk-server/ldk-server/src/util/config.rs | 23 ++++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml index f4485e9d9..8e6c2681e 100644 --- a/ldk-server/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -2,6 +2,7 @@ [node] network = "regtest" # Bitcoin network to use listening_address = "localhost:3001" # Lightning node listening address +announcement_addresses = ["54.3.7.81:3001"] # Lightning node announcement addresses rest_service_address = "127.0.0.1:3002" # LDK Server REST address api_key = "your-secret-api-key" # API key for authenticating REST requests diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 934098f71..393dc2775 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -102,6 +102,7 @@ fn main() { ldk_node_config.storage_dir_path = config_file.storage_dir_path.clone(); ldk_node_config.listening_addresses = Some(vec![config_file.listening_addr]); + ldk_node_config.announcement_addresses = config_file.announcement_addrs; ldk_node_config.network = config_file.network; let mut builder = Builder::from_config(ldk_node_config); diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 4044f6a92..8c4204e49 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -23,6 +23,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug)] pub struct Config { pub listening_addr: SocketAddress, + pub announcement_addrs: Option>, pub alias: Option, pub network: Network, pub api_key: String, @@ -62,6 +63,23 @@ impl TryFrom for Config { format!("Invalid listening address configured: {}", e), ) })?; + let announcement_addrs = toml_config + .node + .announcement_addresses + .map(|addresses| { + addresses + .into_iter() + .map(|addr| { + SocketAddress::from_str(&addr).map_err(|e| { + io::Error::new( + io::ErrorKind::InvalidInput, + format!("Invalid announcement address configured: {}", e), + ) + }) + }) + .collect() + }) + .transpose()?; let rest_service_addr = SocketAddr::from_str(&toml_config.node.rest_service_address) .map_err(|e| { io::Error::new( @@ -162,6 +180,7 @@ impl TryFrom for Config { Ok(Config { listening_addr, + announcement_addrs, network: toml_config.node.network, alias, rest_service_addr, @@ -196,6 +215,7 @@ pub struct TomlConfig { struct NodeConfig { network: Network, listening_address: String, + announcement_addresses: Option>, rest_service_address: String, alias: Option, api_key: String, @@ -332,6 +352,7 @@ mod tests { [node] network = "regtest" listening_address = "localhost:3001" + announcement_addresses = ["54.3.7.81:3001"] rest_service_address = "127.0.0.1:3002" alias = "LDK Server" api_key = "test_api_key" @@ -376,6 +397,7 @@ mod tests { let config = load_config(storage_path.join(config_file_name)).unwrap(); let expected = Config { listening_addr: SocketAddress::from_str("localhost:3001").unwrap(), + announcement_addrs: Some(vec![SocketAddress::from_str("54.3.7.81:3001").unwrap()]), alias: Some(NodeAlias(bytes)), network: Network::Regtest, rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(), @@ -408,6 +430,7 @@ mod tests { }; assert_eq!(config.listening_addr, expected.listening_addr); + assert_eq!(config.announcement_addrs, expected.announcement_addrs); assert_eq!(config.network, expected.network); assert_eq!(config.rest_service_addr, expected.rest_service_addr); assert_eq!(config.api_key, expected.api_key); From 36ef61816b97090a946ca29d3c7fa7d99e503d65 Mon Sep 17 00:00:00 2001 From: Leo Nash Date: Sun, 18 Jan 2026 04:32:16 +0000 Subject: [PATCH 188/203] Make listening addresses optional, and allow multiple to be set --- ldk-server/ldk-server/ldk-server-config.toml | 2 +- ldk-server/ldk-server/src/main.rs | 2 +- ldk-server/ldk-server/src/util/config.rs | 39 ++++++++++++-------- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml index 8e6c2681e..3f60a5a89 100644 --- a/ldk-server/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -1,7 +1,7 @@ # Lightning node settings [node] network = "regtest" # Bitcoin network to use -listening_address = "localhost:3001" # Lightning node listening address +listening_addresses = ["localhost:3001"] # Lightning node listening addresses announcement_addresses = ["54.3.7.81:3001"] # Lightning node announcement addresses rest_service_address = "127.0.0.1:3002" # LDK Server REST address api_key = "your-secret-api-key" # API key for authenticating REST requests diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 393dc2775..038b2198f 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -101,7 +101,7 @@ fn main() { }; ldk_node_config.storage_dir_path = config_file.storage_dir_path.clone(); - ldk_node_config.listening_addresses = Some(vec![config_file.listening_addr]); + ldk_node_config.listening_addresses = config_file.listening_addrs; ldk_node_config.announcement_addresses = config_file.announcement_addrs; ldk_node_config.network = config_file.network; diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 8c4204e49..348224354 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize}; /// Configuration for LDK Server. #[derive(Debug)] pub struct Config { - pub listening_addr: SocketAddress, + pub listening_addrs: Option>, pub announcement_addrs: Option>, pub alias: Option, pub network: Network, @@ -56,13 +56,23 @@ impl TryFrom for Config { type Error = io::Error; fn try_from(toml_config: TomlConfig) -> io::Result { - let listening_addr = - SocketAddress::from_str(&toml_config.node.listening_address).map_err(|e| { - io::Error::new( - io::ErrorKind::InvalidInput, - format!("Invalid listening address configured: {}", e), - ) - })?; + let listening_addrs = toml_config + .node + .listening_addresses + .map(|addresses| { + addresses + .into_iter() + .map(|addr| { + SocketAddress::from_str(&addr).map_err(|e| { + io::Error::new( + io::ErrorKind::InvalidInput, + format!("Invalid listening address configured: {}", e), + ) + }) + }) + .collect() + }) + .transpose()?; let announcement_addrs = toml_config .node .announcement_addresses @@ -179,7 +189,7 @@ impl TryFrom for Config { }); Ok(Config { - listening_addr, + listening_addrs, announcement_addrs, network: toml_config.node.network, alias, @@ -214,7 +224,7 @@ pub struct TomlConfig { #[derive(Deserialize, Serialize)] struct NodeConfig { network: Network, - listening_address: String, + listening_addresses: Option>, announcement_addresses: Option>, rest_service_address: String, alias: Option, @@ -351,7 +361,7 @@ mod tests { let toml_config = r#" [node] network = "regtest" - listening_address = "localhost:3001" + listening_addresses = ["localhost:3001"] announcement_addresses = ["54.3.7.81:3001"] rest_service_address = "127.0.0.1:3002" alias = "LDK Server" @@ -396,7 +406,7 @@ mod tests { let config = load_config(storage_path.join(config_file_name)).unwrap(); let expected = Config { - listening_addr: SocketAddress::from_str("localhost:3001").unwrap(), + listening_addrs: Some(vec![SocketAddress::from_str("localhost:3001").unwrap()]), announcement_addrs: Some(vec![SocketAddress::from_str("54.3.7.81:3001").unwrap()]), alias: Some(NodeAlias(bytes)), network: Network::Regtest, @@ -429,7 +439,7 @@ mod tests { log_file_path: Some("/var/log/ldk-server.log".to_string()), }; - assert_eq!(config.listening_addr, expected.listening_addr); + assert_eq!(config.listening_addrs, expected.listening_addrs); assert_eq!(config.announcement_addrs, expected.announcement_addrs); assert_eq!(config.network, expected.network); assert_eq!(config.rest_service_addr, expected.rest_service_addr); @@ -453,7 +463,6 @@ mod tests { let toml_config = r#" [node] network = "regtest" - listening_address = "localhost:3001" rest_service_address = "127.0.0.1:3002" alias = "LDK Server" api_key = "test_api_key" @@ -498,7 +507,6 @@ mod tests { let toml_config = r#" [node] network = "regtest" - listening_address = "localhost:3001" rest_service_address = "127.0.0.1:3002" alias = "LDK Server" api_key = "test_api_key" @@ -547,7 +555,6 @@ mod tests { let toml_config = r#" [node] network = "regtest" - listening_address = "localhost:3001" rest_service_address = "127.0.0.1:3002" alias = "LDK Server" api_key = "test_api_key" From 15685c867963319fcb5ce91e61de614c3818c949 Mon Sep 17 00:00:00 2001 From: Leo Nash Date: Sun, 18 Jan 2026 03:24:15 +0000 Subject: [PATCH 189/203] Add coverage for a few more fields in `load_config` --- ldk-server/ldk-server/src/util/config.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 348224354..29690845b 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -441,6 +441,7 @@ mod tests { assert_eq!(config.listening_addrs, expected.listening_addrs); assert_eq!(config.announcement_addrs, expected.announcement_addrs); + assert_eq!(config.alias, expected.alias); assert_eq!(config.network, expected.network); assert_eq!(config.rest_service_addr, expected.rest_service_addr); assert_eq!(config.api_key, expected.api_key); @@ -457,6 +458,8 @@ mod tests { assert_eq!(config.rabbitmq_exchange_name, expected.rabbitmq_exchange_name); #[cfg(feature = "experimental-lsps2-support")] assert_eq!(config.lsps2_service_config.is_some(), expected.lsps2_service_config.is_some()); + assert_eq!(config.log_level, expected.log_level); + assert_eq!(config.log_file_path, expected.log_file_path); // Test case where only electrum is set From 55ce9cd462edf60b588946eb8d56ecf39274cace Mon Sep 17 00:00:00 2001 From: Leo Nash Date: Sun, 18 Jan 2026 03:36:50 +0000 Subject: [PATCH 190/203] Fix comment in the configuration file --- ldk-server/ldk-server/ldk-server-config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml index 3f60a5a89..f7ada16b9 100644 --- a/ldk-server/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -19,7 +19,7 @@ file_path = "/tmp/ldk-server/ldk-server.log" # Log file path #key_path = "/path/to/tls.key" # Path to TLS private key, by default uses dir_path/tls.key hosts = ["example.com"] # Allowed hosts for TLS, will always include "localhost" and "127.0.0.1" -# Must set either bitcoind or esplora settings, but not both +# Must set one of bitcoind, electrum, or esplora # Bitcoin Core settings [bitcoind] From 19c625b07deda02c89649c0ddb3e88197aeec3a8 Mon Sep 17 00:00:00 2001 From: Leo Nash Date: Mon, 19 Jan 2026 03:31:55 +0000 Subject: [PATCH 191/203] Correct the name of the file path setting to the expected one Now the setting in the example configuration file gets read correctly. --- ldk-server/ldk-server/ldk-server-config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml index f7ada16b9..0c2658e78 100644 --- a/ldk-server/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -12,7 +12,7 @@ dir_path = "/tmp/ldk-server/" # Path for LDK and BDK data persis [log] level = "Debug" # Log level (Error, Warn, Info, Debug, Trace) -file_path = "/tmp/ldk-server/ldk-server.log" # Log file path +file = "/tmp/ldk-server/ldk-server.log" # Log file path [tls] #cert_path = "/path/to/tls.crt" # Path to TLS certificate, by default uses dir_path/tls.crt From 316403e6c7071424cca561eb1d7e678b4959b56b Mon Sep 17 00:00:00 2001 From: Leo Nash Date: Mon, 19 Jan 2026 03:40:21 +0000 Subject: [PATCH 192/203] Correct the name of the TLS cert file in comments and help messages --- ldk-server/ldk-server-cli/src/main.rs | 2 +- ldk-server/ldk-server-client/src/client.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index fb9559cef..504b6da09 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -53,7 +53,7 @@ struct Cli { short, long, required(true), - help = "Path to the server's TLS certificate file (PEM format). Found at /tls_cert.pem" + help = "Path to the server's TLS certificate file (PEM format). Found at /tls.crt" )] tls_cert: String, diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index abf3e5ee9..f0509ab51 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -42,7 +42,7 @@ const APPLICATION_OCTET_STREAM: &str = "application/octet-stream"; /// Client to access a hosted instance of LDK Server. /// /// The client requires the server's TLS certificate to be provided for verification. -/// This certificate can be found at `/tls_cert.pem` after the +/// This certificate can be found at `/tls.crt` after the /// server generates it on first startup. #[derive(Clone)] pub struct LdkServerClient { @@ -57,7 +57,7 @@ impl LdkServerClient { /// `base_url` should not include the scheme, e.g., `localhost:3000`. /// `api_key` is used for HMAC-based authentication. /// `server_cert_pem` is the server's TLS certificate in PEM format. This can be - /// found at `/tls_cert.pem` after the server starts. + /// found at `/tls.crt` after the server starts. pub fn new(base_url: String, api_key: String, server_cert_pem: &[u8]) -> Result { let cert = Certificate::from_pem(server_cert_pem) .map_err(|e| format!("Failed to parse server certificate: {e}"))?; From 901902d8033c127917ad760cbafe907309992e99 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Wed, 14 Jan 2026 14:46:37 -0600 Subject: [PATCH 193/203] Create default data directory at ~/.ldk-server Previously, the daemon required a config file path argument and the CLI required explicit --api-key and --tls-cert flags. Now both default to reading from ~/.ldk-server/config.toml, so you can just run the daemon and CLI without having to specify any flags. We make sure to separate out data by network so we don't conflict anywhere and accidentally lose anything important --- ldk-server/Cargo.lock | 2 + ldk-server/ldk-server-cli/Cargo.toml | 2 + ldk-server/ldk-server-cli/src/config.rs | 81 ++++++++++ ldk-server/ldk-server-cli/src/main.rs | 78 ++++++++-- ldk-server/ldk-server/ldk-server-config.toml | 3 +- ldk-server/ldk-server/src/main.rs | 146 +++++++++++++++---- ldk-server/ldk-server/src/util/config.rs | 21 +-- 7 files changed, 276 insertions(+), 57 deletions(-) create mode 100644 ldk-server/ldk-server-cli/src/config.rs diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index a77173748..bb849fd7c 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -1760,10 +1760,12 @@ name = "ldk-server-cli" version = "0.1.0" dependencies = [ "clap", + "hex-conservative 0.2.1", "ldk-server-client", "serde", "serde_json", "tokio", + "toml", ] [[package]] diff --git a/ldk-server/ldk-server-cli/Cargo.toml b/ldk-server/ldk-server-cli/Cargo.toml index bc77d1d4a..2ac0c4cf9 100644 --- a/ldk-server/ldk-server-cli/Cargo.toml +++ b/ldk-server/ldk-server-cli/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" [dependencies] ldk-server-client = { path = "../ldk-server-client", features = ["serde"] } clap = { version = "4.0.5", default-features = false, features = ["derive", "std", "error-context", "suggestions", "help"] } +hex-conservative = { version = "0.2", default-features = false, features = ["std"] } tokio = { version = "1.38.0", default-features = false, features = ["rt-multi-thread", "macros"] } serde = "1.0" serde_json = "1.0" +toml = { version = "0.8", default-features = false, features = ["parse"] } diff --git a/ldk-server/ldk-server-cli/src/config.rs b/ldk-server/ldk-server-cli/src/config.rs new file mode 100644 index 000000000..3158ac591 --- /dev/null +++ b/ldk-server/ldk-server-cli/src/config.rs @@ -0,0 +1,81 @@ +// 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 serde::{Deserialize, Serialize}; +use std::path::PathBuf; + +const DEFAULT_CONFIG_FILE: &str = "config.toml"; +const DEFAULT_CERT_FILE: &str = "tls.crt"; +const API_KEY_FILE: &str = "api_key"; + +pub fn get_default_data_dir() -> Option { + #[cfg(target_os = "macos")] + { + #[allow(deprecated)] // todo can remove once we update MSRV to 1.87+ + std::env::home_dir().map(|home| home.join("Library/Application Support/ldk-server")) + } + #[cfg(target_os = "windows")] + { + std::env::var("APPDATA").ok().map(|appdata| PathBuf::from(appdata).join("ldk-server")) + } + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + { + #[allow(deprecated)] // todo can remove once we update MSRV to 1.87+ + std::env::home_dir().map(|home| home.join(".ldk-server")) + } +} + +pub fn get_default_config_path() -> Option { + get_default_data_dir().map(|dir| dir.join(DEFAULT_CONFIG_FILE)) +} + +pub fn get_default_cert_path() -> Option { + get_default_data_dir().map(|path| path.join(DEFAULT_CERT_FILE)) +} + +pub fn get_default_api_key_path(network: &str) -> Option { + get_default_data_dir().map(|path| path.join(network).join(API_KEY_FILE)) +} + +#[derive(Debug, Deserialize)] +pub struct Config { + pub node: NodeConfig, + pub tls: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct TlsConfig { + pub cert_path: Option, +} + +#[derive(Debug, Deserialize)] +pub struct NodeConfig { + pub rest_service_address: String, + network: String, +} + +impl Config { + pub fn network(&self) -> Result { + match self.node.network.as_str() { + "bitcoin" | "mainnet" => Ok("bitcoin".to_string()), + "testnet" => Ok("testnet".to_string()), + "testnet4" => Ok("testnet4".to_string()), + "signet" => Ok("signet".to_string()), + "regtest" => Ok("regtest".to_string()), + other => Err(format!("Unsupported network: {other}")), + } + } +} + +pub fn load_config(path: &PathBuf) -> Result { + let contents = std::fs::read_to_string(path) + .map_err(|e| format!("Failed to read config file '{}': {}", path.display(), e))?; + toml::from_str(&contents) + .map_err(|e| format!("Failed to parse config file '{}': {}", path.display(), e)) +} diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 504b6da09..fae510bbf 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -8,6 +8,10 @@ // licenses. use clap::{Parser, Subcommand}; +use config::{ + get_default_api_key_path, get_default_cert_path, get_default_config_path, load_config, +}; +use hex_conservative::DisplayHex; use ldk_server_client::client::LdkServerClient; use ldk_server_client::error::LdkServerError; use ldk_server_client::error::LdkServerErrorCode::{ @@ -28,8 +32,10 @@ use ldk_server_client::ldk_server_protos::types::{ RouteParametersConfig, }; use serde::Serialize; +use std::path::PathBuf; use types::CliListPaymentsResponse; +mod config; mod types; // Having these default values as constants in the Proto file and @@ -43,19 +49,25 @@ const DEFAULT_EXPIRY_SECS: u32 = 86_400; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Cli { - #[arg(short, long, default_value = "localhost:3000")] - base_url: String, + #[arg(short, long, help = "Base URL of the server. If not provided, reads from config file")] + base_url: Option, - #[arg(short, long, required(true))] - api_key: String, + #[arg( + short, + long, + help = "API key for authentication. Defaults by reading ~/.ldk-server/[network]/api_key" + )] + api_key: Option, #[arg( short, long, - required(true), - help = "Path to the server's TLS certificate file (PEM format). Found at /tls.crt" + help = "Path to the server's TLS certificate file (PEM format). Defaults to ~/.ldk-server/tls.crt" )] - tls_cert: String, + tls_cert: Option, + + #[arg(short, long, help = "Path to config file. Defaults to ~/.ldk-server/config.toml")] + config: Option, #[command(subcommand)] command: Commands, @@ -226,18 +238,54 @@ enum Commands { async fn main() { let cli = Cli::parse(); - // Load server certificate for TLS verification - let server_cert_pem = std::fs::read(&cli.tls_cert).unwrap_or_else(|e| { - eprintln!("Failed to read server certificate file '{}': {}", cli.tls_cert, e); - std::process::exit(1); - }); + let config_path = cli.config.map(PathBuf::from).or_else(get_default_config_path); + let config = config_path.as_ref().and_then(|p| load_config(p).ok()); - let client = - LdkServerClient::new(cli.base_url, cli.api_key, &server_cert_pem).unwrap_or_else(|e| { - eprintln!("Failed to create client: {e}"); + // Get API key from argument, then from api_key file + let api_key = cli + .api_key + .or_else(|| { + // Try to read from api_key file based on network (file contains raw bytes) + let network = config.as_ref().and_then(|c| c.network().ok()).unwrap_or("bitcoin".to_string()); + get_default_api_key_path(&network) + .and_then(|path| std::fs::read(&path).ok()) + .map(|bytes| bytes.to_lower_hex_string()) + }) + .unwrap_or_else(|| { + eprintln!("API key not provided. Use --api-key or ensure the api_key file exists at ~/.ldk-server/[network]/api_key"); std::process::exit(1); }); + // Get base URL from argument then from config file + let base_url = + cli.base_url.or_else(|| config.as_ref().map(|c| c.node.rest_service_address.clone())) + .unwrap_or_else(|| { + eprintln!("Base URL not provided. Use --base-url or ensure config file exists at ~/.ldk-server/config.toml"); + std::process::exit(1); + }); + + // Get TLS cert path from argument, then from config file, then try default location + let tls_cert_path = cli.tls_cert.map(PathBuf::from).or_else(|| { + config + .as_ref() + .and_then(|c| c.tls.as_ref().and_then(|t| t.cert_path.as_ref().map(PathBuf::from))) + .or_else(get_default_cert_path) + }) + .unwrap_or_else(|| { + eprintln!("TLS cert path not provided. Use --tls-cert or ensure config file exists at ~/.ldk-server/config.toml"); + std::process::exit(1); + }); + + let server_cert_pem = std::fs::read(&tls_cert_path).unwrap_or_else(|e| { + eprintln!("Failed to read server certificate file '{}': {}", tls_cert_path.display(), e); + std::process::exit(1); + }); + + let client = LdkServerClient::new(base_url, api_key, &server_cert_pem).unwrap_or_else(|e| { + eprintln!("Failed to create client: {e}"); + std::process::exit(1); + }); + match cli.command { Commands::GetNodeInfo => { handle_response_result::<_, GetNodeInfoResponse>( diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml index 0c2658e78..3c31cbcb7 100644 --- a/ldk-server/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -4,11 +4,10 @@ network = "regtest" # Bitcoin network to use listening_addresses = ["localhost:3001"] # Lightning node listening addresses announcement_addresses = ["54.3.7.81:3001"] # Lightning node announcement addresses rest_service_address = "127.0.0.1:3002" # LDK Server REST address -api_key = "your-secret-api-key" # API key for authenticating REST requests # Storage settings [storage.disk] -dir_path = "/tmp/ldk-server/" # Path for LDK and BDK data persistence +dir_path = "/tmp/ldk-server/" # Path for LDK and BDK data persistence, optional, defaults to ~/.ldk-server/ [log] level = "Debug" # Log level (Error, Warn, Info, Debug, Trace) diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index 038b2198f..acc1a9b61 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -13,6 +13,7 @@ mod service; mod util; use std::fs; +use std::os::unix::fs::PermissionsExt; use std::path::{Path, PathBuf}; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; @@ -20,6 +21,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use hex::DisplayHex; use hyper::server::conn::http1; use hyper_util::rt::TokioIo; +use ldk_node::bitcoin::Network; use ldk_node::config::Config; use ldk_node::entropy::NodeEntropy; use ldk_node::lightning::ln::channelmanager::PaymentId; @@ -27,7 +29,7 @@ use ldk_node::{Builder, Event, Node}; use ldk_server_protos::events; use ldk_server_protos::events::{event_envelope, EventEnvelope}; use ldk_server_protos::types::Payment; -use log::{error, info}; +use log::{debug, error, info}; use prost::Message; use rand::Rng; use tokio::net::TcpListener; @@ -51,29 +53,65 @@ use crate::util::logger::ServerLogger; use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto}; use crate::util::tls::get_or_generate_tls_config; -const USAGE_GUIDE: &str = "Usage: ldk-server "; +const DEFAULT_CONFIG_FILE: &str = "config.toml"; +const API_KEY_FILE: &str = "api_key"; + +fn get_default_data_dir() -> Option { + #[cfg(target_os = "macos")] + { + #[allow(deprecated)] // todo can remove once we update MSRV to 1.87+ + std::env::home_dir().map(|home| home.join("Library/Application Support/ldk-server")) + } + #[cfg(target_os = "windows")] + { + std::env::var("APPDATA").ok().map(|appdata| PathBuf::from(appdata).join("ldk-server")) + } + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + { + #[allow(deprecated)] // todo can remove once we update MSRV to 1.87+ + std::env::home_dir().map(|home| home.join(".ldk-server")) + } +} + +fn get_default_config_path() -> Option { + get_default_data_dir().map(|data_dir| data_dir.join(DEFAULT_CONFIG_FILE)) +} + +const USAGE_GUIDE: &str = "Usage: ldk-server [config_path] + +If no config path is provided, ldk-server will look for a config file at: + Linux: ~/.ldk-server/config.toml + macOS: ~/Library/Application Support/ldk-server/config.toml + Windows: %APPDATA%\\ldk-server\\config.toml"; fn main() { let args: Vec = std::env::args().collect(); - if args.len() < 2 { - eprintln!("{USAGE_GUIDE}"); - std::process::exit(-1); - } - - let arg = args[1].as_str(); - if arg == "-h" || arg == "--help" { - println!("{}", USAGE_GUIDE); - std::process::exit(0); - } + let config_path: PathBuf = if args.len() < 2 { + match get_default_config_path() { + Some(path) => path, + None => { + eprintln!("Unable to determine home directory for default config path."); + eprintln!("{USAGE_GUIDE}"); + std::process::exit(-1); + }, + } + } else { + let arg = args[1].as_str(); + if arg == "-h" || arg == "--help" { + println!("{USAGE_GUIDE}"); + std::process::exit(0); + } + PathBuf::from(arg) + }; - if fs::File::open(arg).is_err() { - eprintln!("Unable to access configuration file."); + if fs::File::open(&config_path).is_err() { + eprintln!("Unable to access configuration file: {}", config_path.display()); std::process::exit(-1); } let mut ldk_node_config = Config::default(); - let config_file = match load_config(Path::new(arg)) { + let config_file = match load_config(&config_path) { Ok(config) => config, Err(e) => { eprintln!("Invalid configuration file: {}", e); @@ -81,13 +119,38 @@ fn main() { }, }; + let storage_dir: PathBuf = match config_file.storage_dir_path { + None => { + let default = get_default_data_dir(); + match default { + Some(path) => { + info!("No storage_dir_path configured, defaulting to {}", path.display()); + path + }, + None => { + eprintln!("Unable to determine home directory for default storage path."); + std::process::exit(-1); + }, + } + }, + Some(configured_path) => PathBuf::from(configured_path), + }; + + let network_dir: PathBuf = match config_file.network { + Network::Bitcoin => storage_dir.join("bitcoin"), + Network::Testnet => storage_dir.join("testnet"), + Network::Testnet4 => storage_dir.join("testnet4"), + Network::Signet => storage_dir.join("signet"), + Network::Regtest => storage_dir.join("regtest"), + }; + let log_file_path = config_file.log_file_path.map(PathBuf::from).unwrap_or_else(|| { - let mut default_log_path = PathBuf::from(&config_file.storage_dir_path); + let mut default_log_path = network_dir.clone(); default_log_path.push("ldk-server.log"); default_log_path }); - if log_file_path == PathBuf::from(&config_file.storage_dir_path) { + if log_file_path == storage_dir || log_file_path == network_dir { eprintln!("Log file path cannot be the same as storage directory path."); std::process::exit(-1); } @@ -100,7 +163,15 @@ fn main() { }, }; - ldk_node_config.storage_dir_path = config_file.storage_dir_path.clone(); + let api_key = match load_or_generate_api_key(&network_dir) { + Ok(key) => key, + Err(e) => { + eprintln!("Failed to load or generate API key: {e}"); + std::process::exit(-1); + }, + }; + + ldk_node_config.storage_dir_path = network_dir.to_str().unwrap().to_string(); ldk_node_config.listening_addresses = config_file.listening_addrs; ldk_node_config.announcement_addresses = config_file.announcement_addrs; ldk_node_config.network = config_file.network; @@ -148,7 +219,7 @@ fn main() { builder.set_runtime(runtime.handle().clone()); - let seed_path = format!("{}/keys_seed", config_file.storage_dir_path); + let seed_path = storage_dir.join("keys_seed").to_str().unwrap().to_string(); let node_entropy = match NodeEntropy::from_seed_path(seed_path) { Ok(entropy) => entropy, Err(e) => { @@ -165,15 +236,14 @@ fn main() { }, }; - let paginated_store: Arc = Arc::new( - match SqliteStore::new(PathBuf::from(&config_file.storage_dir_path), None, None) { + let paginated_store: Arc = + Arc::new(match SqliteStore::new(network_dir.clone(), None, None) { Ok(store) => store, Err(e) => { error!("Failed to create SqliteStore: {e:?}"); std::process::exit(-1); }, - }, - ); + }); #[cfg(not(feature = "events-rabbitmq"))] let event_publisher: Arc = @@ -227,7 +297,7 @@ fn main() { let server_config = match get_or_generate_tls_config( config_file.tls_config, - &config_file.storage_dir_path, + storage_dir.to_str().unwrap(), ) { Ok(config) => config, Err(e) => { @@ -380,7 +450,7 @@ fn main() { res = rest_svc_listener.accept() => { match res { Ok((stream, _)) => { - let node_service = NodeService::new(Arc::clone(&node), Arc::clone(&paginated_store), config_file.api_key.clone()); + let node_service = NodeService::new(Arc::clone(&node), Arc::clone(&paginated_store), api_key.clone()); let acceptor = tls_acceptor.clone(); runtime.spawn(async move { match acceptor.accept(stream).await { @@ -465,3 +535,29 @@ fn upsert_payment_details( }, } } + +/// Loads the API key from a file, or generates a new one if it doesn't exist. +/// The API key file is stored with 0400 permissions (read-only for owner). +fn load_or_generate_api_key(storage_dir: &Path) -> std::io::Result { + let api_key_path = storage_dir.join(API_KEY_FILE); + + if api_key_path.exists() { + let key_bytes = fs::read(&api_key_path)?; + Ok(key_bytes.to_lower_hex_string()) + } else { + // Generate a 32-byte random API key + let mut rng = rand::thread_rng(); + let mut key_bytes = [0u8; 32]; + rng.fill(&mut key_bytes); + + // Write the raw bytes to the file + fs::write(&api_key_path, key_bytes)?; + + // Set permissions to 0400 (read-only for owner) + let permissions = fs::Permissions::from_mode(0o400); + fs::set_permissions(&api_key_path, permissions)?; + + debug!("Generated new API key at {}", api_key_path.display()); + Ok(key_bytes.to_lower_hex_string()) + } +} diff --git a/ldk-server/ldk-server/src/util/config.rs b/ldk-server/ldk-server/src/util/config.rs index 29690845b..3824a82d5 100644 --- a/ldk-server/ldk-server/src/util/config.rs +++ b/ldk-server/ldk-server/src/util/config.rs @@ -26,10 +26,9 @@ pub struct Config { pub announcement_addrs: Option>, pub alias: Option, pub network: Network, - pub api_key: String, pub tls_config: Option, pub rest_service_addr: SocketAddr, - pub storage_dir_path: String, + pub storage_dir_path: Option, pub chain_source: ChainSource, pub rabbitmq_connection_string: String, pub rabbitmq_exchange_name: String, @@ -194,8 +193,7 @@ impl TryFrom for Config { network: toml_config.node.network, alias, rest_service_addr, - api_key: toml_config.node.api_key, - storage_dir_path: toml_config.storage.disk.dir_path, + storage_dir_path: toml_config.storage.and_then(|s| s.disk.and_then(|d| d.dir_path)), chain_source, rabbitmq_connection_string, rabbitmq_exchange_name, @@ -211,7 +209,7 @@ impl TryFrom for Config { #[derive(Deserialize, Serialize)] pub struct TomlConfig { node: NodeConfig, - storage: StorageConfig, + storage: Option, bitcoind: Option, electrum: Option, esplora: Option, @@ -228,17 +226,16 @@ struct NodeConfig { announcement_addresses: Option>, rest_service_address: String, alias: Option, - api_key: String, } #[derive(Deserialize, Serialize)] struct StorageConfig { - disk: DiskConfig, + disk: Option, } #[derive(Deserialize, Serialize)] struct DiskConfig { - dir_path: String, + dir_path: Option, } #[derive(Deserialize, Serialize)] @@ -365,7 +362,6 @@ mod tests { announcement_addresses = ["54.3.7.81:3001"] rest_service_address = "127.0.0.1:3002" alias = "LDK Server" - api_key = "test_api_key" [tls] cert_path = "/path/to/tls.crt" @@ -411,8 +407,7 @@ mod tests { alias: Some(NodeAlias(bytes)), network: Network::Regtest, rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(), - api_key: "test_api_key".to_string(), - storage_dir_path: "/tmp".to_string(), + storage_dir_path: Some("/tmp".to_string()), tls_config: Some(TlsConfig { cert_path: Some("/path/to/tls.crt".to_string()), key_path: Some("/path/to/tls.key".to_string()), @@ -444,7 +439,6 @@ mod tests { assert_eq!(config.alias, expected.alias); assert_eq!(config.network, expected.network); assert_eq!(config.rest_service_addr, expected.rest_service_addr); - assert_eq!(config.api_key, expected.api_key); assert_eq!(config.storage_dir_path, expected.storage_dir_path); assert_eq!(config.tls_config, expected.tls_config); let ChainSource::Esplora { server_url } = config.chain_source else { @@ -468,7 +462,6 @@ mod tests { network = "regtest" rest_service_address = "127.0.0.1:3002" alias = "LDK Server" - api_key = "test_api_key" [storage.disk] dir_path = "/tmp" @@ -512,7 +505,6 @@ mod tests { network = "regtest" rest_service_address = "127.0.0.1:3002" alias = "LDK Server" - api_key = "test_api_key" [storage.disk] dir_path = "/tmp" @@ -560,7 +552,6 @@ mod tests { network = "regtest" rest_service_address = "127.0.0.1:3002" alias = "LDK Server" - api_key = "test_api_key" [storage.disk] dir_path = "/tmp" From 5752cadec7968424fa5659a9e9dbc5071a4ebb8f Mon Sep 17 00:00:00 2001 From: Fmt Bot Date: Mon, 19 Jan 2026 09:03:11 +0000 Subject: [PATCH 194/203] 2026-01-19 automated rustfmt nightly --- ldk-server/ldk-server-cli/src/config.rs | 3 ++- ldk-server/ldk-server-cli/src/main.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/config.rs b/ldk-server/ldk-server-cli/src/config.rs index 3158ac591..49f84cff4 100644 --- a/ldk-server/ldk-server-cli/src/config.rs +++ b/ldk-server/ldk-server-cli/src/config.rs @@ -7,9 +7,10 @@ // You may not use this file except in accordance with one or both of these // licenses. -use serde::{Deserialize, Serialize}; use std::path::PathBuf; +use serde::{Deserialize, Serialize}; + const DEFAULT_CONFIG_FILE: &str = "config.toml"; const DEFAULT_CERT_FILE: &str = "tls.crt"; const API_KEY_FILE: &str = "api_key"; diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index fae510bbf..177b19cc7 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -7,6 +7,8 @@ // You may not use this file except in accordance with one or both of these // licenses. +use std::path::PathBuf; + use clap::{Parser, Subcommand}; use config::{ get_default_api_key_path, get_default_cert_path, get_default_config_path, load_config, @@ -32,7 +34,6 @@ use ldk_server_client::ldk_server_protos::types::{ RouteParametersConfig, }; use serde::Serialize; -use std::path::PathBuf; use types::CliListPaymentsResponse; mod config; From 1084b5c760fce6071ab440178368ebd5e5b7f13a Mon Sep 17 00:00:00 2001 From: benthecarman Date: Sun, 18 Jan 2026 21:47:52 -0600 Subject: [PATCH 195/203] Add help text for all cli commands and args For most of these I tried to just copy from the proto docs or ldk-node docs, adapting the wording when necessary. --- ldk-server/ldk-server-cli/src/main.rs | 180 +++++++++++++++++++------- 1 file changed, 133 insertions(+), 47 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 177b19cc7..e77cf838c 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -48,7 +48,12 @@ const DEFAULT_MAX_CHANNEL_SATURATION_POWER_OF_HALF: u32 = 2; const DEFAULT_EXPIRY_SECS: u32 = 86_400; #[derive(Parser, Debug)] -#[command(version, about, long_about = None)] +#[command( + name = "ldk-server-cli", + version, + about = "CLI for interacting with an LDK Server node", + override_usage = "ldk-server-cli [OPTIONS] " +)] struct Cli { #[arg(short, long, help = "Base URL of the server. If not provided, reads from config file")] base_url: Option, @@ -76,95 +81,161 @@ struct Cli { #[derive(Subcommand, Debug)] enum Commands { + #[command(about = "Retrieve the latest node info like node_id, current_best_block, etc")] GetNodeInfo, + #[command(about = "Retrieve an overview of all known balances")] GetBalances, + #[command(about = "Retrieve a new on-chain funding address")] OnchainReceive, + #[command(about = "Send an on-chain payment to the given address")] OnchainSend { - #[arg(short, long)] + #[arg(short, long, help = "The address to send coins to")] address: String, - #[arg(long)] + #[arg( + long, + help = "The amount in satoshis to send. Will respect any on-chain reserve needed for anchor channels" + )] amount_sats: Option, - #[arg(long)] + #[arg( + long, + help = "Send full balance to the address. Warning: will not retain on-chain reserves for anchor channels" + )] send_all: Option, - #[arg(long)] + #[arg( + long, + help = "Fee rate in satoshis per virtual byte. If not set, a reasonable estimate will be used" + )] fee_rate_sat_per_vb: Option, }, + #[command(about = "Create a BOLT11 invoice to receive a payment")] Bolt11Receive { - #[arg(short, long)] + #[arg(short, long, help = "Description to attach along with the invoice")] description: Option, - #[arg(long)] + #[arg( + long, + help = "SHA-256 hash of the description (hex). Use instead of description for longer text" + )] description_hash: Option, - #[arg(short, long)] + #[arg(short, long, help = "Invoice expiry time in seconds (default: 86400)")] expiry_secs: Option, - #[arg(long)] + #[arg( + long, + help = "Amount in millisatoshis to request. If unset, a variable-amount invoice is returned" + )] amount_msat: Option, }, + #[command(about = "Pay a BOLT11 invoice")] Bolt11Send { - #[arg(short, long)] + #[arg(short, long, help = "A BOLT11 invoice for a payment within the Lightning Network")] invoice: String, - #[arg(long)] + #[arg(long, help = "Amount in millisatoshis. Required when paying a zero-amount invoice")] amount_msat: Option, - #[arg(long)] + #[arg( + long, + help = "Maximum total fees in millisatoshis that may accrue during route finding. Defaults to 1% of payment + 50 sats" + )] max_total_routing_fee_msat: Option, - #[arg(long)] + #[arg(long, help = "Maximum total CLTV delta we accept for the route (default: 1008)")] max_total_cltv_expiry_delta: Option, - #[arg(long)] + #[arg( + long, + help = "Maximum number of paths that may be used by MPP payments (default: 10)" + )] max_path_count: Option, - #[arg(long)] + #[arg( + long, + help = "Maximum share of a channel's total capacity to send over a channel, as a power of 1/2 (default: 2)" + )] max_channel_saturation_power_of_half: Option, }, + #[command(about = "Return a BOLT12 offer for receiving payments")] Bolt12Receive { - #[arg(short, long)] + #[arg(short, long, help = "Description to attach along with the offer")] description: String, - #[arg(long)] + #[arg( + long, + help = "Amount in millisatoshis to request. If unset, a variable-amount offer is returned" + )] amount_msat: Option, - #[arg(long)] + #[arg(long, help = "Offer expiry time in seconds")] expiry_secs: Option, - #[arg(long)] + #[arg(long, help = "Number of items requested. Can only be set for fixed-amount offers")] quantity: Option, }, + #[command(about = "Send a payment for a BOLT12 offer")] Bolt12Send { - #[arg(short, long)] + #[arg(short, long, help = "A BOLT12 offer for a payment within the Lightning Network")] offer: String, - #[arg(long)] + #[arg(long, help = "Amount in millisatoshis. Required when paying a zero-amount offer")] amount_msat: Option, - #[arg(short, long)] + #[arg(short, long, help = "Number of items requested")] quantity: Option, - #[arg(short, long)] + #[arg( + short, + long, + help = "Note to include for the payee. Will be seen by recipient and reflected back in the invoice" + )] payer_note: Option, - #[arg(long)] + #[arg( + long, + help = "Maximum total fees, in millisatoshi, that may accrue during route finding, Defaults to 1% of the payment amount + 50 sats" + )] max_total_routing_fee_msat: Option, - #[arg(long)] + #[arg(long, help = "Maximum total CLTV delta we accept for the route (default: 1008)")] max_total_cltv_expiry_delta: Option, - #[arg(long)] + #[arg( + long, + help = "Maximum number of paths that may be used by MPP payments (default: 10)" + )] max_path_count: Option, - #[arg(long)] + #[arg( + long, + help = "Maximum share of a channel's total capacity to send over a channel, as a power of 1/2 (default: 2)" + )] max_channel_saturation_power_of_half: Option, }, + #[command(about = "Cooperatively close the channel specified by the given channel ID")] CloseChannel { - #[arg(short, long)] + #[arg(short, long, help = "The local user_channel_id of this channel")] user_channel_id: String, - #[arg(short, long)] + #[arg( + short, + long, + help = "The hex-encoded public key of the node to close a channel with" + )] counterparty_node_id: String, }, + #[command(about = "Force close the channel specified by the given channel ID")] ForceCloseChannel { - #[arg(short, long)] + #[arg(short, long, help = "The local user_channel_id of this channel")] user_channel_id: String, - #[arg(short, long)] + #[arg( + short, + long, + help = "The hex-encoded public key of the node to close a channel with" + )] counterparty_node_id: String, - #[arg(long)] + #[arg(long, help = "The reason for force-closing, defaults to \"\"")] force_close_reason: Option, }, + #[command(about = "Create a new outbound channel to the given remote node")] OpenChannel { - #[arg(short, long)] + #[arg(short, long, help = "The hex-encoded public key of the node to open a channel with")] node_pubkey: String, - #[arg(short, long)] + #[arg( + short, + long, + help = "Address to connect to remote peer (IPv4:port, IPv6:port, OnionV3:port, or hostname:port)" + )] address: String, - #[arg(long)] + #[arg(long, help = "The amount of satoshis to commit to the channel")] channel_amount_sats: u64, - #[arg(long)] + #[arg( + long, + help = "Amount of satoshis to push to the remote side as part of the initial commitment state" + )] push_to_counterparty_msat: Option, - #[arg(long)] + #[arg(long, help = "Whether the channel should be public")] announce_channel: bool, // Channel config options #[arg( @@ -183,25 +254,35 @@ enum Commands { )] cltv_expiry_delta: Option, }, + #[command( + about = "Increase the channel balance by the given amount, funds will come from the node's on-chain wallet" + )] SpliceIn { - #[arg(short, long)] + #[arg(short, long, help = "The local user_channel_id of the channel")] user_channel_id: String, - #[arg(short, long)] + #[arg(short, long, help = "The hex-encoded public key of the channel's counterparty node")] counterparty_node_id: String, - #[arg(long)] + #[arg(long, help = "The amount of sats to splice into the channel")] splice_amount_sats: u64, }, + #[command(about = "Decrease the channel balance by the given amount")] SpliceOut { - #[arg(short, long)] + #[arg(short, long, help = "The local user_channel_id of this channel")] user_channel_id: String, - #[arg(short, long)] + #[arg(short, long, help = "The hex-encoded public key of the channel's counterparty node")] counterparty_node_id: String, - #[arg(short, long)] - address: Option, - #[arg(long)] + #[arg(long, help = "The amount of sats to splice out of the channel")] splice_amount_sats: u64, + #[arg( + short, + long, + help = "Bitcoin address to send the spliced-out funds. If not set, uses the node's on-chain wallet" + )] + address: Option, }, + #[command(about = "Return a list of known channels")] ListChannels, + #[command(about = "Retrieve list of all payments")] ListPayments { #[arg(short, long)] #[arg( @@ -212,10 +293,15 @@ enum Commands { #[arg(help = "Page token to continue from a previous page (format: token:index)")] page_token: Option, }, + #[command(about = "Update the config for a previously opened channel")] UpdateChannelConfig { - #[arg(short, long)] + #[arg(short, long, help = "The local user_channel_id of this channel")] user_channel_id: String, - #[arg(short, long)] + #[arg( + short, + long, + help = "The hex-encoded public key of the counterparty node to update channel config with" + )] counterparty_node_id: String, #[arg( long, From b5b41332840fb16205a7ded9b73e525828f65f6d Mon Sep 17 00:00:00 2001 From: benthecarman Date: Wed, 14 Jan 2026 13:28:24 -0600 Subject: [PATCH 196/203] Add GetPaymentDetails to client and CLI --- ldk-server/ldk-server-cli/src/main.rs | 18 +++++++++++++---- ldk-server/ldk-server-client/src/client.rs | 23 ++++++++++++++++------ 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index e77cf838c..7c102dcf1 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -24,10 +24,11 @@ use ldk_server_client::ldk_server_protos::api::{ Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse, GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse, - ListChannelsRequest, ListChannelsResponse, ListPaymentsRequest, ListPaymentsResponse, - OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, - OpenChannelRequest, OpenChannelResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest, - SpliceOutResponse, UpdateChannelConfigRequest, UpdateChannelConfigResponse, + GetPaymentDetailsRequest, GetPaymentDetailsResponse, ListChannelsRequest, ListChannelsResponse, + ListPaymentsRequest, ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse, + OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, OpenChannelResponse, + SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse, + UpdateChannelConfigRequest, UpdateChannelConfigResponse, }; use ldk_server_client::ldk_server_protos::types::{ bolt11_invoice_description, Bolt11InvoiceDescription, ChannelConfig, PageToken, @@ -293,6 +294,10 @@ enum Commands { #[arg(help = "Page token to continue from a previous page (format: token:index)")] page_token: Option, }, + GetPaymentDetails { + #[arg(short, long, help = "The payment ID in hex-encoded form")] + payment_id: String, + }, #[command(about = "Update the config for a previously opened channel")] UpdateChannelConfig { #[arg(short, long, help = "The local user_channel_id of this channel")] @@ -587,6 +592,11 @@ async fn main() { handle_list_payments(client, number_of_payments, page_token).await, ); }, + Commands::GetPaymentDetails { payment_id } => { + handle_response_result::<_, GetPaymentDetailsResponse>( + client.get_payment_details(GetPaymentDetailsRequest { payment_id }).await, + ); + }, Commands::UpdateChannelConfig { user_channel_id, counterparty_node_id, diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index f0509ab51..0338f0b7e 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -16,16 +16,18 @@ use ldk_server_protos::api::{ Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse, GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse, - ListChannelsRequest, ListChannelsResponse, ListPaymentsRequest, ListPaymentsResponse, - OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, - OpenChannelRequest, OpenChannelResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest, - SpliceOutResponse, UpdateChannelConfigRequest, UpdateChannelConfigResponse, + GetPaymentDetailsRequest, GetPaymentDetailsResponse, ListChannelsRequest, ListChannelsResponse, + 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, - LIST_CHANNELS_PATH, LIST_PAYMENTS_PATH, ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, - OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH, UPDATE_CHANNEL_CONFIG_PATH, + GET_PAYMENT_DETAILS_PATH, LIST_CHANNELS_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; @@ -231,6 +233,15 @@ impl LdkServerClient { self.post_request(&request, &url).await } + /// Retrieves payment details for a given payment id. + /// For API contract/usage, refer to docs for [`GetPaymentDetailsRequest`] and [`GetPaymentDetailsResponse`]. + pub async fn get_payment_details( + &self, request: GetPaymentDetailsRequest, + ) -> Result { + let url = format!("https://{}/{GET_PAYMENT_DETAILS_PATH}", self.base_url); + self.post_request(&request, &url).await + } + async fn post_request( &self, request: &Rq, url: &str, ) -> Result { From a3a74810612a400e18040cfe8eb84b08c374bfd6 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Wed, 14 Jan 2026 13:31:25 -0600 Subject: [PATCH 197/203] Add ListForwardedPayments to client and CLI --- ldk-server/ldk-server-cli/src/main.rs | 108 ++++++++++++++------- ldk-server/ldk-server-cli/src/types.rs | 22 ++--- ldk-server/ldk-server-client/src/client.rs | 22 +++-- 3 files changed, 100 insertions(+), 52 deletions(-) diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 7c102dcf1..d755892b3 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -25,9 +25,9 @@ use ldk_server_client::ldk_server_protos::api::{ CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse, GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse, GetPaymentDetailsRequest, GetPaymentDetailsResponse, ListChannelsRequest, ListChannelsResponse, - ListPaymentsRequest, ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse, - OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, OpenChannelResponse, - SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse, + ListForwardedPaymentsRequest, ListPaymentsRequest, OnchainReceiveRequest, + OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, + OpenChannelResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse, UpdateChannelConfigRequest, UpdateChannelConfigResponse, }; use ldk_server_client::ldk_server_protos::types::{ @@ -35,7 +35,7 @@ use ldk_server_client::ldk_server_protos::types::{ RouteParametersConfig, }; use serde::Serialize; -use types::CliListPaymentsResponse; +use types::{CliListForwardedPaymentsResponse, CliListPaymentsResponse, CliPaginatedResponse}; mod config; mod types; @@ -294,11 +294,22 @@ enum Commands { #[arg(help = "Page token to continue from a previous page (format: token:index)")] page_token: Option, }, + #[command(about = "Get details of a specific payment by its payment ID")] GetPaymentDetails { #[arg(short, long, help = "The payment ID in hex-encoded form")] payment_id: String, }, - #[command(about = "Update the config for a previously opened channel")] + #[command(about = "Retrieves list of all forwarded payments")] + ListForwardedPayments { + #[arg( + short, + long, + help = "Fetch at least this many forwarded payments by iterating through multiple pages. Returns combined results with the last page token. If not provided, returns only a single page." + )] + number_of_payments: Option, + #[arg(long, help = "Page token to continue from a previous page (format: token:index)")] + page_token: Option, + }, UpdateChannelConfig { #[arg(short, long, help = "The local user_channel_id of this channel")] user_channel_id: String, @@ -589,7 +600,13 @@ async fn main() { .map(|token_str| parse_page_token(&token_str).unwrap_or_else(|e| handle_error(e))); handle_response_result::<_, CliListPaymentsResponse>( - handle_list_payments(client, number_of_payments, page_token).await, + fetch_paginated( + number_of_payments, + page_token, + |pt| client.list_payments(ListPaymentsRequest { page_token: pt }), + |r| (r.payments, r.next_page_token), + ) + .await, ); }, Commands::GetPaymentDetails { payment_id } => { @@ -597,6 +614,24 @@ async fn main() { client.get_payment_details(GetPaymentDetailsRequest { payment_id }).await, ); }, + Commands::ListForwardedPayments { number_of_payments, page_token } => { + let page_token = page_token + .map(|token_str| parse_page_token(&token_str).unwrap_or_else(|e| handle_error(e))); + + handle_response_result::<_, CliListForwardedPaymentsResponse>( + fetch_paginated( + number_of_payments, + page_token, + |pt| { + client.list_forwarded_payments(ListForwardedPaymentsRequest { + page_token: pt, + }) + }, + |r| (r.forwarded_payments, r.next_page_token), + ) + .await, + ); + }, Commands::UpdateChannelConfig { user_channel_id, counterparty_node_id, @@ -648,37 +683,40 @@ fn build_open_channel_config( }) } -async fn handle_list_payments( - client: LdkServerClient, number_of_payments: Option, initial_page_token: Option, -) -> Result { - if let Some(count) = number_of_payments { - list_n_payments(client, count, initial_page_token).await - } else { - // Fetch single page - client.list_payments(ListPaymentsRequest { page_token: initial_page_token }).await - } -} - -async fn list_n_payments( - client: LdkServerClient, target_count: u64, initial_page_token: Option, -) -> Result { - let mut payments = Vec::with_capacity(target_count as usize); - let mut page_token = initial_page_token; - let mut next_page_token; - - loop { - let response = client.list_payments(ListPaymentsRequest { page_token }).await?; - - payments.extend(response.payments); - next_page_token = response.next_page_token; +async fn fetch_paginated( + target_count: Option, initial_page_token: Option, + fetch_page: impl Fn(Option) -> Fut, + extract: impl Fn(R) -> (Vec, Option), +) -> Result, LdkServerError> +where + Fut: std::future::Future>, +{ + match target_count { + Some(count) => { + let mut items = Vec::with_capacity(count as usize); + let mut page_token = initial_page_token; + let mut next_page_token; + + loop { + let response = fetch_page(page_token).await?; + let (new_items, new_next_page_token) = extract(response); + items.extend(new_items); + next_page_token = new_next_page_token; + + if items.len() >= count as usize || next_page_token.is_none() { + break; + } + page_token = next_page_token; + } - if payments.len() >= target_count as usize || next_page_token.is_none() { - break; - } - page_token = next_page_token; + Ok(CliPaginatedResponse::new(items, next_page_token)) + }, + None => { + let response = fetch_page(initial_page_token).await?; + let (items, next_page_token) = extract(response); + Ok(CliPaginatedResponse::new(items, next_page_token)) + }, } - - Ok(ListPaymentsResponse { payments, next_page_token }) } fn handle_response_result(response: Result) diff --git a/ldk-server/ldk-server-cli/src/types.rs b/ldk-server/ldk-server-cli/src/types.rs index a482f794d..e3c708d51 100644 --- a/ldk-server/ldk-server-cli/src/types.rs +++ b/ldk-server/ldk-server-cli/src/types.rs @@ -13,29 +13,29 @@ //! of API responses for CLI output. These wrappers ensure that the CLI's output //! format matches what users expect and what the CLI can parse back as input. -use ldk_server_client::ldk_server_protos::api::ListPaymentsResponse; -use ldk_server_client::ldk_server_protos::types::{PageToken, Payment}; +use ldk_server_client::ldk_server_protos::types::{ForwardedPayment, PageToken, Payment}; use serde::Serialize; -/// CLI-specific wrapper for ListPaymentsResponse that formats the page token +/// CLI-specific wrapper for paginated responses that formats the page token /// as "token:idx" instead of a JSON object. #[derive(Debug, Clone, Serialize)] -pub struct CliListPaymentsResponse { - /// List of payments. - pub payments: Vec, +pub struct CliPaginatedResponse { + /// List of items. + pub list: Vec, /// Next page token formatted as "token:idx", or None if no more pages. #[serde(skip_serializing_if = "Option::is_none")] pub next_page_token: Option, } -impl From for CliListPaymentsResponse { - fn from(response: ListPaymentsResponse) -> Self { - let next_page_token = response.next_page_token.map(format_page_token); - - CliListPaymentsResponse { payments: response.payments, next_page_token } +impl CliPaginatedResponse { + pub fn new(list: Vec, next_page_token: Option) -> Self { + Self { list, next_page_token: next_page_token.map(format_page_token) } } } +pub type CliListPaymentsResponse = CliPaginatedResponse; +pub type CliListForwardedPaymentsResponse = CliPaginatedResponse; + fn format_page_token(token: PageToken) -> String { format!("{}:{}", token.token, token.index) } diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index 0338f0b7e..ab3d2c293 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/ldk-server-client/src/client.rs @@ -17,16 +17,17 @@ use ldk_server_protos::api::{ CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse, GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse, GetPaymentDetailsRequest, GetPaymentDetailsResponse, ListChannelsRequest, ListChannelsResponse, - ListPaymentsRequest, ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse, - OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, OpenChannelResponse, - SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse, - UpdateChannelConfigRequest, UpdateChannelConfigResponse, + 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_PAYMENTS_PATH, ONCHAIN_RECEIVE_PATH, - ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_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}; @@ -242,6 +243,15 @@ impl LdkServerClient { self.post_request(&request, &url).await } + /// Retrieves list of all forwarded payments. + /// For API contract/usage, refer to docs for [`ListForwardedPaymentsRequest`] and [`ListForwardedPaymentsResponse`]. + pub async fn list_forwarded_payments( + &self, request: ListForwardedPaymentsRequest, + ) -> Result { + let url = format!("https://{}/{LIST_FORWARDED_PAYMENTS_PATH}", self.base_url); + self.post_request(&request, &url).await + } + async fn post_request( &self, request: &Rq, url: &str, ) -> Result { From 13ee0e51c4e5b3c575ae467bb352147e6a71623c Mon Sep 17 00:00:00 2001 From: benthecarman Date: Sun, 18 Jan 2026 22:19:40 -0600 Subject: [PATCH 198/203] Add support for bash completions --- ldk-server/Cargo.lock | 10 ++++++++++ ldk-server/README.md | 20 ++++++++++++++++++-- ldk-server/ldk-server-cli/Cargo.toml | 1 + ldk-server/ldk-server-cli/src/main.rs | 18 +++++++++++++++++- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock index bb849fd7c..538c97742 100644 --- a/ldk-server/Cargo.lock +++ b/ldk-server/Cargo.lock @@ -648,6 +648,15 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.5.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "430b4dc2b5e3861848de79627b2bedc9f3342c7da5173a14eaa5d0f8dc18ae5d" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.5.49" @@ -1760,6 +1769,7 @@ name = "ldk-server-cli" version = "0.1.0" dependencies = [ "clap", + "clap_complete", "hex-conservative 0.2.1", "ldk-server-client", "serde", diff --git a/ldk-server/README.md b/ldk-server/README.md index e3358c47b..8497da579 100644 --- a/ldk-server/README.md +++ b/ldk-server/README.md @@ -51,6 +51,22 @@ cargo run --bin ldk-server ./ldk-server/ldk-server-config.toml Interact with the node using CLI: ``` -./target/debug/ldk-server-cli -b localhost:3002 --api-key your-secret-api-key onchain-receive # To generate onchain-receive address. -./target/debug/ldk-server-cli -b localhost:3002 --api-key your-secret-api-key help # To print help/available commands. +ldk-server-cli -b localhost:3002 --api-key your-secret-api-key --tls-cert /path/to/tls_cert.pem onchain-receive # To generate onchain-receive address. +ldk-server-cli -b localhost:3002 --api-key your-secret-api-key --tls-cert /path/to/tls_cert.pem help # To print help/available commands. +``` + +### Shell Completions + +The CLI supports generating shell completions for Bash, Zsh, Fish, Elvish, and PowerShell. + +Add completions to your shell config: +```bash +# Bash (add to ~/.bashrc) +eval "$(ldk-server-cli completions bash)" + +# Zsh (add to ~/.zshrc) +eval "$(ldk-server-cli completions zsh)" + +# Fish (add to ~/.config/fish/config.fish) +ldk-server-cli completions fish | source ``` diff --git a/ldk-server/ldk-server-cli/Cargo.toml b/ldk-server/ldk-server-cli/Cargo.toml index 2ac0c4cf9..5d006001a 100644 --- a/ldk-server/ldk-server-cli/Cargo.toml +++ b/ldk-server/ldk-server-cli/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] ldk-server-client = { path = "../ldk-server-client", features = ["serde"] } clap = { version = "4.0.5", default-features = false, features = ["derive", "std", "error-context", "suggestions", "help"] } +clap_complete = { version = "4.0", default-features = false } hex-conservative = { version = "0.2", default-features = false, features = ["std"] } tokio = { version = "1.38.0", default-features = false, features = ["rt-multi-thread", "macros"] } serde = "1.0" diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index e77cf838c..00b10d72b 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -9,7 +9,8 @@ use std::path::PathBuf; -use clap::{Parser, Subcommand}; +use clap::{CommandFactory, Parser, Subcommand}; +use clap_complete::{generate, Shell}; use config::{ get_default_api_key_path, get_default_cert_path, get_default_config_path, load_config, }; @@ -319,12 +320,26 @@ enum Commands { )] cltv_expiry_delta: Option, }, + #[command(about = "Generate shell completions for the CLI")] + Completions { + #[arg( + value_enum, + help = "The shell to generate completions for (bash, zsh, fish, powershell, elvish)" + )] + shell: Shell, + }, } #[tokio::main] async fn main() { let cli = Cli::parse(); + // short-circuit if generating completions + if let Commands::Completions { shell } = cli.command { + generate(shell, &mut Cli::command(), "ldk-server-cli", &mut std::io::stdout()); + return; + } + let config_path = cli.config.map(PathBuf::from).or_else(get_default_config_path); let config = config_path.as_ref().and_then(|p| load_config(p).ok()); @@ -613,6 +628,7 @@ async fn main() { .await, ); }, + Commands::Completions { .. } => unreachable!("Handled above"), } } From 0b141da6d1de09e660dcebf23d724e3781b6d29b Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Thu, 22 Jan 2026 08:53:12 +0100 Subject: [PATCH 199/203] Create storage directory before generating API key The load_or_generate_api_key function would fail with "No such file or directory" when the network-specific storage directory didn't exist. This adds fs::create_dir_all() to ensure the directory exists before writing the API key file. Co-Authored-By: Claude Opus 4.5 --- ldk-server/ldk-server/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ldk-server/ldk-server/src/main.rs b/ldk-server/ldk-server/src/main.rs index acc1a9b61..ba0731c9a 100644 --- a/ldk-server/ldk-server/src/main.rs +++ b/ldk-server/ldk-server/src/main.rs @@ -545,6 +545,9 @@ fn load_or_generate_api_key(storage_dir: &Path) -> std::io::Result { let key_bytes = fs::read(&api_key_path)?; Ok(key_bytes.to_lower_hex_string()) } else { + // Ensure the storage directory exists + fs::create_dir_all(storage_dir)?; + // Generate a 32-byte random API key let mut rng = rand::thread_rng(); let mut key_bytes = [0u8; 32]; From 4455a7a038ba624c36026a3932efb032fe2a0db0 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Thu, 22 Jan 2026 09:08:43 +0100 Subject: [PATCH 200/203] 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 a persist flag that indicates whether the peer should be re-connected on restart. Also adds client library and CLI support for the new endpoint. Co-Authored-By: Claude Opus 4.5 --- ldk-server/ldk-server-cli/src/main.rs | 36 +++++++++++++++---- ldk-server/ldk-server-client/src/client.rs | 33 ++++++++++------- ldk-server/ldk-server-protos/src/api.rs | 26 ++++++++++++++ ldk-server/ldk-server-protos/src/endpoints.rs | 1 + .../ldk-server-protos/src/proto/api.proto | 19 ++++++++++ ldk-server/ldk-server/src/api/connect_peer.rs | 28 +++++++++++++++ ldk-server/ldk-server/src/api/mod.rs | 1 + ldk-server/ldk-server/src/service.rs | 12 ++++--- 8 files changed, 133 insertions(+), 23 deletions(-) create mode 100644 ldk-server/ldk-server/src/api/connect_peer.rs diff --git a/ldk-server/ldk-server-cli/src/main.rs b/ldk-server/ldk-server-cli/src/main.rs index 488ca10e6..4e571b3d9 100644 --- a/ldk-server/ldk-server-cli/src/main.rs +++ b/ldk-server/ldk-server-cli/src/main.rs @@ -23,13 +23,13 @@ use ldk_server_client::error::LdkServerErrorCode::{ use ldk_server_client::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, ListPaymentsRequest, 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, ListPaymentsRequest, + OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, + OpenChannelRequest, OpenChannelResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest, + SpliceOutResponse, UpdateChannelConfigRequest, UpdateChannelConfigResponse, }; use ldk_server_client::ldk_server_protos::types::{ bolt11_invoice_description, Bolt11InvoiceDescription, ChannelConfig, PageToken, @@ -336,6 +336,23 @@ enum Commands { )] cltv_expiry_delta: Option, }, + #[command(about = "Connect to a peer on the Lightning Network without opening a channel")] + ConnectPeer { + #[arg(short, long, help = "The hex-encoded public key of the node to connect to")] + node_pubkey: String, + #[arg( + short, + long, + help = "Address to connect to remote peer (IPv4:port, IPv6:port, OnionV3:port, or hostname:port)" + )] + address: String, + #[arg( + long, + default_value_t = false, + help = "Whether to persist the connection for automatic reconnection on restart" + )] + persist: bool, + }, #[command(about = "Generate shell completions for the CLI")] Completions { #[arg( @@ -673,6 +690,11 @@ async fn main() { .await, ); }, + Commands::ConnectPeer { node_pubkey, address, persist } => { + handle_response_result::<_, ConnectPeerResponse>( + client.connect_peer(ConnectPeerRequest { node_pubkey, address, persist }).await, + ); + }, Commands::Completions { .. } => unreachable!("Handled above"), } } diff --git a/ldk-server/ldk-server-client/src/client.rs b/ldk-server/ldk-server-client/src/client.rs index ab3d2c293..0d137db19 100644 --- a/ldk-server/ldk-server-client/src/client.rs +++ b/ldk-server/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/ldk-server-protos/src/api.rs b/ldk-server/ldk-server-protos/src/api.rs index 439a403de..1f1bbbeab 100644 --- a/ldk-server/ldk-server-protos/src/api.rs +++ b/ldk-server/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. + #[prost(bool, tag = "3")] + pub persist: bool, +} +/// 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/ldk-server-protos/src/endpoints.rs b/ldk-server/ldk-server-protos/src/endpoints.rs index c7ed1c26a..606da0dbe 100644 --- a/ldk-server/ldk-server-protos/src/endpoints.rs +++ b/ldk-server/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/ldk-server-protos/src/proto/api.proto b/ldk-server/ldk-server-protos/src/proto/api.proto index 121b4242b..be29f8f87 100644 --- a/ldk-server/ldk-server-protos/src/proto/api.proto +++ b/ldk-server/ldk-server-protos/src/proto/api.proto @@ -480,3 +480,22 @@ message GetBalancesResponse { // might not already be accounted for in `total_onchain_balance_sats`. repeated types.PendingSweepBalance pending_balances_from_channel_closures = 6; } + +// Connect to a peer on the Lightning Network. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.connect +message ConnectPeerRequest { + // The hex-encoded public key of the node to connect to. + string node_pubkey = 1; + + // 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 + string address = 2; + + // Whether to persist the peer connection, i.e., whether the peer will be re-connected on + // restart. + bool persist = 3; +} + +// 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`. +message ConnectPeerResponse {} diff --git a/ldk-server/ldk-server/src/api/connect_peer.rs b/ldk-server/ldk-server/src/api/connect_peer.rs new file mode 100644 index 000000000..95a7e09a9 --- /dev/null +++ b/ldk-server/ldk-server/src/api/connect_peer.rs @@ -0,0 +1,28 @@ +// 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)?; + + context.node.connect(node_id, address, request.persist)?; + + Ok(ConnectPeerResponse {}) +} diff --git a/ldk-server/ldk-server/src/api/mod.rs b/ldk-server/ldk-server/src/api/mod.rs index 0063d9d8a..1152f8b34 100644 --- a/ldk-server/ldk-server/src/api/mod.rs +++ b/ldk-server/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/ldk-server/src/service.rs b/ldk-server/ldk-server/src/service.rs index 056b2566e..0f0509450 100644 --- a/ldk-server/ldk-server/src/service.rs +++ b/ldk-server/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 7317317d879eae621e60b0dd0d34d9382f830c85 Mon Sep 17 00:00:00 2001 From: Fmt Bot Date: Sun, 25 Jan 2026 01:56:41 +0000 Subject: [PATCH 201/203] 2026-01-25 automated rustfmt nightly --- ldk-server/ldk-server/src/api/connect_peer.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ldk-server/ldk-server/src/api/connect_peer.rs b/ldk-server/ldk-server/src/api/connect_peer.rs index 95a7e09a9..d3fac3a02 100644 --- a/ldk-server/ldk-server/src/api/connect_peer.rs +++ b/ldk-server/ldk-server/src/api/connect_peer.rs @@ -7,12 +7,14 @@ // 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 std::str::FromStr; + use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_server_protos::api::{ConnectPeerRequest, ConnectPeerResponse}; -use std::str::FromStr; + +use crate::api::error::LdkServerError; +use crate::service::Context; pub(crate) fn handle_connect_peer( context: Context, request: ConnectPeerRequest, From db58acbeef6319c5a9e531020f1fdd131cc3d91c Mon Sep 17 00:00:00 2001 From: Anyitechs Date: Tue, 27 Jan 2026 02:18:04 +0100 Subject: [PATCH 202/203] Add node `alias` to config file --- ldk-server/ldk-server/ldk-server-config.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/ldk-server/ldk-server/ldk-server-config.toml b/ldk-server/ldk-server/ldk-server-config.toml index 3c31cbcb7..062ca08ab 100644 --- a/ldk-server/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server/ldk-server-config.toml @@ -4,6 +4,7 @@ network = "regtest" # Bitcoin network to use listening_addresses = ["localhost:3001"] # Lightning node listening addresses announcement_addresses = ["54.3.7.81:3001"] # Lightning node announcement addresses rest_service_address = "127.0.0.1:3002" # LDK Server REST address +alias = "ldk_server" # Lightning node alias # Storage settings [storage.disk] From 025e6d2d16f3734df3d4465b6fdebccfcaec7bd7 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Wed, 28 Jan 2026 14:50:35 +0100 Subject: [PATCH 203/203] Integrate ldk-server into workspace - Add ldk-server crates to root workspace - Remove ldk-server's separate workspace Cargo.toml and Cargo.lock - Update ldk-server's ldk-node dependency path to point to root - Move GitHub workflows to root .github/workflows/ - Add per-package release profile settings for ldk-server crates Co-Authored-By: Claude Opus 4.5 --- .../ldk-server-rabbitmq-integration.yml | 4 +- .github/workflows/ldk-server.yml | 43 + Cargo.toml | 21 + ldk-server/.github/workflows/build.yml | 49 - .../.github/workflows/cron-weekly-rustfmt.yml | 33 - ldk-server/Cargo.lock | 4192 ----------------- ldk-server/Cargo.toml | 11 - ldk-server/ldk-server/Cargo.toml | 2 +- 8 files changed, 67 insertions(+), 4288 deletions(-) rename ldk-server/.github/workflows/integration-tests-events-rabbitmq.yml => .github/workflows/ldk-server-rabbitmq-integration.yml (80%) create mode 100644 .github/workflows/ldk-server.yml delete mode 100644 ldk-server/.github/workflows/build.yml delete mode 100644 ldk-server/.github/workflows/cron-weekly-rustfmt.yml delete mode 100644 ldk-server/Cargo.lock delete mode 100644 ldk-server/Cargo.toml diff --git a/ldk-server/.github/workflows/integration-tests-events-rabbitmq.yml b/.github/workflows/ldk-server-rabbitmq-integration.yml similarity index 80% rename from ldk-server/.github/workflows/integration-tests-events-rabbitmq.yml rename to .github/workflows/ldk-server-rabbitmq-integration.yml index 7f276514b..b1390e328 100644 --- a/ldk-server/.github/workflows/integration-tests-events-rabbitmq.yml +++ b/.github/workflows/ldk-server-rabbitmq-integration.yml @@ -1,4 +1,4 @@ -name: RabbitMQ Integration Tests +name: LDK Server - RabbitMQ Integration Tests on: [ push, pull_request ] @@ -29,6 +29,6 @@ jobs: uses: actions/checkout@v4 - name: Run RabbitMQ integration tests - run: cargo test --features integration-tests-events-rabbitmq --verbose --color=always -- --nocapture + run: cargo test -p ldk-server --features integration-tests-events-rabbitmq --verbose --color=always -- --nocapture env: RUST_BACKTRACE: 1 diff --git a/.github/workflows/ldk-server.yml b/.github/workflows/ldk-server.yml new file mode 100644 index 000000000..e1d5551ce --- /dev/null +++ b/.github/workflows/ldk-server.yml @@ -0,0 +1,43 @@ +name: CI Checks - LDK Server + +on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + strategy: + matrix: + platform: [ + ubuntu-latest, + macos-latest, + ] + toolchain: [ + stable, + beta, + 1.85.0, # MSRV, same as ldk-node + ] + include: + - toolchain: 1.85.0 + msrv: true + runs-on: ${{ matrix.platform }} + steps: + - name: Checkout source code + uses: actions/checkout@v3 + - name: Install Rust ${{ matrix.toolchain }} toolchain + run: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ matrix.toolchain }} + if [ "${{ matrix.msrv }}" = "true" ]; then rustup component add clippy; fi + - name: Build ldk-server crates on Rust ${{ matrix.toolchain }} + run: cargo build -p ldk-server -p ldk-server-cli -p ldk-server-client -p ldk-server-protos --verbose --color always + - name: Check clippy on ldk-server if on msrv + if: matrix.msrv + run: cargo clippy -p ldk-server --all-features -- -D warnings + - name: Test ldk-server crates on Rust ${{ matrix.toolchain }} + run: cargo test -p ldk-server -p ldk-server-cli -p ldk-server-client -p ldk-server-protos + - name: Cargo check release on Rust ${{ matrix.toolchain }} + run: cargo check --release -p ldk-server -p ldk-server-cli -p ldk-server-client -p ldk-server-protos + - name: Cargo check doc on Rust ${{ matrix.toolchain }} + run: cargo doc --release -p ldk-server -p ldk-server-cli -p ldk-server-client -p ldk-server-protos diff --git a/Cargo.toml b/Cargo.toml index 6996f59f0..8ccaf5e61 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,12 @@ +[workspace] +resolver = "2" +members = [ + "ldk-server/ldk-server", + "ldk-server/ldk-server-cli", + "ldk-server/ldk-server-client", + "ldk-server/ldk-server-protos", +] + [package] name = "ldk-node" version = "0.8.0+git" @@ -110,6 +119,18 @@ uniffi = { version = "0.28.3", features = ["build"], optional = true } [profile.release] panic = "abort" +[profile.release.package.ldk-server] +opt-level = 3 + +[profile.release.package.ldk-server-cli] +opt-level = 3 + +[profile.release.package.ldk-server-client] +opt-level = 3 + +[profile.release.package.ldk-server-protos] +opt-level = 3 + [profile.dev] panic = "abort" diff --git a/ldk-server/.github/workflows/build.yml b/ldk-server/.github/workflows/build.yml deleted file mode 100644 index b6f8a9fa1..000000000 --- a/ldk-server/.github/workflows/build.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Continuous Integration Checks - -on: [ push, pull_request ] - -jobs: - build: - strategy: - matrix: - platform: [ - ubuntu-latest, - macos-latest, - ] - toolchain: - [ stable, - beta, - 1.85.0, # MSRV, same as ldk-node - ] - include: - - toolchain: stable - check-fmt: true - - toolchain: 1.85.0 - msrv: true - runs-on: ${{ matrix.platform }} - steps: - - name: Checkout source code - uses: actions/checkout@v3 - - name: Install Rust ${{ matrix.toolchain }} toolchain - run: | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ matrix.toolchain }} - rustup override set ${{ matrix.toolchain }} - if [ "${{ matrix.msrv }}" = "true" ]; then rustup component add clippy; fi - - name: Check formatting - if: matrix.check-fmt - run: rustup component add rustfmt && cargo fmt --all -- --check - - name: Pin packages to allow for MSRV - if: matrix.msrv - run: | # None needed yet - echo "No packages need pinning for MSRV ${{ matrix.toolchain }}" - - name: Build on Rust ${{ matrix.toolchain }} - run: cargo build --verbose --color always - - name: Check clippy if on msrv - if: matrix.msrv - run: cargo clippy --all-features -- -D warnings - - name: Test on Rust ${{ matrix.toolchain }} - run: cargo test - - name: Cargo check release on Rust ${{ matrix.toolchain }} - run: cargo check --release - - name: Cargo check doc on Rust ${{ matrix.toolchain }} - run: cargo doc --release diff --git a/ldk-server/.github/workflows/cron-weekly-rustfmt.yml b/ldk-server/.github/workflows/cron-weekly-rustfmt.yml deleted file mode 100644 index d6326f03b..000000000 --- a/ldk-server/.github/workflows/cron-weekly-rustfmt.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Nightly rustfmt - -permissions: - contents: write - pull-requests: write - -on: - schedule: - - cron: "0 0 * * 0" # runs weekly on Sunday at 00:00 - workflow_dispatch: # allows manual triggering -jobs: - format: - name: Nightly rustfmt - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v5 - - uses: dtolnay/rust-toolchain@nightly - with: - components: rustfmt - - name: Run Nightly rustfmt - # Run the formatter and manually remove trailing whitespace. - run: cargo +nightly fmt && git ls-files -- '*.rs' -z | xargs sed -E -i'' -e 's/[[:space:]]+$//' - - name: Get the current date - run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - - name: Create Pull Request - uses: peter-evans/create-pull-request@v7 - with: - author: Fmt Bot - title: Automated nightly rustfmt (${{ env.date }}) - body: | - Automated nightly `rustfmt` changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action - commit-message: ${{ env.date }} automated rustfmt nightly - labels: rustfmt diff --git a/ldk-server/Cargo.lock b/ldk-server/Cargo.lock deleted file mode 100644 index 538c97742..000000000 --- a/ldk-server/Cargo.lock +++ /dev/null @@ -1,4192 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "amq-protocol" -version = "7.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "587d313f3a8b4a40f866cc84b6059fe83133bf172165ac3b583129dd211d8e1c" -dependencies = [ - "amq-protocol-tcp", - "amq-protocol-types", - "amq-protocol-uri", - "cookie-factory", - "nom", - "serde", -] - -[[package]] -name = "amq-protocol-tcp" -version = "7.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc707ab9aa964a85d9fc25908a3fdc486d2e619406883b3105b48bf304a8d606" -dependencies = [ - "amq-protocol-uri", - "tcp-stream", - "tracing", -] - -[[package]] -name = "amq-protocol-types" -version = "7.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf99351d92a161c61ec6ecb213bc7057f5b837dd4e64ba6cb6491358efd770c4" -dependencies = [ - "cookie-factory", - "nom", - "serde", - "serde_json", -] - -[[package]] -name = "amq-protocol-uri" -version = "7.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89f8273826a676282208e5af38461a07fe939def57396af6ad5997fcf56577d" -dependencies = [ - "amq-protocol-types", - "percent-encoding", - "url", -] - -[[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.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" - -[[package]] -name = "anyhow" -version = "1.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "asn1-rs" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" -dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror", - "time", -] - -[[package]] -name = "asn1-rs-derive" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", - "synstructure", -] - -[[package]] -name = "asn1-rs-impl" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "async-channel" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand 2.3.0", - "futures-lite 2.6.1", - "pin-project-lite", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f937e26114b93193065fd44f507aa2e9169ad0cdabbb996920b1fe1ddea7ba" -dependencies = [ - "async-channel", - "async-executor", - "async-io 2.6.0", - "async-lock 3.4.1", - "blocking", - "futures-lite 2.6.1", -] - -[[package]] -name = "async-global-executor-trait" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af57045d58eeb1f7060e7025a1631cbc6399e0a1d10ad6735b3d0ea7f8346ce" -dependencies = [ - "async-global-executor", - "async-trait", - "executor-trait", -] - -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.28", - "slab", - "socket2 0.4.10", - "waker-fn", -] - -[[package]] -name = "async-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" -dependencies = [ - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite 2.6.1", - "parking", - "polling 3.11.0", - "rustix 1.1.2", - "slab", - "windows-sys 0.61.2", -] - -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - -[[package]] -name = "async-lock" -version = "3.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" -dependencies = [ - "event-listener 5.4.1", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-reactor-trait" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6012d170ad00de56c9ee354aef2e358359deb1ec504254e0e5a3774771de0e" -dependencies = [ - "async-io 1.13.0", - "async-trait", - "futures-core", - "reactor-trait", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "base58ck" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" -dependencies = [ - "bitcoin-internals 0.3.0", - "bitcoin_hashes 0.14.0", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" - -[[package]] -name = "bdk_chain" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b5d691fd092aacec7e05046b7d04897d58d6d65ed3152cb6cf65dababcfabed" -dependencies = [ - "bdk_core", - "bitcoin", - "miniscript", - "serde", -] - -[[package]] -name = "bdk_core" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dbbe4aad0c898bfeb5253c222be3ea3dccfb380a07e72c87e3e4ed6664a6753" -dependencies = [ - "bitcoin", - "hashbrown 0.14.5", - "serde", -] - -[[package]] -name = "bdk_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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f5961444b5f51b9c3937e729a212363d0e4cde6390ded6e01e16292078df4" -dependencies = [ - "async-trait", - "bdk_core", - "esplora-client", - "futures", -] - -[[package]] -name = "bdk_wallet" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b172f2caa6311b8172cf99559cd7f7a61cb58834e35e4ca208b3299e7be8bec" -dependencies = [ - "bdk_chain", - "bip39", - "bitcoin", - "miniscript", - "rand_core 0.6.4", - "serde", - "serde_json", -] - -[[package]] -name = "bech32" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" - -[[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.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d193de1f7487df1914d3a568b772458861d33f9c54249612cc2893d6915054" -dependencies = [ - "bitcoin_hashes 0.13.0", - "rand 0.8.5", - "rand_core 0.6.4", - "serde", - "unicode-normalization", -] - -[[package]] -name = "bitcoin" -version = "0.32.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda569d741b895131a88ee5589a467e73e9c4718e958ac9308e4f7dc44b6945" -dependencies = [ - "base58ck", - "base64 0.21.7", - "bech32", - "bitcoin-internals 0.3.0", - "bitcoin-io", - "bitcoin-units", - "bitcoin_hashes 0.14.0", - "hex-conservative 0.2.1", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" -dependencies = [ - "serde", -] - -[[package]] -name = "bitcoin-io" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" - -[[package]] -name = "bitcoin-payment-instructions" -version = "0.6.0" -source = "git+https://github.com/tnull/bitcoin-payment-instructions?rev=fdca6c62f2fe2c53427d3e51e322a49aa7323ee2#fdca6c62f2fe2c53427d3e51e322a49aa7323ee2" -dependencies = [ - "bitcoin", - "dnssec-prover", - "getrandom 0.3.4", - "lightning", - "lightning-invoice", -] - -[[package]] -name = "bitcoin-units" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" -dependencies = [ - "bitcoin-internals 0.3.0", - "serde", -] - -[[package]] -name = "bitcoin_hashes" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" -dependencies = [ - "bitcoin-internals 0.2.0", - "hex-conservative 0.1.2", -] - -[[package]] -name = "bitcoin_hashes" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" -dependencies = [ - "bitcoin-io", - "hex-conservative 0.2.1", - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blocking" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" -dependencies = [ - "async-channel", - "async-task", - "futures-io", - "futures-lite 2.6.1", - "piper", -] - -[[package]] -name = "bumpalo" -version = "3.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" -dependencies = [ - "serde", -] - -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher", -] - -[[package]] -name = "cc" -version = "1.2.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chacha20-poly1305" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b4b0fc281743d80256607bd65e8beedc42cb0787ea119c85b81b4c0eab85e5f" - -[[package]] -name = "chrono" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" -dependencies = [ - "iana-time-zone", - "num-traits", - "serde", - "windows-link", -] - -[[package]] -name = "chunked_transfer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "clap" -version = "4.5.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" -dependencies = [ - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_complete" -version = "4.5.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "430b4dc2b5e3861848de79627b2bedc9f3342c7da5173a14eaa5d0f8dc18ae5d" -dependencies = [ - "clap", -] - -[[package]] -name = "clap_derive" -version = "4.5.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "clap_lex" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" - -[[package]] -name = "cms" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b77c319abfd5219629c45c34c89ba945ed3c5e49fcde9d16b6c3885f118a730" -dependencies = [ - "const-oid", - "der", - "spki", - "x509-cert", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "cookie-factory" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "data-encoding" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" - -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "der_derive", - "flagset", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "der-parser" -version = "10.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" -dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", -] - -[[package]] -name = "der_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "deranged" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "des" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" -dependencies = [ - "cipher", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "dnssec-prover" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec4f825369fc7134da70ca4040fddc8e03b80a46d249ae38d9c1c39b7b4476bf" -dependencies = [ - "bitcoin_hashes 0.14.0", - "tokio", -] - -[[package]] -name = "doc-comment" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "electrum-client" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7b07e2578a6df0093b101915c79dca0119d7f7810099ad9eef11341d2ae57" -dependencies = [ - "bitcoin", - "byteorder", - "libc", - "log", - "rustls 0.23.34", - "serde", - "serde_json", - "webpki-roots 0.25.4", - "winapi", -] - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "esplora-client" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0af349d96a5d9ad77ba59f1437aa6f348b03c5865d4f7d6e7a662d60aedce39" -dependencies = [ - "bitcoin", - "hex-conservative 0.2.1", - "log", - "reqwest 0.12.24", - "serde", - "tokio", -] - -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener 5.4.1", - "pin-project-lite", -] - -[[package]] -name = "executor-trait" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c39dff9342e4e0e16ce96be751eb21a94e94a87bb2f6e63ad1961c2ce109bf" -dependencies = [ - "async-trait", -] - -[[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 = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "find-msvc-tools" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flagset" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" - -[[package]] -name = "flume" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" -dependencies = [ - "futures-core", - "futures-sink", - "spin", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-lite" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" -dependencies = [ - "fastrand 2.3.0", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi", - "wasip2", - "wasm-bindgen", -] - -[[package]] -name = "h2" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[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" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" - -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown 0.14.5", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" -dependencies = [ - "arrayvec", -] - -[[package]] -name = "hex_lit" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http 1.3.1", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http 1.3.1", - "http-body 1.0.1", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.10", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" -dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "http 1.3.1", - "http-body 1.0.1", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "pin-utils", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.32", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", -] - -[[package]] -name = "hyper-rustls" -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", - "hyper-util", - "rustls 0.23.34", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.26.4", - "tower-service", - "webpki-roots 1.0.3", -] - -[[package]] -name = "hyper-util" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "hyper 1.7.0", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2 0.6.1", - "tokio", - "tower-service", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" -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 = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" - -[[package]] -name = "icu_properties" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" - -[[package]] -name = "icu_provider" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" -dependencies = [ - "equivalent", - "hashbrown 0.16.0", -] - -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "block-padding", - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "iri-string" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "js-sys" -version = "0.3.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "lapin" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d2aa4725b9607915fa1a73e940710a3be6af508ce700e56897cbe8847fbb07" -dependencies = [ - "amq-protocol", - "async-global-executor-trait", - "async-reactor-trait", - "async-trait", - "executor-trait", - "flume", - "futures-core", - "futures-io", - "parking_lot", - "pinky-swear", - "reactor-trait", - "serde", - "tracing", - "waker-fn", -] - -[[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.8.0+git" -source = "git+https://github.com/lightningdevkit/ldk-node?rev=d1bbf978c8b7abe87ae2e40793556c1fe4e7ea49#d1bbf978c8b7abe87ae2e40793556c1fe4e7ea49" -dependencies = [ - "base64 0.22.1", - "bdk_chain", - "bdk_electrum", - "bdk_esplora", - "bdk_wallet", - "bip21", - "bip39", - "bitcoin", - "bitcoin-payment-instructions", - "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", - "rand 0.9.2", - "reqwest 0.12.24", - "rusqlite", - "rustls 0.23.34", - "serde", - "serde_json", - "tokio", - "vss-client-ng", - "winapi", -] - -[[package]] -name = "ldk-server" -version = "0.1.0" -dependencies = [ - "async-trait", - "base64 0.21.7", - "bytes", - "chrono", - "futures-util", - "hex-conservative 0.2.1", - "http-body-util", - "hyper 1.7.0", - "hyper-util", - "lapin", - "ldk-node", - "ldk-server-protos", - "log", - "prost", - "rand 0.8.5", - "rcgen", - "rusqlite", - "serde", - "tokio", - "tokio-rustls 0.26.4", - "toml", -] - -[[package]] -name = "ldk-server-cli" -version = "0.1.0" -dependencies = [ - "clap", - "clap_complete", - "hex-conservative 0.2.1", - "ldk-server-client", - "serde", - "serde_json", - "tokio", - "toml", -] - -[[package]] -name = "ldk-server-client" -version = "0.1.0" -dependencies = [ - "bitcoin_hashes 0.14.0", - "ldk-server-protos", - "prost", - "reqwest 0.11.27", -] - -[[package]] -name = "ldk-server-protos" -version = "0.1.0" -dependencies = [ - "bytes", - "prost", - "prost-build", - "serde", -] - -[[package]] -name = "libc" -version = "0.2.177" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" - -[[package]] -name = "libm" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" - -[[package]] -name = "libsqlite3-sys" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "lightning" -version = "0.3.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" -dependencies = [ - "bech32", - "bitcoin", - "dnssec-prover", - "hashbrown 0.13.2", - "libm", - "lightning-invoice", - "lightning-macros", - "lightning-types", - "musig2", - "possiblyrandom", -] - -[[package]] -name = "lightning-background-processor" -version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" -dependencies = [ - "bitcoin", - "bitcoin-io", - "bitcoin_hashes 0.14.0", - "lightning", - "lightning-liquidity", - "lightning-rapid-gossip-sync", - "possiblyrandom", -] - -[[package]] -name = "lightning-block-sync" -version = "0.3.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" -dependencies = [ - "bitcoin", - "chunked_transfer", - "lightning", - "serde_json", - "tokio", -] - -[[package]] -name = "lightning-invoice" -version = "0.34.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" -dependencies = [ - "bech32", - "bitcoin", - "lightning-types", - "serde", -] - -[[package]] -name = "lightning-liquidity" -version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" -dependencies = [ - "bitcoin", - "chrono", - "lightning", - "lightning-invoice", - "lightning-macros", - "lightning-types", - "serde", - "serde_json", -] - -[[package]] -name = "lightning-macros" -version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "lightning-net-tokio" -version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" -dependencies = [ - "bitcoin", - "lightning", - "tokio", -] - -[[package]] -name = "lightning-persister" -version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" -dependencies = [ - "bitcoin", - "lightning", - "tokio", - "windows-sys 0.48.0", -] - -[[package]] -name = "lightning-rapid-gossip-sync" -version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" -dependencies = [ - "bitcoin", - "bitcoin-io", - "bitcoin_hashes 0.14.0", - "lightning", -] - -[[package]] -name = "lightning-transaction-sync" -version = "0.2.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" -dependencies = [ - "bitcoin", - "electrum-client", - "esplora-client", - "futures", - "lightning", - "lightning-macros", -] - -[[package]] -name = "lightning-types" -version = "0.3.0+git" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" -dependencies = [ - "bitcoin", -] - -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" - -[[package]] -name = "litemap" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" - -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - -[[package]] -name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "minimal-lexical" -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 = "mio" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.61.2", -] - -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "musig2" -version = "0.1.0" -source = "git+https://github.com/arik-so/rust-musig2?rev=6f95a05718cbb44d8fe3fa6021aea8117aa38d50#6f95a05718cbb44d8fe3fa6021aea8117aa38d50" -dependencies = [ - "bitcoin", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "oid-registry" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" -dependencies = [ - "asn1-rs", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "p12-keystore" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cae83056e7cb770211494a0ecf66d9fa7eba7d00977e5bb91f0e925b40b937f" -dependencies = [ - "cbc", - "cms", - "der", - "des", - "hex", - "hmac", - "pkcs12", - "pkcs5", - "rand 0.9.2", - "rc2", - "sha1", - "sha2", - "thiserror", - "x509-parser", -] - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pinky-swear" -version = "6.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1ea6e230dd3a64d61bcb8b79e597d3ab6b4c94ec7a234ce687dd718b4f2e657" -dependencies = [ - "doc-comment", - "flume", - "parking_lot", - "tracing", -] - -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand 2.3.0", - "futures-io", -] - -[[package]] -name = "pkcs12" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "695b3df3d3cc1015f12d70235e35b6b79befc5fa7a9b95b951eab1dd07c9efc2" -dependencies = [ - "cms", - "const-oid", - "der", - "digest", - "spki", - "x509-cert", - "zeroize", -] - -[[package]] -name = "pkcs5" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" -dependencies = [ - "aes", - "cbc", - "der", - "pbkdf2", - "scrypt", - "sha2", - "spki", -] - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - -[[package]] -name = "polling" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.5.2", - "pin-project-lite", - "rustix 1.1.2", - "windows-sys 0.61.2", -] - -[[package]] -name = "possiblyrandom" -version = "0.2.0" -source = "git+https://github.com/lightningdevkit/rust-lightning?rev=5236dba053a3f4f01cf0c32ce42b609a93738891#5236dba053a3f4f01cf0c32ce42b609a93738891" -dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "potential_utf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "proc-macro2" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" -dependencies = [ - "bytes", - "heck 0.4.1", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 1.0.109", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost", -] - -[[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.34", - "socket2 0.6.1", - "thiserror", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" -dependencies = [ - "bytes", - "getrandom 0.3.4", - "lru-slab", - "rand 0.9.2", - "ring", - "rustc-hash", - "rustls 0.23.34", - "rustls-pki-types", - "slab", - "thiserror", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2 0.6.1", - "tracing", - "windows-sys 0.60.2", -] - -[[package]] -name = "quote" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.4", -] - -[[package]] -name = "rc2" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62c64daa8e9438b84aaae55010a93f396f8e60e3911590fcba770d04643fc1dd" -dependencies = [ - "cipher", -] - -[[package]] -name = "rcgen" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" -dependencies = [ - "ring", - "rustls-pki-types", - "time", - "yasna", -] - -[[package]] -name = "reactor-trait" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "438a4293e4d097556730f4711998189416232f009c137389e0f961d2bc0ddc58" -dependencies = [ - "async-trait", - "futures-core", - "futures-io", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags 2.10.0", -] - -[[package]] -name = "regex" -version = "1.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" - -[[package]] -name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper-rustls 0.24.2", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration", - "tokio", - "tokio-rustls 0.24.1", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots 0.25.4", - "winreg", -] - -[[package]] -name = "reqwest" -version = "0.12.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "hyper 1.7.0", - "hyper-rustls 0.27.7", - "hyper-util", - "js-sys", - "log", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls 0.23.34", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 1.0.2", - "tokio", - "tokio-rustls 0.26.4", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots 1.0.3", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rusqlite" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" -dependencies = [ - "bitflags 2.10.0", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", -] - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rusticata-macros" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" -dependencies = [ - "nom", -] - -[[package]] -name = "rustix" -version = "0.37.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.10.0", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" -dependencies = [ - "bitflags 2.10.0", - "errno", - "libc", - "linux-raw-sys 0.11.0", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.7", - "sct", -] - -[[package]] -name = "rustls" -version = "0.23.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" -dependencies = [ - "log", - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki 0.103.8", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-connector" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70cc376c6ba1823ae229bacf8ad93c136d93524eab0e4e5e0e4f96b9c4e5b212" -dependencies = [ - "log", - "rustls 0.23.34", - "rustls-native-certs", - "rustls-pki-types", - "rustls-webpki 0.103.8", -] - -[[package]] -name = "rustls-native-certs" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" -dependencies = [ - "openssl-probe", - "rustls-pemfile 2.2.0", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" -dependencies = [ - "web-time", - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher", -] - -[[package]] -name = "schannel" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scrypt" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" -dependencies = [ - "pbkdf2", - "salsa20", - "sha2", -] - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "secp256k1" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" -dependencies = [ - "bitcoin_hashes 0.14.0", - "rand 0.8.5", - "secp256k1-sys", - "serde", -] - -[[package]] -name = "secp256k1-sys" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" -dependencies = [ - "cc", -] - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.10.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "serde_json" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", - "serde_core", -] - -[[package]] -name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" -dependencies = [ - "libc", -] - -[[package]] -name = "slab" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tcp-stream" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495b0abdce3dc1f8fd27240651c9e68890c14e9d9c61527b1ce44d8a5a7bd3d5" -dependencies = [ - "cfg-if", - "p12-keystore", - "rustls-connector", - "rustls-pemfile 2.2.0", -] - -[[package]] -name = "tempfile" -version = "3.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" -dependencies = [ - "fastrand 2.3.0", - "getrandom 0.3.4", - "once_cell", - "rustix 1.1.2", - "windows-sys 0.61.2", -] - -[[package]] -name = "thiserror" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "time" -version = "0.3.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" - -[[package]] -name = "time-macros" -version = "0.2.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" -dependencies = [ - "bytes", - "libc", - "mio", - "pin-project-lite", - "signal-hook-registry", - "socket2 0.6.1", - "tokio-macros", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-macros" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" -dependencies = [ - "rustls 0.23.34", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper 1.0.2", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" -dependencies = [ - "bitflags 2.10.0", - "bytes", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "iri-string", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typenum" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[package]] -name = "unicode-ident" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" - -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "vss-client-ng" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c6bf7f2c3e22e62c638ad7d8c48dd5dc7e79033c5e088bdd797bbc815b29bb" -dependencies = [ - "async-trait", - "base64 0.22.1", - "bitcoin", - "bitcoin_hashes 0.14.0", - "chacha20-poly1305", - "prost", - "prost-build", - "rand 0.8.5", - "reqwest 0.12.24", - "serde", - "serde_json", - "tokio", - "url", -] - -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasip2" -version = "1.0.1+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.108", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - -[[package]] -name = "webpki-roots" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -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", - "windows-result", - "windows-strings", -] - -[[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.108", -] - -[[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.108", -] - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - -[[package]] -name = "winnow" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "wit-bindgen" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" - -[[package]] -name = "writeable" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - -[[package]] -name = "x509-cert" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" -dependencies = [ - "const-oid", - "der", - "spki", -] - -[[package]] -name = "x509-parser" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460" -dependencies = [ - "asn1-rs", - "data-encoding", - "der-parser", - "lazy_static", - "nom", - "oid-registry", - "rusticata-macros", - "thiserror", - "time", -] - -[[package]] -name = "yasna" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" -dependencies = [ - "time", -] - -[[package]] -name = "yoke" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.8.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" - -[[package]] -name = "zerotrie" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] diff --git a/ldk-server/Cargo.toml b/ldk-server/Cargo.toml deleted file mode 100644 index 16d6cedd5..000000000 --- a/ldk-server/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[workspace] -resolver = "2" -members = [ "ldk-server-cli", "ldk-server-client", "ldk-server-protos", "ldk-server"] - -[profile.release] -panic = "abort" -opt-level = 3 -lto = true - -[profile.dev] -panic = "abort" diff --git a/ldk-server/ldk-server/Cargo.toml b/ldk-server/ldk-server/Cargo.toml index 965c9604f..0d2fcec8d 100644 --- a/ldk-server/ldk-server/Cargo.toml +++ b/ldk-server/ldk-server/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -ldk-node = { git = "https://github.com/lightningdevkit/ldk-node", rev = "d1bbf978c8b7abe87ae2e40793556c1fe4e7ea49" } +ldk-node = { path = "../.." } serde = { version = "1.0.203", default-features = false, features = ["derive"] } hyper = { version = "1", default-features = false, features = ["server", "http1"] } http-body-util = { version = "0.1", default-features = false }