From 7dfe8432abbccbfd4eda3037b62e350e24ab29d4 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Wed, 25 Mar 2026 19:26:49 -0500 Subject: [PATCH] Replace REST and RabbitMQ with gRPC Consolidate the two separate communication protocols (protobuf over REST via Hyper, and RabbitMQ for events) into a single gRPC interface using tonic. This eliminates the RabbitMQ operational dependency and gives clients strongly-typed generated stubs. Events are now delivered via a server-streaming RPC backed by a tokio broadcast channel. HMAC auth moves to a tonic interceptor using timestamp-only signing since TLS guarantees body integrity. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/e2e-tests.yml | 23 + .../integration-tests-events-rabbitmq.yml | 57 - Cargo.lock | 1767 +++--------- e2e-tests/Cargo.lock | 1718 +++--------- e2e-tests/Cargo.toml | 5 +- e2e-tests/build.rs | 2 +- e2e-tests/src/lib.rs | 154 +- e2e-tests/tests/e2e.rs | 22 +- ldk-server-cli/src/config.rs | 24 +- ldk-server-cli/src/main.rs | 13 +- ldk-server-client/Cargo.toml | 7 +- ldk-server-client/src/client.rs | 436 +-- ldk-server-protos/Cargo.toml | 8 +- ldk-server-protos/build.rs | 16 +- ldk-server-protos/src/api.rs | 2432 ++++++++++++++++- ldk-server-protos/src/endpoints.rs | 45 - ldk-server-protos/src/error.rs | 12 +- ldk-server-protos/src/events.rs | 8 +- ldk-server-protos/src/lib.rs | 1 - ldk-server-protos/src/proto/api.proto | 80 + ldk-server-protos/src/serde_utils.rs | 6 +- ldk-server-protos/src/types.rs | 82 +- ldk-server/Cargo.toml | 21 +- ldk-server/ldk-server-config.toml | 7 +- ldk-server/src/api/bolt11_claim_for_hash.rs | 2 +- ldk-server/src/api/bolt11_fail_for_hash.rs | 2 +- ldk-server/src/api/bolt11_receive.rs | 2 +- ldk-server/src/api/bolt11_receive_for_hash.rs | 2 +- .../src/api/bolt11_receive_via_jit_channel.rs | 2 +- ldk-server/src/api/bolt11_send.rs | 2 +- ldk-server/src/api/bolt12_receive.rs | 2 +- ldk-server/src/api/bolt12_send.rs | 2 +- ldk-server/src/api/close_channel.rs | 2 +- ldk-server/src/api/connect_peer.rs | 2 +- ldk-server/src/api/disconnect_peer.rs | 2 +- ldk-server/src/api/error.rs | 2 +- .../src/api/export_pathfinding_scores.rs | 2 +- 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/graph_get_channel.rs | 2 +- ldk-server/src/api/graph_get_node.rs | 2 +- ldk-server/src/api/graph_list_channels.rs | 2 +- ldk-server/src/api/graph_list_nodes.rs | 2 +- ldk-server/src/api/list_channels.rs | 2 +- ldk-server/src/api/list_forwarded_payments.rs | 2 +- ldk-server/src/api/list_payments.rs | 2 +- ldk-server/src/api/list_peers.rs | 2 +- ldk-server/src/api/onchain_receive.rs | 2 +- ldk-server/src/api/onchain_send.rs | 2 +- ldk-server/src/api/open_channel.rs | 2 +- ldk-server/src/api/sign_message.rs | 2 +- ldk-server/src/api/splice_channel.rs | 2 +- ldk-server/src/api/spontaneous_send.rs | 2 +- ldk-server/src/api/unified_send.rs | 2 +- ldk-server/src/api/update_channel_config.rs | 2 +- ldk-server/src/api/verify_signature.rs | 2 +- ldk-server/src/grpc_service.rs | 401 +++ ldk-server/src/io/events/event_publisher.rs | 68 - ldk-server/src/io/events/mod.rs | 26 - ldk-server/src/io/events/rabbitmq/mod.rs | 244 -- ldk-server/src/io/mod.rs | 1 - ldk-server/src/main.rs | 365 ++- ldk-server/src/service.rs | 618 ----- ldk-server/src/util/config.rs | 181 +- ldk-server/src/util/proto_adapter.rs | 26 +- ldk-server/src/util/tls.rs | 158 +- 67 files changed, 4217 insertions(+), 4883 deletions(-) create mode 100644 .github/workflows/e2e-tests.yml delete mode 100644 .github/workflows/integration-tests-events-rabbitmq.yml delete mode 100644 ldk-server-protos/src/endpoints.rs create mode 100644 ldk-server/src/grpc_service.rs delete mode 100644 ldk-server/src/io/events/event_publisher.rs delete mode 100644 ldk-server/src/io/events/mod.rs delete mode 100644 ldk-server/src/io/events/rabbitmq/mod.rs delete mode 100644 ldk-server/src/service.rs diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml new file mode 100644 index 00000000..b1e2f668 --- /dev/null +++ b/.github/workflows/e2e-tests.yml @@ -0,0 +1,23 @@ +name: E2E Tests + +on: [ push, pull_request ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + e2e-tests: + runs-on: ubuntu-latest + steps: + - name: Checkout source code + uses: actions/checkout@v6 + - name: Install Rust stable toolchain + run: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain stable + - name: Install protoc + run: sudo apt-get install -y protobuf-compiler + - name: Run E2E tests + run: cd e2e-tests && cargo test + env: + RUST_LOG: info diff --git a/.github/workflows/integration-tests-events-rabbitmq.yml b/.github/workflows/integration-tests-events-rabbitmq.yml deleted file mode 100644 index 6caeb4a0..00000000 --- a/.github/workflows/integration-tests-events-rabbitmq.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: 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: Enable caching for bitcoind - id: cache-bitcoind - uses: actions/cache@v4 - with: - path: bin/bitcoind-${{ runner.os }}-${{ runner.arch }} - key: bitcoind-${{ runner.os }}-${{ runner.arch }} - - - name: Download bitcoind - if: steps.cache-bitcoind.outputs.cache-hit != 'true' - run: | - source ./scripts/download_bitcoind.sh - mkdir -p bin - mv "$BITCOIND_EXE" bin/bitcoind-${{ runner.os }}-${{ runner.arch }} - - - name: Set bitcoind environment variable - run: echo "BITCOIND_EXE=$( pwd )/bin/bitcoind-${{ runner.os }}-${{ runner.arch }}" >> "$GITHUB_ENV" - - - name: Run RabbitMQ integration tests - run: cargo test --features integration-tests-events-rabbitmq --verbose --color=always -- --nocapture - env: - RUST_BACKTRACE: 1 - - - name: Run end-to-end tests - run: cargo test --manifest-path e2e-tests/Cargo.toml --verbose --color=always -- --test-threads=4 --nocapture - env: - RUST_BACKTRACE: 1 - BITCOIND_SKIP_DOWNLOAD: 1 diff --git a/Cargo.lock b/Cargo.lock index b1e4f72f..280e4649 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,17 +2,6 @@ # 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" @@ -34,54 +23,6 @@ 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" @@ -110,38 +51,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] -name = "asn1-rs" -version = "0.7.1" +name = "async-stream" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror", - "time", + "async-stream-impl", + "futures-core", + "pin-project-lite", ] [[package]] -name = "asn1-rs-derive" -version = "0.6.0" +name = "async-stream-impl" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", "syn 2.0.108", - "synstructure", ] [[package]] -name = "asn1-rs-impl" -version = "0.2.0" +name = "async-trait" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", @@ -149,155 +84,64 @@ dependencies = [ ] [[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" +name = "atomic-waker" +version = "1.1.2" 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", -] +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] -name = "async-global-executor" -version = "3.1.0" +name = "autocfg" +version = "1.5.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", -] +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "async-global-executor-trait" -version = "2.2.0" +name = "axum" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af57045d58eeb1f7060e7025a1631cbc6399e0a1d10ad6735b3d0ea7f8346ce" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" 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", + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower 0.5.2", + "tower-layer", + "tower-service", ] [[package]] -name = "async-reactor-trait" -version = "1.1.0" +name = "axum-core" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6012d170ad00de56c9ee354aef2e358359deb1ec504254e0e5a3774771de0e" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" 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", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", ] -[[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" @@ -320,12 +164,6 @@ 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" @@ -498,12 +336,6 @@ dependencies = [ "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" @@ -525,37 +357,6 @@ dependencies = [ "webpki-roots 0.25.4", ] -[[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" @@ -577,15 +378,6 @@ 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" @@ -626,16 +418,6 @@ dependencies = [ "windows-link", ] -[[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" @@ -685,307 +467,106 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] -name = "cms" -version = "0.2.3" +name = "core-foundation-sys" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b77c319abfd5219629c45c34c89ba945ed3c5e49fcde9d16b6c3885f118a730" -dependencies = [ - "const-oid", - "der", - "spki", - "x509-cert", -] +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "concurrent-queue" -version = "2.5.0" +name = "displaydoc" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "crossbeam-utils", + "proc-macro2", + "quote", + "syn 2.0.108", ] [[package]] -name = "const-oid" -version = "0.9.6" +name = "dnssec-prover" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +checksum = "ec4f825369fc7134da70ca4040fddc8e03b80a46d249ae38d9c1c39b7b4476bf" +dependencies = [ + "bitcoin_hashes 0.14.0", + "tokio", +] [[package]] -name = "cookie-factory" -version = "0.3.3" +name = "either" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] -name = "core-foundation" -version = "0.9.4" +name = "electrum-client" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "ede7b07e2578a6df0093b101915c79dca0119d7f7810099ad9eef11341d2ae57" dependencies = [ - "core-foundation-sys", + "bitcoin", + "byteorder", "libc", + "log", + "rustls 0.23.34", + "serde", + "serde_json", + "webpki-roots 0.25.4", + "winapi", ] [[package]] -name = "core-foundation-sys" -version = "0.8.7" +name = "equivalent" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] -name = "cpufeatures" -version = "0.2.17" +name = "errno" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", + "windows-sys 0.61.2", ] [[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" +name = "esplora-client" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "a0af349d96a5d9ad77ba59f1437aa6f348b03c5865d4f7d6e7a662d60aedce39" dependencies = [ - "generic-array", - "typenum", + "bitcoin", + "hex-conservative 0.2.1", + "log", + "reqwest", + "serde", + "tokio", ] [[package]] -name = "data-encoding" -version = "2.9.0" +name = "fallible-iterator" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] -name = "der" -version = "0.7.10" +name = "fallible-streaming-iterator" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "der_derive", - "flagset", - "pem-rfc7468", - "zeroize", -] +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] -name = "der-parser" -version = "10.0.0" +name = "fastrand" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" -dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", -] +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[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" +name = "find-msvc-tools" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" @@ -995,23 +576,6 @@ 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" @@ -1075,34 +639,6 @@ 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" @@ -1144,16 +680,6 @@ dependencies = [ "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" @@ -1183,23 +709,29 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.27" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap", + "http", + "indexmap 2.12.0", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.13.2" @@ -1243,24 +775,6 @@ 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" @@ -1282,15 +796,6 @@ 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" @@ -1300,17 +805,6 @@ 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" @@ -1322,17 +816,6 @@ dependencies = [ "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" @@ -1340,7 +823,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.3.1", + "http", ] [[package]] @@ -1351,8 +834,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.3.1", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -1368,30 +851,6 @@ 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" @@ -1402,8 +861,9 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "http 1.3.1", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", "httpdate", "itoa", @@ -1414,28 +874,14 @@ dependencies = [ "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", + "http", + "hyper", "hyper-util", "rustls 0.23.34", "rustls-pki-types", @@ -1445,6 +891,19 @@ dependencies = [ "webpki-roots 1.0.3", ] +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.17" @@ -1456,9 +915,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "hyper 1.7.0", + "http", + "http-body", + "hyper", "ipnet", "libc", "percent-encoding", @@ -1597,42 +1056,22 @@ dependencies = [ [[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" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "cfg-if", + "autocfg", + "hashbrown 0.12.3", ] [[package]] -name = "io-lifetimes" -version = "1.0.11" +name = "indexmap" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", + "equivalent", + "hashbrown 0.16.0", ] [[package]] @@ -1676,28 +1115,6 @@ dependencies = [ "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" @@ -1737,7 +1154,7 @@ dependencies = [ "lightning-transaction-sync", "lightning-types", "log", - "prost", + "prost 0.11.9", "rusqlite", "rustls 0.23.34", "serde", @@ -1751,28 +1168,23 @@ dependencies = [ name = "ldk-server" version = "0.1.0" dependencies = [ - "async-trait", "base64 0.21.7", "bytes", "chrono", "clap", - "futures-util", "getrandom 0.2.16", "hex-conservative 0.2.1", - "http-body-util", - "hyper 1.7.0", - "hyper-util", - "lapin", "ldk-node", "ldk-server-protos", "log", - "prost", + "prost 0.13.5", "ring", "rusqlite", "serde", "tokio", - "tokio-rustls 0.26.4", + "tokio-stream", "toml", + "tonic", ] [[package]] @@ -1795,8 +1207,9 @@ version = "0.1.0" dependencies = [ "bitcoin_hashes 0.14.0", "ldk-server-protos", - "prost", - "reqwest 0.11.27", + "prost 0.13.5", + "tokio-stream", + "tonic", ] [[package]] @@ -1804,9 +1217,11 @@ name = "ldk-server-protos" version = "0.1.0" dependencies = [ "bytes", - "prost", - "prost-build", + "prost 0.13.5", + "prost-build 0.13.5", "serde", + "tonic", + "tonic-build", ] [[package]] @@ -1964,12 +1379,6 @@ 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" @@ -1988,15 +1397,6 @@ 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.29" @@ -2009,6 +1409,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "memchr" version = "2.7.6" @@ -2021,12 +1427,6 @@ 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" @@ -2063,41 +1463,6 @@ 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" @@ -2107,97 +1472,12 @@ 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" @@ -2217,73 +1497,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 2.12.0", ] [[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" +name = "pin-project" +version = "1.1.11" 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" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" dependencies = [ - "doc-comment", - "flume", - "parking_lot", - "tracing", + "pin-project-internal", ] [[package]] -name = "piper" -version = "0.2.4" +name = "pin-project-internal" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ - "atomic-waker", - "fastrand 2.3.0", - "futures-io", + "proc-macro2", + "quote", + "syn 2.0.108", ] [[package]] -name = "pkcs12" -version = "0.1.0" +name = "pin-project-lite" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "695b3df3d3cc1015f12d70235e35b6b79befc5fa7a9b95b951eab1dd07c9efc2" -dependencies = [ - "cms", - "const-oid", - "der", - "digest", - "spki", - "x509-cert", - "zeroize", -] +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] -name = "pkcs5" -version = "0.7.1" +name = "pin-utils" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" -dependencies = [ - "aes", - "cbc", - "der", - "pbkdf2", - "scrypt", - "sha2", - "spki", -] +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" @@ -2291,36 +1538,6 @@ 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" @@ -2338,12 +1555,6 @@ 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" @@ -2363,6 +1574,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.108", +] + [[package]] name = "proc-macro2" version = "1.0.103" @@ -2379,7 +1600,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.11.9", +] + +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive 0.13.5", ] [[package]] @@ -2395,15 +1626,35 @@ dependencies = [ "log", "multimap", "petgraph", - "prettyplease", - "prost", - "prost-types", + "prettyplease 0.1.25", + "prost 0.11.9", + "prost-types 0.11.9", "regex", "syn 1.0.109", "tempfile", "which", ] +[[package]] +name = "prost-build" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +dependencies = [ + "heck 0.5.0", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease 0.2.37", + "prost 0.13.5", + "prost-types 0.13.5", + "regex", + "syn 2.0.108", + "tempfile", +] + [[package]] name = "prost-derive" version = "0.11.9" @@ -2417,13 +1668,35 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.108", +] + [[package]] name = "prost-types" version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" dependencies = [ - "prost", + "prost 0.11.9", +] + +[[package]] +name = "prost-types" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +dependencies = [ + "prost 0.13.5", ] [[package]] @@ -2555,105 +1828,35 @@ 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 = "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", +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.12.24" @@ -2663,11 +1866,11 @@ dependencies = [ "base64 0.22.1", "bytes", "futures-core", - "http 1.3.1", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "hyper 1.7.0", - "hyper-rustls 0.27.7", + "hyper", + "hyper-rustls", "hyper-util", "js-sys", "log", @@ -2679,10 +1882,10 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tokio-rustls 0.26.4", - "tower", + "tower 0.5.2", "tower-http", "tower-service", "url", @@ -2712,7 +1915,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" dependencies = [ - "bitflags 2.10.0", + "bitflags", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -2726,36 +1929,13 @@ 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", + "bitflags", "errno", "libc", "linux-raw-sys 0.4.15", @@ -2768,7 +1948,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.10.0", + "bitflags", "errno", "libc", "linux-raw-sys 0.11.0", @@ -2781,7 +1961,6 @@ 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", @@ -2802,41 +1981,6 @@ dependencies = [ "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" @@ -2889,41 +2033,6 @@ 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" @@ -2955,29 +2064,6 @@ 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" @@ -3042,28 +2128,6 @@ 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.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" @@ -3091,16 +2155,6 @@ 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" @@ -3121,25 +2175,6 @@ dependencies = [ "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" @@ -3180,12 +2215,6 @@ dependencies = [ "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" @@ -3206,46 +2235,13 @@ dependencies = [ "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", + "fastrand", "getrandom 0.3.4", "once_cell", "rustix 1.1.2", @@ -3272,37 +2268,6 @@ dependencies = [ "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" @@ -3375,6 +2340,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + [[package]] name = "tokio-util" version = "0.7.16" @@ -3415,13 +2392,79 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap", + "indexmap 2.12.0", "serde", "serde_spanned", "toml_datetime", "winnow", ] +[[package]] +name = "tonic" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.22.1", + "bytes", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost 0.13.5", + "rustls-pemfile", + "socket2 0.5.10", + "tokio", + "tokio-rustls 0.26.4", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-build" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" +dependencies = [ + "prettyplease 0.2.37", + "proc-macro2", + "prost-build 0.13.5", + "prost-types 0.13.5", + "quote", + "syn 2.0.108", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower" version = "0.5.2" @@ -3431,7 +2474,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tower-layer", "tower-service", @@ -3443,14 +2486,14 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.10.0", + "bitflags", "bytes", "futures-util", - "http 1.3.1", - "http-body 1.0.1", + "http", + "http-body", "iri-string", "pin-project-lite", - "tower", + "tower 0.5.2", "tower-layer", "tower-service", ] @@ -3474,9 +2517,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.108", +] + [[package]] name = "tracing-core" version = "0.1.34" @@ -3492,12 +2547,6 @@ 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" @@ -3562,20 +2611,14 @@ dependencies = [ "bitreq", "chacha20-poly1305", "log", - "prost", - "prost-build", + "prost 0.11.9", + "prost-build 0.11.9", "rand 0.8.5", "serde", "serde_json", "tokio", ] -[[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" @@ -4026,16 +3069,6 @@ 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" @@ -4048,34 +3081,6 @@ 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 = "yoke" version = "0.8.1" diff --git a/e2e-tests/Cargo.lock b/e2e-tests/Cargo.lock index 07a6f7b9..a2e11638 100644 --- a/e2e-tests/Cargo.lock +++ b/e2e-tests/Cargo.lock @@ -8,17 +8,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - [[package]] name = "ahash" version = "0.8.12" @@ -40,54 +29,6 @@ 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" @@ -110,38 +51,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] -name = "asn1-rs" -version = "0.7.1" +name = "async-stream" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror", - "time", + "async-stream-impl", + "futures-core", + "pin-project-lite", ] [[package]] -name = "asn1-rs-derive" -version = "0.6.0" +name = "async-stream-impl" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", "syn 2.0.116", - "synstructure", ] [[package]] -name = "asn1-rs-impl" -version = "0.2.0" +name = "async-trait" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", @@ -149,155 +84,64 @@ dependencies = [ ] [[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.14.0" +name = "atomic-waker" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand 2.3.0", - "futures-lite 2.6.1", - "pin-project-lite", - "slab", -] +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] -name = "async-global-executor" -version = "3.1.0" +name = "autocfg" +version = "1.5.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.2", - "blocking", - "futures-lite 2.6.1", -] +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "async-global-executor-trait" -version = "2.2.0" +name = "axum" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af57045d58eeb1f7060e7025a1631cbc6399e0a1d10ad6735b3d0ea7f8346ce" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" 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.3", - "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.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" -dependencies = [ - "event-listener 5.4.1", - "event-listener-strategy", + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower 0.5.3", + "tower-layer", + "tower-service", ] [[package]] -name = "async-reactor-trait" -version = "1.1.0" +name = "axum-core" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6012d170ad00de56c9ee354aef2e358359deb1ec504254e0e5a3774771de0e" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" 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.116", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", ] -[[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" @@ -326,12 +170,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "base64ct" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" - [[package]] name = "bdk_chain" version = "0.23.2" @@ -488,49 +326,12 @@ dependencies = [ "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.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" -[[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.20.1" @@ -572,15 +373,6 @@ dependencies = [ "pkg-config", ] -[[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.56" @@ -627,59 +419,6 @@ 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 = "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" @@ -730,15 +469,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - [[package]] name = "crc32fast" version = "1.5.0" @@ -755,143 +485,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] -name = "crypto-common" -version = "0.1.7" +name = "displaydoc" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "generic-array", - "typenum", + "proc-macro2", + "quote", + "syn 2.0.116", ] [[package]] -name = "data-encoding" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" - -[[package]] -name = "der" -version = "0.7.10" +name = "dnssec-prover" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +checksum = "ec4f825369fc7134da70ca4040fddc8e03b80a46d249ae38d9c1c39b7b4476bf" dependencies = [ - "const-oid", - "der_derive", - "flagset", - "pem-rfc7468", - "zeroize", + "bitcoin_hashes", + "tokio", ] [[package]] -name = "der-parser" -version = "10.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +name = "e2e-tests" +version = "0.1.0" dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", + "corepc-node", + "hex-conservative", + "ldk-node", + "ldk-server-client", + "ldk-server-protos", + "serde_json", + "tempfile", + "tokio", + "tokio-stream", + "tonic", ] [[package]] -name = "der_derive" -version = "0.7.3" +name = "either" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.116", -] +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] -name = "deranged" -version = "0.5.6" +name = "electrum-client" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" -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.116", -] - -[[package]] -name = "dnssec-prover" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec4f825369fc7134da70ca4040fddc8e03b80a46d249ae38d9c1c39b7b4476bf" -dependencies = [ - "bitcoin_hashes", - "tokio", -] - -[[package]] -name = "doc-comment" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" - -[[package]] -name = "e2e-tests" -version = "0.1.0" -dependencies = [ - "corepc-node", - "futures-util", - "hex-conservative", - "lapin", - "ldk-node", - "ldk-server-client", - "ldk-server-protos", - "prost", - "serde_json", - "tempfile", - "tokio", -] - -[[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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5059f13888a90486e7268bbce59b175f5f76b1c55e5b9c568ceaa42d2b8507c" +checksum = "a5059f13888a90486e7268bbce59b175f5f76b1c55e5b9c568ceaa42d2b8507c" dependencies = [ "bitcoin", "byteorder", @@ -904,15 +544,6 @@ dependencies = [ "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" @@ -938,48 +569,12 @@ dependencies = [ "bitcoin", "hex-conservative", "log", - "reqwest 0.12.28", + "reqwest", "serde", "serde_json", "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" @@ -992,15 +587,6 @@ 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" @@ -1030,12 +616,6 @@ 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 = "flate2" version = "1.1.9" @@ -1046,17 +626,6 @@ dependencies = [ "miniz_oxide", ] -[[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" @@ -1126,34 +695,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" -[[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.32" @@ -1194,16 +735,6 @@ 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.17" @@ -1246,23 +777,29 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.27" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap", + "http", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.13.2" @@ -1315,24 +852,6 @@ 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.2.2" @@ -1348,15 +867,6 @@ 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" @@ -1366,17 +876,6 @@ 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.4.0" @@ -1387,17 +886,6 @@ dependencies = [ "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" @@ -1405,7 +893,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.0", + "http", ] [[package]] @@ -1416,8 +904,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -1433,30 +921,6 @@ 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.8.1" @@ -1467,9 +931,11 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "http 1.4.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", + "httpdate", "itoa", "pin-project-lite", "pin-utils", @@ -1480,33 +946,32 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.32", - "rustls 0.21.12", + "http", + "hyper", + "hyper-util", + "rustls 0.23.36", + "rustls-pki-types", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls", + "tower-service", + "webpki-roots 1.0.6", ] [[package]] -name = "hyper-rustls" -version = "0.27.7" +name = "hyper-timeout" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "http 1.4.0", - "hyper 1.8.1", + "hyper", "hyper-util", - "rustls 0.23.36", - "rustls-pki-types", + "pin-project-lite", "tokio", - "tokio-rustls 0.26.4", "tower-service", - "webpki-roots 1.0.6", ] [[package]] @@ -1519,14 +984,14 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.4.0", - "http-body 1.0.1", - "hyper 1.8.1", + "http", + "http-body", + "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.2", "tokio", "tower-service", "tracing", @@ -1664,6 +1129,16 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.13.0" @@ -1676,36 +1151,6 @@ dependencies = [ "serde_core", ] -[[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" @@ -1759,28 +1204,6 @@ dependencies = [ "serde_json", ] -[[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" @@ -1817,9 +1240,9 @@ dependencies = [ "lightning-transaction-sync", "lightning-types", "log", - "prost", + "prost 0.11.9", "rand 0.9.2", - "reqwest 0.12.28", + "reqwest", "rusqlite", "rustls 0.23.36", "serde", @@ -1835,8 +1258,9 @@ version = "0.1.0" dependencies = [ "bitcoin_hashes", "ldk-server-protos", - "prost", - "reqwest 0.11.27", + "prost 0.13.5", + "tokio-stream", + "tonic", ] [[package]] @@ -1844,9 +1268,11 @@ name = "ldk-server-protos" version = "0.1.0" dependencies = [ "bytes", - "prost", - "prost-build", + "prost 0.13.5", + "prost-build 0.13.5", "serde", + "tonic", + "tonic-build", ] [[package]] @@ -1873,9 +1299,9 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "bitflags 2.11.0", + "bitflags", "libc", - "redox_syscall 0.7.1", + "redox_syscall", ] [[package]] @@ -2021,12 +1447,6 @@ 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" @@ -2045,15 +1465,6 @@ 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.29" @@ -2066,6 +1477,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "memchr" version = "2.8.0" @@ -2078,12 +1495,6 @@ 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" @@ -2143,41 +1554,6 @@ 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.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" - -[[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" @@ -2187,97 +1563,12 @@ 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 0.5.18", - "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" @@ -2297,73 +1588,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 2.13.0", ] [[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" +name = "pin-project" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1ea6e230dd3a64d61bcb8b79e597d3ab6b4c94ec7a234ce687dd718b4f2e657" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" dependencies = [ - "doc-comment", - "flume", - "parking_lot", - "tracing", + "pin-project-internal", ] [[package]] -name = "piper" -version = "0.2.4" +name = "pin-project-internal" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ - "atomic-waker", - "fastrand 2.3.0", - "futures-io", + "proc-macro2", + "quote", + "syn 2.0.116", ] [[package]] -name = "pkcs12" -version = "0.1.0" +name = "pin-project-lite" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "695b3df3d3cc1015f12d70235e35b6b79befc5fa7a9b95b951eab1dd07c9efc2" -dependencies = [ - "cms", - "const-oid", - "der", - "digest", - "spki", - "x509-cert", - "zeroize", -] +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] -name = "pkcs5" -version = "0.7.1" +name = "pin-utils" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" -dependencies = [ - "aes", - "cbc", - "der", - "pbkdf2", - "scrypt", - "sha2", - "spki", -] +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" @@ -2371,36 +1629,6 @@ 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.3", - "windows-sys 0.61.2", -] - [[package]] name = "possiblyrandom" version = "0.2.0" @@ -2418,12 +1646,6 @@ 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" @@ -2469,7 +1691,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.11.9", +] + +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive 0.13.5", ] [[package]] @@ -2486,14 +1718,34 @@ dependencies = [ "multimap", "petgraph", "prettyplease 0.1.25", - "prost", - "prost-types", + "prost 0.11.9", + "prost-types 0.11.9", "regex", "syn 1.0.109", "tempfile", "which 4.4.2", ] +[[package]] +name = "prost-build" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +dependencies = [ + "heck 0.5.0", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease 0.2.37", + "prost 0.13.5", + "prost-types 0.13.5", + "regex", + "syn 2.0.116", + "tempfile", +] + [[package]] name = "prost-derive" version = "0.11.9" @@ -2507,13 +1759,35 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.116", +] + [[package]] name = "prost-types" version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" dependencies = [ - "prost", + "prost 0.11.9", +] + +[[package]] +name = "prost-types" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +dependencies = [ + "prost 0.13.5", ] [[package]] @@ -2529,7 +1803,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls 0.23.36", - "socket2 0.5.10", + "socket2 0.6.2", "thiserror", "tokio", "tracing", @@ -2566,9 +1840,9 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2 0.6.2", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -2645,42 +1919,13 @@ 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 = "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.11.0", -] - [[package]] name = "redox_syscall" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35985aa610addc02e24fc232012c86fd11f14111180f902b67e2d5331f8ebf2b" dependencies = [ - "bitflags 2.11.0", + "bitflags", ] [[package]] @@ -2688,71 +1933,30 @@ name = "regex" version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" - -[[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", +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", ] +[[package]] +name = "regex-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + [[package]] name = "reqwest" version = "0.12.28" @@ -2764,11 +1968,11 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "hyper 1.8.1", - "hyper-rustls 0.27.7", + "hyper", + "hyper-rustls", "hyper-util", "js-sys", "log", @@ -2780,10 +1984,10 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", - "tokio-rustls 0.26.4", - "tower", + "tokio-rustls", + "tower 0.5.3", "tower-http", "tower-service", "url", @@ -2813,7 +2017,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" dependencies = [ - "bitflags 2.11.0", + "bitflags", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -2827,36 +2031,13 @@ 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.11.0", + "bitflags", "errno", "libc", "linux-raw-sys 0.4.15", @@ -2869,7 +2050,7 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.11.0", + "bitflags", "errno", "libc", "linux-raw-sys 0.11.0", @@ -2903,41 +2084,6 @@ dependencies = [ "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.36", - "rustls-native-certs", - "rustls-pki-types", - "rustls-webpki 0.103.9", -] - -[[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" @@ -2990,41 +2136,6 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" -[[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" @@ -3056,29 +2167,6 @@ 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.11.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "321c8673b092a9a42605034a9879d73cb79101ed5fd117bc9a597b89b4e9e61a" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "1.0.27" @@ -3140,28 +2228,6 @@ 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.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" @@ -3186,16 +2252,6 @@ 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" @@ -3216,25 +2272,6 @@ dependencies = [ "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" @@ -3269,12 +2306,6 @@ dependencies = [ "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" @@ -3295,27 +2326,6 @@ dependencies = [ "syn 2.0.116", ] -[[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 = "tar" version = "0.4.44" @@ -3327,25 +2337,13 @@ dependencies = [ "xattr", ] -[[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.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" dependencies = [ - "fastrand 2.3.0", + "fastrand", "getrandom 0.4.1", "once_cell", "rustix 1.1.3", @@ -3372,37 +2370,6 @@ dependencies = [ "syn 2.0.116", ] -[[package]] -name = "time" -version = "0.3.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde_core", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" - -[[package]] -name = "time-macros" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" -dependencies = [ - "num-conv", - "time-core", -] - [[package]] name = "tinystr" version = "0.8.2" @@ -3456,21 +2423,22 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.21.12", + "rustls 0.23.36", "tokio", ] [[package]] -name = "tokio-rustls" -version = "0.26.4" +name = "tokio-stream" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ - "rustls 0.23.36", + "futures-core", + "pin-project-lite", "tokio", ] @@ -3487,6 +2455,72 @@ dependencies = [ "tokio", ] +[[package]] +name = "tonic" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.22.1", + "bytes", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost 0.13.5", + "rustls-pemfile", + "socket2 0.5.10", + "tokio", + "tokio-rustls", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-build" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" +dependencies = [ + "prettyplease 0.2.37", + "proc-macro2", + "prost-build 0.13.5", + "prost-types 0.13.5", + "quote", + "syn 2.0.116", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower" version = "0.5.3" @@ -3496,7 +2530,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tower-layer", "tower-service", @@ -3508,14 +2542,14 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.11.0", + "bitflags", "bytes", "futures-util", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "iri-string", "pin-project-lite", - "tower", + "tower 0.5.3", "tower-layer", "tower-service", ] @@ -3539,9 +2573,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.116", +] + [[package]] name = "tracing-core" version = "0.1.36" @@ -3557,12 +2603,6 @@ 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.24" @@ -3632,22 +2672,16 @@ dependencies = [ "bitcoin_hashes", "chacha20-poly1305", "log", - "prost", - "prost-build", + "prost 0.11.9", + "prost-build 0.11.9", "rand 0.8.5", - "reqwest 0.12.28", + "reqwest", "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" @@ -3757,7 +2791,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", - "indexmap", + "indexmap 2.13.0", "wasm-encoder", "wasmparser", ] @@ -3768,9 +2802,9 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.0", + "bitflags", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.13.0", "semver", ] @@ -4142,16 +3176,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" -[[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.51.0" @@ -4180,7 +3204,7 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck 0.5.0", - "indexmap", + "indexmap 2.13.0", "prettyplease 0.2.37", "syn 2.0.116", "wasm-metadata", @@ -4210,8 +3234,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.0", - "indexmap", + "bitflags", + "indexmap 2.13.0", "log", "serde", "serde_derive", @@ -4230,7 +3254,7 @@ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", - "indexmap", + "indexmap 2.13.0", "log", "semver", "serde", @@ -4246,34 +3270,6 @@ 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 = "xattr" version = "1.6.1" diff --git a/e2e-tests/Cargo.toml b/e2e-tests/Cargo.toml index 5576b7d2..cc4f7b36 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -11,7 +11,6 @@ ldk-server-client = { path = "../ldk-server-client" } ldk-server-protos = { path = "../ldk-server-protos", features = ["serde"] } serde_json = "1.0" hex-conservative = { version = "0.2", features = ["std"] } -lapin = { version = "2.4.0", features = ["rustls"], default-features = false } -prost = { version = "0.11.6", default-features = false, features = ["std"] } -futures-util = "0.3" +tonic = { version = "0.12" } +tokio-stream = { version = "0.1", default-features = false } ldk-node = { git = "https://github.com/lightningdevkit/ldk-node", rev = "d1bbf978c8b7abe87ae2e40793556c1fe4e7ea49" } diff --git a/e2e-tests/build.rs b/e2e-tests/build.rs index 6701b3d0..2dc67c30 100644 --- a/e2e-tests/build.rs +++ b/e2e-tests/build.rs @@ -21,7 +21,7 @@ fn main() { "-p", "ldk-server", "--features", - "events-rabbitmq,experimental-lsps2-support", + "experimental-lsps2-support", "-p", "ldk-server-cli", ]) diff --git a/e2e-tests/src/lib.rs b/e2e-tests/src/lib.rs index 083c08e7..0d380193 100644 --- a/e2e-tests/src/lib.rs +++ b/e2e-tests/src/lib.rs @@ -87,13 +87,12 @@ impl TestBitcoind { /// Handle to a running ldk-server child process. pub struct LdkServerHandle { child: Option, - pub rest_port: u16, + pub grpc_port: u16, pub p2p_port: u16, pub storage_dir: PathBuf, pub api_key: String, pub tls_cert_path: PathBuf, pub node_id: String, - pub exchange_name: String, client: LdkServerClient, } @@ -103,19 +102,17 @@ impl LdkServerHandle { pub async fn start(bitcoind: &TestBitcoind) -> Self { #[allow(deprecated)] let storage_dir = tempfile::tempdir().unwrap().into_path(); - let rest_port = find_available_port(); + let grpc_port = find_available_port(); let p2p_port = find_available_port(); let (rpc_host, rpc_port_num, rpc_user, rpc_password) = bitcoind.rpc_details(); let rpc_address = format!("{rpc_host}:{rpc_port_num}"); - let exchange_name = format!("e2e_test_exchange_{rest_port}"); - let config_content = format!( r#"[node] network = "regtest" listening_addresses = ["127.0.0.1:{p2p_port}"] -rest_service_address = "127.0.0.1:{rest_port}" +grpc_service_address = "127.0.0.1:{grpc_port}" alias = "e2e-test-node" [storage.disk] @@ -126,10 +123,6 @@ rpc_address = "{rpc_address}" rpc_user = "{rpc_user}" rpc_password = "{rpc_password}" -[rabbitmq] -connection_string = "amqp://guest:guest@localhost:5672/%2f" -exchange_name = "{exchange_name}" - [liquidity.lsps2_service] advertise_service = false channel_opening_fee_ppm = 10000 @@ -191,18 +184,17 @@ client_trusts_lsp = true // Read TLS cert let tls_cert_pem = std::fs::read(&tls_cert_path).unwrap(); - let base_url = format!("127.0.0.1:{rest_port}"); - let client = LdkServerClient::new(base_url, api_key.clone(), &tls_cert_pem).unwrap(); + let base_url = format!("127.0.0.1:{grpc_port}"); + let client = LdkServerClient::new(base_url, api_key.clone(), &tls_cert_pem).await.unwrap(); let mut handle = Self { child: Some(child), - rest_port, + grpc_port, p2p_port, storage_dir, api_key, tls_cert_path, node_id: String::new(), - exchange_name, client, }; @@ -222,7 +214,7 @@ client_trusts_lsp = true } pub fn base_url(&self) -> String { - format!("127.0.0.1:{}", self.rest_port) + format!("127.0.0.1:{}", self.grpc_port) } } @@ -350,22 +342,26 @@ pub async fn wait_for_usable_channel( ) { let start = std::time::Instant::now(); loop { - let channels = client.list_channels(ListChannelsRequest {}).await.unwrap(); - if channels.channels.iter().any(|c| c.is_usable) { - return; - } - if start.elapsed() > timeout { - let chan_info: Vec<_> = channels - .channels - .iter() - .map(|c| { - format!( - "id={} is_ready={} is_usable={} value={}", - c.user_channel_id, c.is_channel_ready, c.is_usable, c.channel_value_sats - ) - }) - .collect(); - panic!("Timed out waiting for usable channel. Channels: {:?}", chan_info); + if let Ok(channels) = client.list_channels(ListChannelsRequest {}).await { + if channels.channels.iter().any(|c| c.is_usable) { + return; + } + if start.elapsed() > timeout { + let chan_info: Vec<_> = channels + .channels + .iter() + .map(|c| { + format!( + "id={} is_ready={} is_usable={} value={}", + c.user_channel_id, c.is_channel_ready, c.is_usable, + c.channel_value_sats + ) + }) + .collect(); + panic!("Timed out waiting for usable channel. Channels: {:?}", chan_info); + } + } else if start.elapsed() > timeout { + panic!("Timed out waiting for usable channel (connection error)"); } // Mine a block to trigger chain sync in the LDK nodes bitcoind.mine_blocks(1); @@ -377,9 +373,10 @@ pub async fn wait_for_usable_channel( pub async fn wait_for_onchain_balance(client: &LdkServerClient, timeout: Duration) { let start = std::time::Instant::now(); loop { - let bal = client.get_balances(GetBalancesRequest {}).await.unwrap(); - if bal.spendable_onchain_balance_sats > 0 { - return; + if let Ok(bal) = client.get_balances(GetBalancesRequest {}).await { + if bal.spendable_onchain_balance_sats > 0 { + return; + } } if start.elapsed() > timeout { panic!("Timed out waiting for on-chain balance"); @@ -428,95 +425,28 @@ pub async fn setup_funded_channel( open_resp.user_channel_id } -/// RabbitMQ event consumer for verifying events published by ldk-server. -pub struct RabbitMqEventConsumer { - _connection: lapin::Connection, - channel: lapin::Channel, - consumer: lapin::Consumer, +/// gRPC event stream consumer for verifying events published by ldk-server. +pub struct GrpcEventConsumer { + stream: tonic::Streaming, } -impl RabbitMqEventConsumer { - /// Connect to RabbitMQ and create an exclusive queue bound to the given exchange. - pub async fn new(exchange_name: &str) -> Self { - use lapin::options::{ - BasicConsumeOptions, ExchangeDeclareOptions, QueueBindOptions, QueueDeclareOptions, - }; - use lapin::types::FieldTable; - use lapin::{ConnectionProperties, ExchangeKind}; - - let connection = lapin::Connection::connect( - "amqp://guest:guest@localhost:5672/%2f", - ConnectionProperties::default(), - ) - .await - .expect("Failed to connect to RabbitMQ"); - - let channel = connection.create_channel().await.expect("Failed to create channel"); - - // Declare exchange (idempotent — may already exist from the server) - channel - .exchange_declare( - exchange_name, - ExchangeKind::Fanout, - ExchangeDeclareOptions { durable: true, ..Default::default() }, - FieldTable::default(), - ) - .await - .expect("Failed to declare exchange"); - - // Create exclusive auto-delete queue with server-generated name - let queue = channel - .queue_declare( - "", - QueueDeclareOptions { exclusive: true, auto_delete: true, ..Default::default() }, - FieldTable::default(), - ) - .await - .expect("Failed to declare queue"); - let queue_name = queue.name().to_string(); - - channel - .queue_bind( - &queue_name, - exchange_name, - "", - QueueBindOptions::default(), - FieldTable::default(), - ) - .await - .expect("Failed to bind queue"); - - let consumer = channel - .basic_consume( - &queue_name, - &format!("consumer_{}", queue_name), - BasicConsumeOptions::default(), - FieldTable::default(), - ) - .await - .expect("Failed to start consumer"); - - Self { _connection: connection, channel, consumer } +impl GrpcEventConsumer { + /// Subscribe to the event stream from the given server. + pub async fn new(client: &LdkServerClient) -> Self { + let stream = client.subscribe_events().await.expect("Failed to subscribe to events"); + Self { stream } } /// Consume up to `count` events, waiting up to `timeout` for each. pub async fn consume_events( &mut self, count: usize, timeout: Duration, ) -> Vec { - use futures_util::StreamExt; - use lapin::options::BasicAckOptions; - use prost::Message; + use tokio_stream::StreamExt; let mut events = Vec::new(); for _ in 0..count { - match tokio::time::timeout(timeout, self.consumer.next()).await { - Ok(Some(Ok(delivery))) => { - let event = ldk_server_protos::events::EventEnvelope::decode(&*delivery.data) - .expect("Failed to decode event"); - self.channel - .basic_ack(delivery.delivery_tag, BasicAckOptions::default()) - .await - .expect("Failed to ack"); + match tokio::time::timeout(timeout, self.stream.next()).await { + Ok(Some(Ok(event))) => { events.push(event); }, _ => break, diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 577b74c1..e7d24141 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -12,7 +12,7 @@ use std::time::Duration; use e2e_tests::{ find_available_port, mine_and_sync, run_cli, run_cli_raw, setup_funded_channel, - wait_for_onchain_balance, LdkServerHandle, RabbitMqEventConsumer, TestBitcoind, + wait_for_onchain_balance, GrpcEventConsumer, LdkServerHandle, TestBitcoind, }; use hex_conservative::{DisplayHex, FromHex}; use ldk_node::bitcoin::hashes::{sha256, Hash}; @@ -285,8 +285,8 @@ async fn test_cli_bolt11_send() { let server_b = LdkServerHandle::start(&bitcoind).await; // Set up event consumers before any payments - let mut consumer_a = RabbitMqEventConsumer::new(&server_a.exchange_name).await; - let mut consumer_b = RabbitMqEventConsumer::new(&server_b.exchange_name).await; + let mut consumer_a = GrpcEventConsumer::new(server_a.client()).await; + let mut consumer_b = GrpcEventConsumer::new(server_b.client()).await; setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await; @@ -390,8 +390,8 @@ async fn test_cli_spontaneous_send() { let server_a = LdkServerHandle::start(&bitcoind).await; let server_b = LdkServerHandle::start(&bitcoind).await; - let mut consumer_a = RabbitMqEventConsumer::new(&server_a.exchange_name).await; - let mut consumer_b = RabbitMqEventConsumer::new(&server_b.exchange_name).await; + let mut consumer_a = GrpcEventConsumer::new(server_a.client()).await; + let mut consumer_b = GrpcEventConsumer::new(server_b.client()).await; setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await; @@ -614,8 +614,8 @@ async fn test_forwarded_payment_event() { // B: LSP node (all e2e servers include LSPS2 service config) let server_b = LdkServerHandle::start(&bitcoind).await; - // Set up RabbitMQ consumer on B before any payments - let mut consumer_b = RabbitMqEventConsumer::new(&server_b.exchange_name).await; + // Set up event consumer on B before any payments + let mut consumer_b = GrpcEventConsumer::new(server_b.client()).await; // Open channel A -> B (1M sats, larger for JIT forwarding) setup_funded_channel(&bitcoind, &server_a, &server_b, 1_000_000).await; @@ -692,8 +692,8 @@ async fn test_hodl_invoice_claim() { let server_a = LdkServerHandle::start(&bitcoind).await; let server_b = LdkServerHandle::start(&bitcoind).await; - let mut consumer_a = RabbitMqEventConsumer::new(&server_a.exchange_name).await; - let mut consumer_b = RabbitMqEventConsumer::new(&server_b.exchange_name).await; + let mut consumer_a = GrpcEventConsumer::new(server_a.client()).await; + let mut consumer_b = GrpcEventConsumer::new(server_b.client()).await; setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await; @@ -774,8 +774,8 @@ async fn test_hodl_invoice_fail() { let server_b = LdkServerHandle::start(&bitcoind).await; // Set up event consumers before any payments - let mut consumer_a = RabbitMqEventConsumer::new(&server_a.exchange_name).await; - let mut consumer_b = RabbitMqEventConsumer::new(&server_b.exchange_name).await; + let mut consumer_a = GrpcEventConsumer::new(server_a.client()).await; + let mut consumer_b = GrpcEventConsumer::new(server_b.client()).await; setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await; diff --git a/ldk-server-cli/src/config.rs b/ldk-server-cli/src/config.rs index 8cf0276b..2071f344 100644 --- a/ldk-server-cli/src/config.rs +++ b/ldk-server-cli/src/config.rs @@ -14,7 +14,7 @@ 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"; -pub const DEFAULT_REST_SERVICE_ADDRESS: &str = "127.0.0.1:3536"; +pub const DEFAULT_GRPC_SERVICE_ADDRESS: &str = "127.0.0.1:3536"; pub fn get_default_data_dir() -> Option { #[cfg(target_os = "macos")] @@ -67,8 +67,8 @@ pub struct TlsConfig { #[derive(Debug, Deserialize)] pub struct NodeConfig { - #[serde(default = "default_rest_service_address")] - pub rest_service_address: String, + #[serde(default = "default_grpc_service_address")] + pub grpc_service_address: String, network: String, } @@ -104,20 +104,20 @@ pub fn load_config(path: &PathBuf) -> Result { pub fn resolve_base_url(cli_base_url: Option, config: Option<&Config>) -> String { cli_base_url - .or_else(|| config.map(|config| config.node.rest_service_address.clone())) - .unwrap_or_else(default_rest_service_address) + .or_else(|| config.map(|config| config.node.grpc_service_address.clone())) + .unwrap_or_else(default_grpc_service_address) } -fn default_rest_service_address() -> String { - DEFAULT_REST_SERVICE_ADDRESS.to_string() +fn default_grpc_service_address() -> String { + DEFAULT_GRPC_SERVICE_ADDRESS.to_string() } #[cfg(test)] mod tests { - use super::{resolve_base_url, Config, DEFAULT_REST_SERVICE_ADDRESS}; + use super::{resolve_base_url, Config, DEFAULT_GRPC_SERVICE_ADDRESS}; #[test] - fn config_defaults_rest_service_address() { + fn config_defaults_grpc_service_address() { let config: Config = toml::from_str( r#" [node] @@ -126,7 +126,7 @@ mod tests { ) .unwrap(); - assert_eq!(config.node.rest_service_address, DEFAULT_REST_SERVICE_ADDRESS); + assert_eq!(config.node.grpc_service_address, DEFAULT_GRPC_SERVICE_ADDRESS); } #[test] @@ -135,7 +135,7 @@ mod tests { r#" [node] network = "regtest" - rest_service_address = "127.0.0.1:3002" + grpc_service_address = "127.0.0.1:3002" "#, ) .unwrap(); @@ -148,6 +148,6 @@ mod tests { #[test] fn resolve_base_url_falls_back_to_default() { - assert_eq!(resolve_base_url(None, None), DEFAULT_REST_SERVICE_ADDRESS); + assert_eq!(resolve_base_url(None, None), DEFAULT_GRPC_SERVICE_ADDRESS); } } diff --git a/ldk-server-cli/src/main.rs b/ldk-server-cli/src/main.rs index 89623d44..e12594da 100644 --- a/ldk-server-cli/src/main.rs +++ b/ldk-server-cli/src/main.rs @@ -14,7 +14,7 @@ use clap_complete::{generate, Shell}; use config::{ api_key_path_for_storage_dir, cert_path_for_storage_dir, get_default_api_key_path, get_default_cert_path, get_default_config_path, load_config, resolve_base_url, - DEFAULT_REST_SERVICE_ADDRESS, + DEFAULT_GRPC_SERVICE_ADDRESS, }; use hex_conservative::DisplayHex; use ldk_server_client::client::LdkServerClient; @@ -84,7 +84,7 @@ struct Cli { short, long, help = format!( - "Base URL of the server. Defaults to config file or {DEFAULT_REST_SERVICE_ADDRESS}" + "Base URL of the server. Defaults to config file or {DEFAULT_GRPC_SERVICE_ADDRESS}" ) )] base_url: Option, @@ -600,10 +600,11 @@ async fn main() { 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); - }); + let client = + LdkServerClient::new(base_url, api_key, &server_cert_pem).await.unwrap_or_else(|e| { + eprintln!("Failed to create client: {e}"); + std::process::exit(1); + }); match cli.command { Commands::GetNodeInfo => { diff --git a/ldk-server-client/Cargo.toml b/ldk-server-client/Cargo.toml index 13916fa3..848105b6 100644 --- a/ldk-server-client/Cargo.toml +++ b/ldk-server-client/Cargo.toml @@ -8,7 +8,8 @@ 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"] } -prost = { version = "0.11.6", default-features = false, features = ["std", "prost-derive"] } +ldk-server-protos = { path = "../ldk-server-protos", features = ["client"] } +tonic = { version = "0.12", features = ["tls"] } +prost = { version = "0.13", default-features = false, features = ["std", "prost-derive"] } bitcoin_hashes = "0.14" +tokio-stream = { version = "0.1", default-features = false } diff --git a/ldk-server-client/src/client.rs b/ldk-server-client/src/client.rs index 75459a45..dfa5dd63 100644 --- a/ldk-server-client/src/client.rs +++ b/ldk-server-client/src/client.rs @@ -11,62 +11,54 @@ use std::time::{SystemTime, UNIX_EPOCH}; use bitcoin_hashes::hmac::{Hmac, HmacEngine}; use bitcoin_hashes::{sha256, Hash, HashEngine}; -use ldk_server_protos::api::{ - Bolt11ClaimForHashRequest, Bolt11ClaimForHashResponse, Bolt11FailForHashRequest, - Bolt11FailForHashResponse, Bolt11ReceiveForHashRequest, Bolt11ReceiveForHashResponse, - Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11ReceiveVariableAmountViaJitChannelRequest, - Bolt11ReceiveVariableAmountViaJitChannelResponse, Bolt11ReceiveViaJitChannelRequest, - Bolt11ReceiveViaJitChannelResponse, Bolt11SendRequest, Bolt11SendResponse, - Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, - CloseChannelRequest, CloseChannelResponse, ConnectPeerRequest, ConnectPeerResponse, - DisconnectPeerRequest, DisconnectPeerResponse, ExportPathfindingScoresRequest, - ExportPathfindingScoresResponse, ForceCloseChannelRequest, ForceCloseChannelResponse, - GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse, - GetPaymentDetailsRequest, GetPaymentDetailsResponse, GraphGetChannelRequest, - GraphGetChannelResponse, GraphGetNodeRequest, GraphGetNodeResponse, GraphListChannelsRequest, - GraphListChannelsResponse, GraphListNodesRequest, GraphListNodesResponse, ListChannelsRequest, - ListChannelsResponse, ListForwardedPaymentsRequest, ListForwardedPaymentsResponse, - ListPaymentsRequest, ListPaymentsResponse, ListPeersRequest, ListPeersResponse, - OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, - OpenChannelRequest, OpenChannelResponse, SignMessageRequest, SignMessageResponse, - SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse, SpontaneousSendRequest, - SpontaneousSendResponse, UnifiedSendRequest, UnifiedSendResponse, UpdateChannelConfigRequest, - UpdateChannelConfigResponse, VerifySignatureRequest, VerifySignatureResponse, -}; -use ldk_server_protos::endpoints::{ - BOLT11_CLAIM_FOR_HASH_PATH, BOLT11_FAIL_FOR_HASH_PATH, BOLT11_RECEIVE_FOR_HASH_PATH, - BOLT11_RECEIVE_PATH, BOLT11_RECEIVE_VARIABLE_AMOUNT_VIA_JIT_CHANNEL_PATH, - BOLT11_RECEIVE_VIA_JIT_CHANNEL_PATH, BOLT11_SEND_PATH, BOLT12_RECEIVE_PATH, BOLT12_SEND_PATH, - CLOSE_CHANNEL_PATH, CONNECT_PEER_PATH, DISCONNECT_PEER_PATH, EXPORT_PATHFINDING_SCORES_PATH, - FORCE_CLOSE_CHANNEL_PATH, GET_BALANCES_PATH, GET_NODE_INFO_PATH, GET_PAYMENT_DETAILS_PATH, - GRAPH_GET_CHANNEL_PATH, GRAPH_GET_NODE_PATH, GRAPH_LIST_CHANNELS_PATH, GRAPH_LIST_NODES_PATH, - LIST_CHANNELS_PATH, LIST_FORWARDED_PAYMENTS_PATH, LIST_PAYMENTS_PATH, LIST_PEERS_PATH, - ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SIGN_MESSAGE_PATH, SPLICE_IN_PATH, - SPLICE_OUT_PATH, SPONTANEOUS_SEND_PATH, UNIFIED_SEND_PATH, UPDATE_CHANNEL_CONFIG_PATH, - VERIFY_SIGNATURE_PATH, -}; -use ldk_server_protos::error::{ErrorCode, ErrorResponse}; -use prost::Message; -use reqwest::header::CONTENT_TYPE; -use reqwest::{Certificate, Client}; +use ldk_server_protos::api::lightning_node_client::LightningNodeClient; +use ldk_server_protos::api::*; +use ldk_server_protos::events::EventEnvelope; +use tonic::metadata::MetadataValue; +use tonic::service::interceptor::InterceptedService; +use tonic::service::Interceptor; +use tonic::transport::{Certificate, Channel, ClientTlsConfig, Endpoint}; +use tonic::{Request, Status}; use crate::error::LdkServerError; use crate::error::LdkServerErrorCode::{ AuthError, InternalError, InternalServerError, InvalidRequestError, LightningError, }; -const APPLICATION_OCTET_STREAM: &str = "application/octet-stream"; +/// Interceptor that computes and attaches HMAC auth metadata to each gRPC request. +#[derive(Clone)] +struct AuthInterceptor { + api_key: String, +} + +impl Interceptor for AuthInterceptor { + fn call(&mut self, mut request: Request<()>) -> Result, Status> { + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("System time should be after Unix epoch") + .as_secs(); + + let mut hmac_engine: HmacEngine = HmacEngine::new(self.api_key.as_bytes()); + hmac_engine.input(×tamp.to_be_bytes()); + let hmac_result = Hmac::::from_engine(hmac_engine); + + let auth_value = format!("HMAC {}:{}", timestamp, hmac_result); + let meta_value = MetadataValue::try_from(&auth_value) + .map_err(|_| Status::internal("Failed to encode auth header"))?; + request.metadata_mut().insert("x-auth", meta_value); -/// Client to access a hosted instance of LDK Server. + Ok(request) + } +} + +/// Client to access a hosted instance of LDK Server via gRPC. /// /// The client requires the server's TLS certificate to be provided for verification. /// This certificate can be found at `/tls.crt` after the /// server generates it on first startup. #[derive(Clone)] pub struct LdkServerClient { - base_url: String, - client: Client, - api_key: String, + inner: LightningNodeClient>, } impl LdkServerClient { @@ -76,33 +68,24 @@ impl LdkServerClient { /// `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.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}"))?; + pub async fn new( + base_url: String, api_key: String, server_cert_pem: &[u8], + ) -> Result { + let cert = Certificate::from_pem(server_cert_pem); + let tls_config = ClientTlsConfig::new().ca_certificate(cert); - let client = Client::builder() - .add_root_certificate(cert) - .build() - .map_err(|e| format!("Failed to build HTTP client: {e}"))?; + let endpoint = Endpoint::from_shared(format!("https://{}", base_url)) + .map_err(|e| format!("Invalid endpoint URL: {e}"))? + .tls_config(tls_config) + .map_err(|e| format!("Failed to configure TLS: {e}"))?; - Ok(Self { base_url, client, api_key }) - } + let channel = + endpoint.connect().await.map_err(|e| format!("Failed to connect to server: {e}"))?; - /// 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); + let interceptor = AuthInterceptor { api_key }; + let inner = LightningNodeClient::with_interceptor(channel, interceptor); - format!("HMAC {}:{}", timestamp, hmac_result) + Ok(Self { inner }) } /// Retrieve the latest node info like `node_id`, `current_best_block` etc. @@ -110,8 +93,7 @@ impl LdkServerClient { pub async fn get_node_info( &self, request: GetNodeInfoRequest, ) -> Result { - let url = format!("https://{}/{GET_NODE_INFO_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().get_node_info(request).await.map(|r| r.into_inner()).map_err(from_status) } /// Retrieves an overview of all known balances. @@ -119,8 +101,7 @@ impl LdkServerClient { pub async fn get_balances( &self, request: GetBalancesRequest, ) -> Result { - let url = format!("https://{}/{GET_BALANCES_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().get_balances(request).await.map(|r| r.into_inner()).map_err(from_status) } /// Retrieve a new on-chain funding address. @@ -128,8 +109,12 @@ impl LdkServerClient { pub async fn onchain_receive( &self, request: OnchainReceiveRequest, ) -> Result { - let url = format!("https://{}/{ONCHAIN_RECEIVE_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .onchain_receive(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Send an on-chain payment to the given address. @@ -137,8 +122,7 @@ impl LdkServerClient { pub async fn onchain_send( &self, request: OnchainSendRequest, ) -> Result { - let url = format!("https://{}/{ONCHAIN_SEND_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().onchain_send(request).await.map(|r| r.into_inner()).map_err(from_status) } /// Retrieve a new BOLT11 payable invoice. @@ -146,60 +130,72 @@ impl LdkServerClient { pub async fn bolt11_receive( &self, request: Bolt11ReceiveRequest, ) -> Result { - let url = format!("https://{}/{BOLT11_RECEIVE_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .bolt11_receive(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Retrieve a new BOLT11 payable invoice for a given payment hash. - /// The inbound payment will NOT be automatically claimed upon arrival. - /// For API contract/usage, refer to docs for [`Bolt11ReceiveForHashRequest`] and [`Bolt11ReceiveForHashResponse`]. pub async fn bolt11_receive_for_hash( &self, request: Bolt11ReceiveForHashRequest, ) -> Result { - let url = format!("https://{}/{BOLT11_RECEIVE_FOR_HASH_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .bolt11_receive_for_hash(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Manually claim a payment for a given payment hash with the corresponding preimage. - /// For API contract/usage, refer to docs for [`Bolt11ClaimForHashRequest`] and [`Bolt11ClaimForHashResponse`]. pub async fn bolt11_claim_for_hash( &self, request: Bolt11ClaimForHashRequest, ) -> Result { - let url = format!("https://{}/{BOLT11_CLAIM_FOR_HASH_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .bolt11_claim_for_hash(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Manually fail a payment for a given payment hash. - /// For API contract/usage, refer to docs for [`Bolt11FailForHashRequest`] and [`Bolt11FailForHashResponse`]. pub async fn bolt11_fail_for_hash( &self, request: Bolt11FailForHashRequest, ) -> Result { - let url = format!("https://{}/{BOLT11_FAIL_FOR_HASH_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .bolt11_fail_for_hash(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Retrieve a new fixed-amount BOLT11 invoice for receiving via an LSPS2 JIT channel. - /// For API contract/usage, refer to docs for [`Bolt11ReceiveViaJitChannelRequest`] and - /// [`Bolt11ReceiveViaJitChannelResponse`]. pub async fn bolt11_receive_via_jit_channel( &self, request: Bolt11ReceiveViaJitChannelRequest, ) -> Result { - let url = format!("https://{}/{BOLT11_RECEIVE_VIA_JIT_CHANNEL_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .bolt11_receive_via_jit_channel(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Retrieve a new variable-amount BOLT11 invoice for receiving via an LSPS2 JIT channel. - /// For API contract/usage, refer to docs for - /// [`Bolt11ReceiveVariableAmountViaJitChannelRequest`] and - /// [`Bolt11ReceiveVariableAmountViaJitChannelResponse`]. pub async fn bolt11_receive_variable_amount_via_jit_channel( &self, request: Bolt11ReceiveVariableAmountViaJitChannelRequest, ) -> Result { - let url = format!( - "https://{}/{BOLT11_RECEIVE_VARIABLE_AMOUNT_VIA_JIT_CHANNEL_PATH}", - self.base_url, - ); - self.post_request(&request, &url).await + self.inner + .clone() + .bolt11_receive_variable_amount_via_jit_channel(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Send a payment for a BOLT11 invoice. @@ -207,17 +203,20 @@ impl LdkServerClient { pub async fn bolt11_send( &self, request: Bolt11SendRequest, ) -> Result { - let url = format!("https://{}/{BOLT11_SEND_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().bolt11_send(request).await.map(|r| r.into_inner()).map_err(from_status) } - /// Retrieve a new BOLT11 payable offer. + /// Retrieve a new BOLT12 offer. /// For API contract/usage, refer to docs for [`Bolt12ReceiveRequest`] and [`Bolt12ReceiveResponse`]. pub async fn bolt12_receive( &self, request: Bolt12ReceiveRequest, ) -> Result { - let url = format!("https://{}/{BOLT12_RECEIVE_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .bolt12_receive(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Send a payment for a BOLT12 offer. @@ -225,8 +224,7 @@ impl LdkServerClient { pub async fn bolt12_send( &self, request: Bolt12SendRequest, ) -> Result { - let url = format!("https://{}/{BOLT12_SEND_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().bolt12_send(request).await.map(|r| r.into_inner()).map_err(from_status) } /// Creates a new outbound channel. @@ -234,245 +232,247 @@ impl LdkServerClient { pub async fn open_channel( &self, request: OpenChannelRequest, ) -> Result { - let url = format!("https://{}/{OPEN_CHANNEL_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().open_channel(request).await.map(|r| r.into_inner()).map_err(from_status) } /// 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!("https://{}/{SPLICE_IN_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().splice_in(request).await.map(|r| r.into_inner()).map_err(from_status) } /// 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!("https://{}/{SPLICE_OUT_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().splice_out(request).await.map(|r| r.into_inner()).map_err(from_status) } /// 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!("https://{}/{CLOSE_CHANNEL_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().close_channel(request).await.map(|r| r.into_inner()).map_err(from_status) } /// 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!("https://{}/{FORCE_CLOSE_CHANNEL_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .force_close_channel(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// 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!("https://{}/{LIST_CHANNELS_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().list_channels(request).await.map(|r| r.into_inner()).map_err(from_status) } /// 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!("https://{}/{LIST_PAYMENTS_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().list_payments(request).await.map(|r| r.into_inner()).map_err(from_status) } /// 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!("https://{}/{UPDATE_CHANNEL_CONFIG_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .update_channel_config(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// 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 + self.inner + .clone() + .get_payment_details(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// 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 + self.inner + .clone() + .list_forwarded_payments(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// 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 + self.inner.clone().connect_peer(request).await.map(|r| r.into_inner()).map_err(from_status) } /// Disconnect from a peer and remove it from the peer store. - /// For API contract/usage, refer to docs for [`DisconnectPeerRequest`] and [`DisconnectPeerResponse`]. pub async fn disconnect_peer( &self, request: DisconnectPeerRequest, ) -> Result { - let url = format!("https://{}/{DISCONNECT_PEER_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .disconnect_peer(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Retrieves list of peers. - /// For API contract/usage, refer to docs for [`ListPeersRequest`] and [`ListPeersResponse`]. pub async fn list_peers( &self, request: ListPeersRequest, ) -> Result { - let url = format!("https://{}/{LIST_PEERS_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().list_peers(request).await.map(|r| r.into_inner()).map_err(from_status) } /// Send a spontaneous payment (keysend) to a node. - /// For API contract/usage, refer to docs for [`SpontaneousSendRequest`] and [`SpontaneousSendResponse`]. pub async fn spontaneous_send( &self, request: SpontaneousSendRequest, ) -> Result { - let url = format!("https://{}/{SPONTANEOUS_SEND_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .spontaneous_send(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Send a payment given a BIP 21 URI or BIP 353 Human-Readable Name. - /// For API contract/usage, refer to docs for [`UnifiedSendRequest`] and [`UnifiedSendResponse`]. pub async fn unified_send( &self, request: UnifiedSendRequest, ) -> Result { - let url = format!("https://{}/{UNIFIED_SEND_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().unified_send(request).await.map(|r| r.into_inner()).map_err(from_status) } /// Sign a message with the node's secret key. - /// For API contract/usage, refer to docs for [`SignMessageRequest`] and [`SignMessageResponse`]. pub async fn sign_message( &self, request: SignMessageRequest, ) -> Result { - let url = format!("https://{}/{SIGN_MESSAGE_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner.clone().sign_message(request).await.map(|r| r.into_inner()).map_err(from_status) } /// Verify a signature against a message and public key. - /// For API contract/usage, refer to docs for [`VerifySignatureRequest`] and [`VerifySignatureResponse`]. pub async fn verify_signature( &self, request: VerifySignatureRequest, ) -> Result { - let url = format!("https://{}/{VERIFY_SIGNATURE_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .verify_signature(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Export the pathfinding scores used by the router. - /// For API contract/usage, refer to docs for [`ExportPathfindingScoresRequest`] and [`ExportPathfindingScoresResponse`]. pub async fn export_pathfinding_scores( &self, request: ExportPathfindingScoresRequest, ) -> Result { - let url = format!("https://{}/{EXPORT_PATHFINDING_SCORES_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .export_pathfinding_scores(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Returns a list of all known short channel IDs in the network graph. - /// For API contract/usage, refer to docs for [`GraphListChannelsRequest`] and [`GraphListChannelsResponse`]. pub async fn graph_list_channels( &self, request: GraphListChannelsRequest, ) -> Result { - let url = format!("https://{}/{GRAPH_LIST_CHANNELS_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .graph_list_channels(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Returns information on a channel with the given short channel ID from the network graph. - /// For API contract/usage, refer to docs for [`GraphGetChannelRequest`] and [`GraphGetChannelResponse`]. pub async fn graph_get_channel( &self, request: GraphGetChannelRequest, ) -> Result { - let url = format!("https://{}/{GRAPH_GET_CHANNEL_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .graph_get_channel(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Returns a list of all known node IDs in the network graph. - /// For API contract/usage, refer to docs for [`GraphListNodesRequest`] and [`GraphListNodesResponse`]. pub async fn graph_list_nodes( &self, request: GraphListNodesRequest, ) -> Result { - let url = format!("https://{}/{GRAPH_LIST_NODES_PATH}", self.base_url); - self.post_request(&request, &url).await + self.inner + .clone() + .graph_list_nodes(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) } /// Returns information on a node with the given ID from the network graph. - /// For API contract/usage, refer to docs for [`GraphGetNodeRequest`] and [`GraphGetNodeResponse`]. pub async fn graph_get_node( &self, request: GraphGetNodeRequest, ) -> Result { - let url = format!("https://{}/{GRAPH_GET_NODE_PATH}", self.base_url); - self.post_request(&request, &url).await - } - - async fn post_request( - &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() + self.inner + .clone() + .graph_get_node(request) + .await + .map(|r| r.into_inner()) + .map_err(from_status) + } + + /// Subscribe to a stream of server events (payments, forwards, etc.). + pub async fn subscribe_events( + &self, + ) -> Result, LdkServerError> { + self.inner + .clone() + .subscribe_events(SubscribeEventsRequest {}) .await - .map_err(|e| { - LdkServerError::new(InternalError, format!("HTTP request failed: {}", e)) - })?; - - let status = response_raw.status(); - 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[..]).map_err(|e| { - LdkServerError::new( - InternalError, - format!("Failed to decode success response: {}", e), - ) - })?) - } else { - 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)) - } + .map(|r| r.into_inner()) + .map_err(from_status) } } + +fn from_status(status: Status) -> LdkServerError { + let error_code = match status.code() { + tonic::Code::InvalidArgument => InvalidRequestError, + tonic::Code::Unauthenticated | tonic::Code::PermissionDenied => AuthError, + tonic::Code::FailedPrecondition => LightningError, + tonic::Code::Internal => InternalServerError, + tonic::Code::Ok + | tonic::Code::Cancelled + | tonic::Code::Unknown + | tonic::Code::DeadlineExceeded + | tonic::Code::NotFound + | tonic::Code::AlreadyExists + | tonic::Code::ResourceExhausted + | tonic::Code::Aborted + | tonic::Code::OutOfRange + | tonic::Code::Unimplemented + | tonic::Code::Unavailable + | tonic::Code::DataLoss => InternalError, + }; + LdkServerError::new(error_code, status.message().to_string()) +} diff --git a/ldk-server-protos/Cargo.toml b/ldk-server-protos/Cargo.toml index c971d6f5..5caedda9 100644 --- a/ldk-server-protos/Cargo.toml +++ b/ldk-server-protos/Cargo.toml @@ -15,11 +15,15 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(genproto)'] } [features] default = [] serde = ["dep:serde", "dep:bytes"] +server = [] +client = [] [dependencies] -prost = { version = "0.11.6", default-features = false, features = ["std", "prost-derive"] } +prost = { version = "0.13", default-features = false, features = ["std", "prost-derive"] } +tonic = { version = "0.12" } 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.13", default-features = false } +tonic-build = { version = "0.12", default-features = false, features = ["prost"] } diff --git a/ldk-server-protos/build.rs b/ldk-server-protos/build.rs index 13e54d53..7596e37b 100644 --- a/ldk-server-protos/build.rs +++ b/ldk-server-protos/build.rs @@ -10,6 +10,9 @@ #[cfg(genproto)] extern crate prost_build; +#[cfg(genproto)] +extern crate tonic_build; + #[cfg(genproto)] use std::{env, fs, io::Write, path::Path}; @@ -34,7 +37,9 @@ fn main() { #[cfg(genproto)] fn generate_protos() { - prost_build::Config::new() + let mut prost_config = prost_build::Config::new(); + prost_config + .protoc_arg("--experimental_allow_proto3_optional") .bytes(&["."]) .type_attribute( ".", @@ -72,8 +77,13 @@ fn generate_protos() { .field_attribute( "api.UnifiedSendResponse.payment_result", "#[cfg_attr(feature = \"serde\", serde(flatten))]", - ) - .compile_protos( + ); + + tonic_build::configure() + .server_mod_attribute("api", "#[cfg(feature = \"server\")]") + .client_mod_attribute("api", "#[cfg(feature = \"client\")]") + .compile_protos_with_config( + prost_config, &[ "src/proto/api.proto", "src/proto/types.proto", diff --git a/ldk-server-protos/src/api.rs b/ldk-server-protos/src/api.rs index f72357d3..9891c7d5 100644 --- a/ldk-server-protos/src/api.rs +++ b/ldk-server-protos/src/api.rs @@ -7,20 +7,19 @@ // You may not use this file except in accordance with one or both of these // licenses. +// This file is @generated by prost-build. /// Retrieve the latest node info like `node_id`, `current_best_block` etc. /// 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)] +#[derive(Clone, Copy, 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 { /// The hex-encoded `node-id` or public key for our own lightning node. @@ -85,14 +84,12 @@ pub struct GetNodeInfoResponse { /// 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)] +#[derive(Clone, Copy, 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 { /// A Bitcoin on-chain address. @@ -102,7 +99,6 @@ pub struct OnchainReceiveResponse { /// 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 { /// The address to send coins to. @@ -132,7 +128,6 @@ pub struct OnchainSendRequest { /// 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 { /// The transaction ID of the broadcasted transaction. @@ -147,7 +142,6 @@ pub struct OnchainSendResponse { /// - #[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 { /// The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount invoice is returned. @@ -165,7 +159,6 @@ pub struct Bolt11ReceiveRequest { /// 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 { /// An invoice for a payment within the Lightning Network. @@ -189,7 +182,6 @@ pub struct Bolt11ReceiveResponse { /// - #[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 Bolt11ReceiveForHashRequest { /// The amount in millisatoshi to receive. If unset, a "zero-amount" or variable-amount invoice is returned. @@ -210,7 +202,6 @@ pub struct Bolt11ReceiveForHashRequest { /// 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 Bolt11ReceiveForHashResponse { /// An invoice for a payment within the Lightning Network. @@ -224,7 +215,6 @@ pub struct Bolt11ReceiveForHashResponse { /// 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 Bolt11ClaimForHashRequest { /// The hex-encoded 32-byte payment hash. @@ -243,15 +233,13 @@ pub struct Bolt11ClaimForHashRequest { /// 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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct Bolt11ClaimForHashResponse {} /// Manually fail a payment for a given payment hash. /// This should be used to reject payments created via `Bolt11ReceiveForHash`. /// 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 Bolt11FailForHashRequest { /// The hex-encoded 32-byte payment hash. @@ -262,15 +250,13 @@ pub struct Bolt11FailForHashRequest { /// 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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct Bolt11FailForHashResponse {} /// Return a BOLT11 payable invoice that can be used to request and receive a payment via an /// LSPS2 just-in-time 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 Bolt11ReceiveViaJitChannelRequest { /// The amount in millisatoshi to request. @@ -291,7 +277,6 @@ pub struct Bolt11ReceiveViaJitChannelRequest { /// 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 Bolt11ReceiveViaJitChannelResponse { /// An invoice for a payment within the Lightning Network. @@ -303,7 +288,6 @@ pub struct Bolt11ReceiveViaJitChannelResponse { /// 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 Bolt11ReceiveVariableAmountViaJitChannelRequest { /// An optional description to attach along with the invoice. @@ -322,7 +306,6 @@ pub struct Bolt11ReceiveVariableAmountViaJitChannelRequest { /// 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 Bolt11ReceiveVariableAmountViaJitChannelResponse { /// An invoice for a payment within the Lightning Network. @@ -333,7 +316,6 @@ pub struct Bolt11ReceiveVariableAmountViaJitChannelResponse { /// 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 { /// An invoice for a payment within the Lightning Network. @@ -352,7 +334,6 @@ pub struct Bolt11SendRequest { /// 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 { /// An identifier used to uniquely identify a payment in hex-encoded form. @@ -366,7 +347,6 @@ pub struct Bolt11SendResponse { /// - #[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 { /// An optional description to attach along with the offer. @@ -387,7 +367,6 @@ pub struct Bolt12ReceiveRequest { /// 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 { /// An offer for a payment within the Lightning Network. @@ -405,7 +384,6 @@ pub struct Bolt12ReceiveResponse { /// - #[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 { /// An offer for a payment within the Lightning Network. @@ -430,7 +408,6 @@ pub struct Bolt12SendRequest { /// 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 { /// An identifier used to uniquely identify a payment in hex-encoded form. @@ -441,7 +418,6 @@ pub struct Bolt12SendResponse { /// 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 SpontaneousSendRequest { /// The amount in millisatoshis to send. @@ -458,7 +434,6 @@ pub struct SpontaneousSendRequest { /// 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 SpontaneousSendResponse { /// An identifier used to uniquely identify a payment in hex-encoded form. @@ -469,7 +444,6 @@ pub struct SpontaneousSendResponse { /// 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 { /// The hex-encoded public key of the node to open a channel with. @@ -496,7 +470,6 @@ pub struct OpenChannelRequest { /// 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 { /// The local channel id of the created channel that user can use to refer to channel. @@ -507,7 +480,6 @@ pub struct OpenChannelResponse { /// 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 { /// The local `user_channel_id` of the channel. @@ -524,14 +496,12 @@ pub struct SpliceInRequest { /// 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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct SpliceInResponse {} /// Decreases the channel balance by the given 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 SpliceOutRequest { /// The local `user_channel_id` of this channel. @@ -553,7 +523,6 @@ pub struct SpliceOutRequest { /// 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 { /// The Bitcoin on-chain address where the funds will be sent. @@ -564,7 +533,6 @@ pub struct SpliceOutResponse { /// 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 { /// The local `user_channel_id` of this channel. @@ -581,14 +549,12 @@ pub struct UpdateChannelConfigRequest { /// 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)] +#[derive(Clone, Copy, 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 { /// The local `user_channel_id` of this channel. @@ -602,14 +568,12 @@ pub struct CloseChannelRequest { /// 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)] +#[derive(Clone, Copy, 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 { /// The local `user_channel_id` of this channel. @@ -626,21 +590,18 @@ pub struct ForceCloseChannelRequest { /// 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)] +#[derive(Clone, Copy, 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)] +#[derive(Clone, Copy, 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 { /// List of channels. @@ -651,7 +612,6 @@ pub struct ListChannelsResponse { /// 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 { /// An identifier used to uniquely identify a payment in hex-encoded form. @@ -662,7 +622,6 @@ pub struct GetPaymentDetailsRequest { /// 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 { /// Represents a payment. @@ -674,7 +633,6 @@ pub struct GetPaymentDetailsResponse { /// 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 { /// `page_token` is a pagination token. @@ -690,7 +648,6 @@ pub struct ListPaymentsRequest { /// 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 { /// List of payments. @@ -716,7 +673,6 @@ pub struct ListPaymentsResponse { /// 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 { /// `page_token` is a pagination token. @@ -732,7 +688,6 @@ pub struct ListForwardedPaymentsRequest { /// 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 { /// List of forwarded payments. @@ -758,7 +713,6 @@ pub struct ListForwardedPaymentsResponse { /// 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 SignMessageRequest { /// The message to sign, as raw bytes. @@ -769,7 +723,6 @@ pub struct SignMessageRequest { /// 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 SignMessageResponse { /// The signature of the message, as a zbase32-encoded string. @@ -780,7 +733,6 @@ pub struct SignMessageResponse { /// 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 VerifySignatureRequest { /// The message that was signed, as raw bytes. @@ -797,8 +749,7 @@ pub struct VerifySignatureRequest { /// 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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct VerifySignatureResponse { /// Whether the signature is valid. #[prost(bool, tag = "1")] @@ -808,14 +759,12 @@ pub struct VerifySignatureResponse { /// 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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct ExportPathfindingScoresRequest {} /// The response `content` for the `ExportPathfindingScores` 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 ExportPathfindingScoresResponse { /// The serialized pathfinding scores data. @@ -826,14 +775,12 @@ pub struct ExportPathfindingScoresResponse { /// 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)] +#[derive(Clone, Copy, 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 { /// The total balance of our on-chain wallet. @@ -879,7 +826,6 @@ pub struct GetBalancesResponse { /// 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. @@ -898,14 +844,12 @@ pub struct ConnectPeerRequest { /// 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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct ConnectPeerResponse {} /// Disconnect from a peer and remove it from the peer store. /// 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 DisconnectPeerRequest { /// The hex-encoded public key of the node to disconnect from. @@ -916,21 +860,18 @@ pub struct DisconnectPeerRequest { /// 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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct DisconnectPeerResponse {} /// Returns a list of peers. /// 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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct ListPeersRequest {} /// The response `content` for the `ListPeers` 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 ListPeersResponse { /// List of peers. @@ -941,14 +882,12 @@ pub struct ListPeersResponse { /// 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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct GraphListChannelsRequest {} /// The response `content` for the `GraphListChannels` 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 GraphListChannelsResponse { /// List of short channel IDs known to the network graph. @@ -959,8 +898,7 @@ pub struct GraphListChannelsResponse { /// 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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct GraphGetChannelRequest { /// The short channel ID to look up. #[prost(uint64, tag = "1")] @@ -970,7 +908,6 @@ pub struct GraphGetChannelRequest { /// 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 GraphGetChannelResponse { /// The channel information. @@ -981,14 +918,12 @@ pub struct GraphGetChannelResponse { /// 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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct GraphListNodesRequest {} /// The response `content` for the `GraphListNodes` 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 GraphListNodesResponse { /// List of hex-encoded node IDs known to the network graph. @@ -1003,7 +938,6 @@ pub struct GraphListNodesResponse { /// 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 UnifiedSendRequest { /// A BIP 21 URI or BIP 353 Human-Readable Name to pay. @@ -1020,7 +954,6 @@ pub struct UnifiedSendRequest { /// 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 UnifiedSendResponse { #[prost(oneof = "unified_send_response::PaymentResult", tags = "1, 2, 3")] @@ -1031,7 +964,6 @@ pub struct UnifiedSendResponse { pub mod unified_send_response { #[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 PaymentResult { /// An on-chain payment was made. Contains the transaction ID. @@ -1049,7 +981,6 @@ pub mod unified_send_response { /// 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 GraphGetNodeRequest { /// The hex-encoded node ID to look up. @@ -1060,10 +991,2333 @@ pub struct GraphGetNodeRequest { /// 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 GraphGetNodeResponse { /// The node information. #[prost(message, optional, tag = "1")] pub node: ::core::option::Option, } +/// Subscribe to a stream of server events (payment received, payment successful, etc.). +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct SubscribeEventsRequest {} +/// Generated client implementations. +#[cfg(feature = "client")] +pub mod lightning_node_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value + )] + use tonic::codegen::http::Uri; + use tonic::codegen::*; + /// The LightningNode service provides a gRPC interface for managing a Lightning Network node. + #[derive(Debug, Clone)] + pub struct LightningNodeClient { + inner: tonic::client::Grpc, + } + impl LightningNodeClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, interceptor: F, + ) -> LightningNodeClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + >>::Error: + Into + std::marker::Send + std::marker::Sync, + { + LightningNodeClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Retrieve the latest node info. + pub async fn get_node_info( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/GetNodeInfo"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "GetNodeInfo")); + self.inner.unary(req, path, codec).await + } + /// Retrieve an overview of all known balances. + pub async fn get_balances( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/GetBalances"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "GetBalances")); + self.inner.unary(req, path, codec).await + } + /// Retrieve a new on-chain funding address. + pub async fn onchain_receive( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/OnchainReceive"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "OnchainReceive")); + self.inner.unary(req, path, codec).await + } + /// Send an on-chain payment to the given address. + pub async fn onchain_send( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/OnchainSend"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "OnchainSend")); + self.inner.unary(req, path, codec).await + } + /// Return a BOLT11 payable invoice. + pub async fn bolt11_receive( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/Bolt11Receive"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "Bolt11Receive")); + self.inner.unary(req, path, codec).await + } + /// Return a BOLT11 payable invoice for a given payment hash. + pub async fn bolt11_receive_for_hash( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/api.LightningNode/Bolt11ReceiveForHash"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("api.LightningNode", "Bolt11ReceiveForHash")); + self.inner.unary(req, path, codec).await + } + /// Manually claim a payment for a given payment hash. + pub async fn bolt11_claim_for_hash( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/api.LightningNode/Bolt11ClaimForHash"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "Bolt11ClaimForHash")); + self.inner.unary(req, path, codec).await + } + /// Manually fail a payment for a given payment hash. + pub async fn bolt11_fail_for_hash( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/Bolt11FailForHash"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "Bolt11FailForHash")); + self.inner.unary(req, path, codec).await + } + /// Return a BOLT11 invoice for receiving via a JIT channel. + pub async fn bolt11_receive_via_jit_channel( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/api.LightningNode/Bolt11ReceiveViaJitChannel", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("api.LightningNode", "Bolt11ReceiveViaJitChannel")); + self.inner.unary(req, path, codec).await + } + /// Return a variable-amount BOLT11 invoice for receiving via a JIT channel. + pub async fn bolt11_receive_variable_amount_via_jit_channel( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/api.LightningNode/Bolt11ReceiveVariableAmountViaJitChannel", + ); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new( + "api.LightningNode", + "Bolt11ReceiveVariableAmountViaJitChannel", + )); + self.inner.unary(req, path, codec).await + } + /// Send a payment for a BOLT11 invoice. + pub async fn bolt11_send( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/Bolt11Send"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "Bolt11Send")); + self.inner.unary(req, path, codec).await + } + /// Return a BOLT12 offer. + pub async fn bolt12_receive( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/Bolt12Receive"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "Bolt12Receive")); + self.inner.unary(req, path, codec).await + } + /// Send a payment for a BOLT12 offer. + pub async fn bolt12_send( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/Bolt12Send"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "Bolt12Send")); + self.inner.unary(req, path, codec).await + } + /// Send a spontaneous payment (keysend). + pub async fn spontaneous_send( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/SpontaneousSend"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "SpontaneousSend")); + self.inner.unary(req, path, codec).await + } + /// Create a new outbound channel. + pub async fn open_channel( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/OpenChannel"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "OpenChannel")); + self.inner.unary(req, path, codec).await + } + /// Splice funds into a channel. + pub async fn splice_in( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/SpliceIn"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "SpliceIn")); + self.inner.unary(req, path, codec).await + } + /// Splice funds out of a channel. + pub async fn splice_out( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/SpliceOut"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "SpliceOut")); + self.inner.unary(req, path, codec).await + } + /// Update the config for a channel. + pub async fn update_channel_config( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/api.LightningNode/UpdateChannelConfig"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("api.LightningNode", "UpdateChannelConfig")); + self.inner.unary(req, path, codec).await + } + /// Close a channel cooperatively. + pub async fn close_channel( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/CloseChannel"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "CloseChannel")); + self.inner.unary(req, path, codec).await + } + /// Force close a channel. + pub async fn force_close_channel( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/ForceCloseChannel"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "ForceCloseChannel")); + self.inner.unary(req, path, codec).await + } + /// List known channels. + pub async fn list_channels( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/ListChannels"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "ListChannels")); + self.inner.unary(req, path, codec).await + } + /// Get payment details by payment ID. + pub async fn get_payment_details( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/GetPaymentDetails"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "GetPaymentDetails")); + self.inner.unary(req, path, codec).await + } + /// List all payments. + pub async fn list_payments( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/ListPayments"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "ListPayments")); + self.inner.unary(req, path, codec).await + } + /// List all forwarded payments. + pub async fn list_forwarded_payments( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/api.LightningNode/ListForwardedPayments"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("api.LightningNode", "ListForwardedPayments")); + self.inner.unary(req, path, codec).await + } + /// Connect to a peer. + pub async fn connect_peer( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/ConnectPeer"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "ConnectPeer")); + self.inner.unary(req, path, codec).await + } + /// Disconnect from a peer. + pub async fn disconnect_peer( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/DisconnectPeer"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "DisconnectPeer")); + self.inner.unary(req, path, codec).await + } + /// List peers. + pub async fn list_peers( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/ListPeers"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "ListPeers")); + self.inner.unary(req, path, codec).await + } + /// Sign a message with the node's secret key. + pub async fn sign_message( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/SignMessage"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "SignMessage")); + self.inner.unary(req, path, codec).await + } + /// Verify a signature against a message and public key. + pub async fn verify_signature( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/VerifySignature"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "VerifySignature")); + self.inner.unary(req, path, codec).await + } + /// Export the pathfinding scores used by the router. + pub async fn export_pathfinding_scores( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/api.LightningNode/ExportPathfindingScores"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("api.LightningNode", "ExportPathfindingScores")); + self.inner.unary(req, path, codec).await + } + /// Send a payment given a BIP 21 URI or BIP 353 Human-Readable Name. + pub async fn unified_send( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/UnifiedSend"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "UnifiedSend")); + self.inner.unary(req, path, codec).await + } + /// List all known short channel IDs in the network graph. + pub async fn graph_list_channels( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/GraphListChannels"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "GraphListChannels")); + self.inner.unary(req, path, codec).await + } + /// Get channel info from the network graph by short channel ID. + pub async fn graph_get_channel( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/GraphGetChannel"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "GraphGetChannel")); + self.inner.unary(req, path, codec).await + } + /// List all known node IDs in the network graph. + pub async fn graph_list_nodes( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/GraphListNodes"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "GraphListNodes")); + self.inner.unary(req, path, codec).await + } + /// Get node info from the network graph by node ID. + pub async fn graph_get_node( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/GraphGetNode"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "GraphGetNode")); + self.inner.unary(req, path, codec).await + } + /// Subscribe to a stream of server events. + pub async fn subscribe_events( + &mut self, request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + self.inner.ready().await.map_err(|e| { + tonic::Status::unknown(format!("Service was not ready: {}", e.into())) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/api.LightningNode/SubscribeEvents"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("api.LightningNode", "SubscribeEvents")); + self.inner.server_streaming(req, path, codec).await + } + } +} +/// Generated server implementations. +#[cfg(feature = "server")] +pub mod lightning_node_server { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value + )] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with LightningNodeServer. + #[async_trait] + pub trait LightningNode: std::marker::Send + std::marker::Sync + 'static { + /// Retrieve the latest node info. + async fn get_node_info( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Retrieve an overview of all known balances. + async fn get_balances( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Retrieve a new on-chain funding address. + async fn onchain_receive( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Send an on-chain payment to the given address. + async fn onchain_send( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Return a BOLT11 payable invoice. + async fn bolt11_receive( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Return a BOLT11 payable invoice for a given payment hash. + async fn bolt11_receive_for_hash( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Manually claim a payment for a given payment hash. + async fn bolt11_claim_for_hash( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Manually fail a payment for a given payment hash. + async fn bolt11_fail_for_hash( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Return a BOLT11 invoice for receiving via a JIT channel. + async fn bolt11_receive_via_jit_channel( + &self, request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Return a variable-amount BOLT11 invoice for receiving via a JIT channel. + async fn bolt11_receive_variable_amount_via_jit_channel( + &self, request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Send a payment for a BOLT11 invoice. + async fn bolt11_send( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Return a BOLT12 offer. + async fn bolt12_receive( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Send a payment for a BOLT12 offer. + async fn bolt12_send( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Send a spontaneous payment (keysend). + async fn spontaneous_send( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Create a new outbound channel. + async fn open_channel( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Splice funds into a channel. + async fn splice_in( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Splice funds out of a channel. + async fn splice_out( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Update the config for a channel. + async fn update_channel_config( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Close a channel cooperatively. + async fn close_channel( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Force close a channel. + async fn force_close_channel( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// List known channels. + async fn list_channels( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get payment details by payment ID. + async fn get_payment_details( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// List all payments. + async fn list_payments( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// List all forwarded payments. + async fn list_forwarded_payments( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Connect to a peer. + async fn connect_peer( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Disconnect from a peer. + async fn disconnect_peer( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// List peers. + async fn list_peers( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Sign a message with the node's secret key. + async fn sign_message( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Verify a signature against a message and public key. + async fn verify_signature( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Export the pathfinding scores used by the router. + async fn export_pathfinding_scores( + &self, request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Send a payment given a BIP 21 URI or BIP 353 Human-Readable Name. + async fn unified_send( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// List all known short channel IDs in the network graph. + async fn graph_list_channels( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get channel info from the network graph by short channel ID. + async fn graph_get_channel( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// List all known node IDs in the network graph. + async fn graph_list_nodes( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get node info from the network graph by node ID. + async fn graph_get_node( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Server streaming response type for the SubscribeEvents method. + type SubscribeEventsStream: tonic::codegen::tokio_stream::Stream< + Item = std::result::Result, + > + std::marker::Send + + 'static; + /// Subscribe to a stream of server events. + async fn subscribe_events( + &self, request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + } + /// The LightningNode service provides a gRPC interface for managing a Lightning Network node. + #[derive(Debug)] + pub struct LightningNodeServer { + inner: Arc, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + impl LightningNodeServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor(inner: T, interceptor: F) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for LightningNodeServer + where + T: LightningNode, + B: Body + std::marker::Send + 'static, + B::Error: Into + std::marker::Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + match req.uri().path() { + "/api.LightningNode/GetNodeInfo" => { + #[allow(non_camel_case_types)] + struct GetNodeInfoSvc(pub Arc); + impl tonic::server::UnaryService + for GetNodeInfoSvc + { + type Response = super::GetNodeInfoResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_node_info(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetNodeInfoSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/GetBalances" => { + #[allow(non_camel_case_types)] + struct GetBalancesSvc(pub Arc); + impl tonic::server::UnaryService + for GetBalancesSvc + { + type Response = super::GetBalancesResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_balances(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetBalancesSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/OnchainReceive" => { + #[allow(non_camel_case_types)] + struct OnchainReceiveSvc(pub Arc); + impl tonic::server::UnaryService + for OnchainReceiveSvc + { + type Response = super::OnchainReceiveResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::onchain_receive(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = OnchainReceiveSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/OnchainSend" => { + #[allow(non_camel_case_types)] + struct OnchainSendSvc(pub Arc); + impl tonic::server::UnaryService + for OnchainSendSvc + { + type Response = super::OnchainSendResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::onchain_send(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = OnchainSendSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/Bolt11Receive" => { + #[allow(non_camel_case_types)] + struct Bolt11ReceiveSvc(pub Arc); + impl tonic::server::UnaryService + for Bolt11ReceiveSvc + { + type Response = super::Bolt11ReceiveResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::bolt11_receive(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = Bolt11ReceiveSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/Bolt11ReceiveForHash" => { + #[allow(non_camel_case_types)] + struct Bolt11ReceiveForHashSvc(pub Arc); + impl + tonic::server::UnaryService + for Bolt11ReceiveForHashSvc + { + type Response = super::Bolt11ReceiveForHashResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::bolt11_receive_for_hash(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = Bolt11ReceiveForHashSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/Bolt11ClaimForHash" => { + #[allow(non_camel_case_types)] + struct Bolt11ClaimForHashSvc(pub Arc); + impl + tonic::server::UnaryService for Bolt11ClaimForHashSvc + { + type Response = super::Bolt11ClaimForHashResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::bolt11_claim_for_hash(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = Bolt11ClaimForHashSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/Bolt11FailForHash" => { + #[allow(non_camel_case_types)] + struct Bolt11FailForHashSvc(pub Arc); + impl + tonic::server::UnaryService for Bolt11FailForHashSvc + { + type Response = super::Bolt11FailForHashResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::bolt11_fail_for_hash(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = Bolt11FailForHashSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/Bolt11ReceiveViaJitChannel" => { + #[allow(non_camel_case_types)] + struct Bolt11ReceiveViaJitChannelSvc(pub Arc); + impl + tonic::server::UnaryService + for Bolt11ReceiveViaJitChannelSvc + { + type Response = super::Bolt11ReceiveViaJitChannelResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::bolt11_receive_via_jit_channel( + &inner, request, + ) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = Bolt11ReceiveViaJitChannelSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/Bolt11ReceiveVariableAmountViaJitChannel" => { + #[allow(non_camel_case_types)] + struct Bolt11ReceiveVariableAmountViaJitChannelSvc( + pub Arc, + ); + impl + tonic::server::UnaryService< + super::Bolt11ReceiveVariableAmountViaJitChannelRequest, + > for Bolt11ReceiveVariableAmountViaJitChannelSvc + { + type Response = super::Bolt11ReceiveVariableAmountViaJitChannelResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request< + super::Bolt11ReceiveVariableAmountViaJitChannelRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::bolt11_receive_variable_amount_via_jit_channel( + &inner, + request, + ) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = Bolt11ReceiveVariableAmountViaJitChannelSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/Bolt11Send" => { + #[allow(non_camel_case_types)] + struct Bolt11SendSvc(pub Arc); + impl tonic::server::UnaryService for Bolt11SendSvc { + type Response = super::Bolt11SendResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::bolt11_send(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = Bolt11SendSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/Bolt12Receive" => { + #[allow(non_camel_case_types)] + struct Bolt12ReceiveSvc(pub Arc); + impl tonic::server::UnaryService + for Bolt12ReceiveSvc + { + type Response = super::Bolt12ReceiveResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::bolt12_receive(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = Bolt12ReceiveSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/Bolt12Send" => { + #[allow(non_camel_case_types)] + struct Bolt12SendSvc(pub Arc); + impl tonic::server::UnaryService for Bolt12SendSvc { + type Response = super::Bolt12SendResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::bolt12_send(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = Bolt12SendSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/SpontaneousSend" => { + #[allow(non_camel_case_types)] + struct SpontaneousSendSvc(pub Arc); + impl + tonic::server::UnaryService for SpontaneousSendSvc + { + type Response = super::SpontaneousSendResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::spontaneous_send(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SpontaneousSendSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/OpenChannel" => { + #[allow(non_camel_case_types)] + struct OpenChannelSvc(pub Arc); + impl tonic::server::UnaryService + for OpenChannelSvc + { + type Response = super::OpenChannelResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::open_channel(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = OpenChannelSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/SpliceIn" => { + #[allow(non_camel_case_types)] + struct SpliceInSvc(pub Arc); + impl tonic::server::UnaryService for SpliceInSvc { + type Response = super::SpliceInResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::splice_in(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SpliceInSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/SpliceOut" => { + #[allow(non_camel_case_types)] + struct SpliceOutSvc(pub Arc); + impl tonic::server::UnaryService for SpliceOutSvc { + type Response = super::SpliceOutResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::splice_out(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SpliceOutSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/UpdateChannelConfig" => { + #[allow(non_camel_case_types)] + struct UpdateChannelConfigSvc(pub Arc); + impl + tonic::server::UnaryService for UpdateChannelConfigSvc + { + type Response = super::UpdateChannelConfigResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::update_channel_config(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = UpdateChannelConfigSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/CloseChannel" => { + #[allow(non_camel_case_types)] + struct CloseChannelSvc(pub Arc); + impl tonic::server::UnaryService + for CloseChannelSvc + { + type Response = super::CloseChannelResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::close_channel(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = CloseChannelSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/ForceCloseChannel" => { + #[allow(non_camel_case_types)] + struct ForceCloseChannelSvc(pub Arc); + impl + tonic::server::UnaryService for ForceCloseChannelSvc + { + type Response = super::ForceCloseChannelResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::force_close_channel(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ForceCloseChannelSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/ListChannels" => { + #[allow(non_camel_case_types)] + struct ListChannelsSvc(pub Arc); + impl tonic::server::UnaryService + for ListChannelsSvc + { + type Response = super::ListChannelsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::list_channels(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ListChannelsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/GetPaymentDetails" => { + #[allow(non_camel_case_types)] + struct GetPaymentDetailsSvc(pub Arc); + impl + tonic::server::UnaryService for GetPaymentDetailsSvc + { + type Response = super::GetPaymentDetailsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_payment_details(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetPaymentDetailsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/ListPayments" => { + #[allow(non_camel_case_types)] + struct ListPaymentsSvc(pub Arc); + impl tonic::server::UnaryService + for ListPaymentsSvc + { + type Response = super::ListPaymentsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::list_payments(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ListPaymentsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/ListForwardedPayments" => { + #[allow(non_camel_case_types)] + struct ListForwardedPaymentsSvc(pub Arc); + impl + tonic::server::UnaryService + for ListForwardedPaymentsSvc + { + type Response = super::ListForwardedPaymentsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::list_forwarded_payments(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ListForwardedPaymentsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/ConnectPeer" => { + #[allow(non_camel_case_types)] + struct ConnectPeerSvc(pub Arc); + impl tonic::server::UnaryService + for ConnectPeerSvc + { + type Response = super::ConnectPeerResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::connect_peer(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ConnectPeerSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/DisconnectPeer" => { + #[allow(non_camel_case_types)] + struct DisconnectPeerSvc(pub Arc); + impl tonic::server::UnaryService + for DisconnectPeerSvc + { + type Response = super::DisconnectPeerResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::disconnect_peer(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = DisconnectPeerSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/ListPeers" => { + #[allow(non_camel_case_types)] + struct ListPeersSvc(pub Arc); + impl tonic::server::UnaryService for ListPeersSvc { + type Response = super::ListPeersResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::list_peers(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ListPeersSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/SignMessage" => { + #[allow(non_camel_case_types)] + struct SignMessageSvc(pub Arc); + impl tonic::server::UnaryService + for SignMessageSvc + { + type Response = super::SignMessageResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::sign_message(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SignMessageSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/VerifySignature" => { + #[allow(non_camel_case_types)] + struct VerifySignatureSvc(pub Arc); + impl + tonic::server::UnaryService for VerifySignatureSvc + { + type Response = super::VerifySignatureResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::verify_signature(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = VerifySignatureSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/ExportPathfindingScores" => { + #[allow(non_camel_case_types)] + struct ExportPathfindingScoresSvc(pub Arc); + impl + tonic::server::UnaryService + for ExportPathfindingScoresSvc + { + type Response = super::ExportPathfindingScoresResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::export_pathfinding_scores(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ExportPathfindingScoresSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/UnifiedSend" => { + #[allow(non_camel_case_types)] + struct UnifiedSendSvc(pub Arc); + impl tonic::server::UnaryService + for UnifiedSendSvc + { + type Response = super::UnifiedSendResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::unified_send(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = UnifiedSendSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/GraphListChannels" => { + #[allow(non_camel_case_types)] + struct GraphListChannelsSvc(pub Arc); + impl + tonic::server::UnaryService for GraphListChannelsSvc + { + type Response = super::GraphListChannelsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::graph_list_channels(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GraphListChannelsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/GraphGetChannel" => { + #[allow(non_camel_case_types)] + struct GraphGetChannelSvc(pub Arc); + impl + tonic::server::UnaryService for GraphGetChannelSvc + { + type Response = super::GraphGetChannelResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::graph_get_channel(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GraphGetChannelSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/GraphListNodes" => { + #[allow(non_camel_case_types)] + struct GraphListNodesSvc(pub Arc); + impl tonic::server::UnaryService + for GraphListNodesSvc + { + type Response = super::GraphListNodesResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::graph_list_nodes(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GraphListNodesSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/GraphGetNode" => { + #[allow(non_camel_case_types)] + struct GraphGetNodeSvc(pub Arc); + impl tonic::server::UnaryService + for GraphGetNodeSvc + { + type Response = super::GraphGetNodeResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::graph_get_node(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GraphGetNodeSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + "/api.LightningNode/SubscribeEvents" => { + #[allow(non_camel_case_types)] + struct SubscribeEventsSvc(pub Arc); + impl + tonic::server::ServerStreamingService + for SubscribeEventsSvc + { + type Response = super::super::events::EventEnvelope; + type ResponseStream = T::SubscribeEventsStream; + type Future = + BoxFuture, tonic::Status>; + fn call( + &mut self, request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::subscribe_events(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SubscribeEventsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.server_streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + }, + _ => Box::pin(async move { + let mut response = http::Response::new(empty_body()); + let headers = response.headers_mut(); + headers.insert( + tonic::Status::GRPC_STATUS, + (tonic::Code::Unimplemented as i32).into(), + ); + headers.insert(http::header::CONTENT_TYPE, tonic::metadata::GRPC_CONTENT_TYPE); + Ok(response) + }), + } + } + } + impl Clone for LightningNodeServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + /// Generated gRPC service name + pub const SERVICE_NAME: &str = "api.LightningNode"; + impl tonic::server::NamedService for LightningNodeServer { + const NAME: &'static str = SERVICE_NAME; + } +} diff --git a/ldk-server-protos/src/endpoints.rs b/ldk-server-protos/src/endpoints.rs deleted file mode 100644 index c6818dee..00000000 --- a/ldk-server-protos/src/endpoints.rs +++ /dev/null @@ -1,45 +0,0 @@ -// 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"; -pub const ONCHAIN_SEND_PATH: &str = "OnchainSend"; -pub const BOLT11_RECEIVE_PATH: &str = "Bolt11Receive"; -pub const BOLT11_RECEIVE_FOR_HASH_PATH: &str = "Bolt11ReceiveForHash"; -pub const BOLT11_CLAIM_FOR_HASH_PATH: &str = "Bolt11ClaimForHash"; -pub const BOLT11_FAIL_FOR_HASH_PATH: &str = "Bolt11FailForHash"; -pub const BOLT11_RECEIVE_VIA_JIT_CHANNEL_PATH: &str = "Bolt11ReceiveViaJitChannel"; -pub const BOLT11_RECEIVE_VARIABLE_AMOUNT_VIA_JIT_CHANNEL_PATH: &str = - "Bolt11ReceiveVariableAmountViaJitChannel"; -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"; -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 LIST_PEERS_PATH: &str = "ListPeers"; -pub const CONNECT_PEER_PATH: &str = "ConnectPeer"; -pub const DISCONNECT_PEER_PATH: &str = "DisconnectPeer"; -pub const SPONTANEOUS_SEND_PATH: &str = "SpontaneousSend"; -pub const SIGN_MESSAGE_PATH: &str = "SignMessage"; -pub const VERIFY_SIGNATURE_PATH: &str = "VerifySignature"; -pub const EXPORT_PATHFINDING_SCORES_PATH: &str = "ExportPathfindingScores"; -pub const UNIFIED_SEND_PATH: &str = "UnifiedSend"; -pub const GRAPH_LIST_CHANNELS_PATH: &str = "GraphListChannels"; -pub const GRAPH_GET_CHANNEL_PATH: &str = "GraphGetChannel"; -pub const GRAPH_LIST_NODES_PATH: &str = "GraphListNodes"; -pub const GRAPH_GET_NODE_PATH: &str = "GraphGetNode"; diff --git a/ldk-server-protos/src/error.rs b/ldk-server-protos/src/error.rs index 41e73ee4..0f778fd2 100644 --- a/ldk-server-protos/src/error.rs +++ b/ldk-server-protos/src/error.rs @@ -7,11 +7,11 @@ // You may not use this file except in accordance with one or both of these // licenses. +// This file is @generated by prost-build. /// 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 { /// The error message containing a generic description of the error condition in English. @@ -58,11 +58,11 @@ impl ErrorCode { /// (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", + Self::UnknownError => "UNKNOWN_ERROR", + Self::InvalidRequestError => "INVALID_REQUEST_ERROR", + Self::AuthError => "AUTH_ERROR", + Self::LightningError => "LIGHTNING_ERROR", + Self::InternalServerError => "INTERNAL_SERVER_ERROR", } } /// Creates an enum from field names used in the ProtoBuf definition. diff --git a/ldk-server-protos/src/events.rs b/ldk-server-protos/src/events.rs index a41446aa..911fe7c2 100644 --- a/ldk-server-protos/src/events.rs +++ b/ldk-server-protos/src/events.rs @@ -7,10 +7,10 @@ // You may not use this file except in accordance with one or both of these // licenses. +// This file is @generated by prost-build. /// 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 { #[prost(oneof = "event_envelope::Event", tags = "2, 3, 4, 6, 7")] @@ -20,7 +20,6 @@ pub struct 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 { #[prost(message, tag = "2")] @@ -38,7 +37,6 @@ 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 { /// The payment details for the payment in event. @@ -48,7 +46,6 @@ pub struct PaymentReceived { /// 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 { /// The payment details for the payment in event. @@ -58,7 +55,6 @@ pub struct PaymentSuccessful { /// 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 { /// The payment details for the payment in event. @@ -69,7 +65,6 @@ pub struct PaymentFailed { /// This event is only emitted for payments created via `Bolt11ReceiveForHash`. #[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 PaymentClaimable { /// The payment details for the claimable payment. @@ -79,7 +74,6 @@ pub struct PaymentClaimable { /// 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 { #[prost(message, optional, tag = "1")] diff --git a/ldk-server-protos/src/lib.rs b/ldk-server-protos/src/lib.rs index f76f2f73..b60a9b63 100644 --- a/ldk-server-protos/src/lib.rs +++ b/ldk-server-protos/src/lib.rs @@ -8,7 +8,6 @@ // licenses. pub mod api; -pub mod endpoints; pub mod error; pub mod events; #[cfg(feature = "serde")] diff --git a/ldk-server-protos/src/proto/api.proto b/ldk-server-protos/src/proto/api.proto index 3eb505d3..358db168 100644 --- a/ldk-server-protos/src/proto/api.proto +++ b/ldk-server-protos/src/proto/api.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package api; import 'types.proto'; +import 'events.proto'; // Retrieve the latest node info like `node_id`, `current_best_block` etc. // See more: @@ -822,3 +823,82 @@ message GraphGetNodeResponse { // The node information. types.GraphNode node = 1; } + +// Subscribe to a stream of server events (payment received, payment successful, etc.). +message SubscribeEventsRequest {} + +// The LightningNode service provides a gRPC interface for managing a Lightning Network node. +service LightningNode { + // Retrieve the latest node info. + rpc GetNodeInfo(GetNodeInfoRequest) returns (GetNodeInfoResponse); + // Retrieve an overview of all known balances. + rpc GetBalances(GetBalancesRequest) returns (GetBalancesResponse); + // Retrieve a new on-chain funding address. + rpc OnchainReceive(OnchainReceiveRequest) returns (OnchainReceiveResponse); + // Send an on-chain payment to the given address. + rpc OnchainSend(OnchainSendRequest) returns (OnchainSendResponse); + // Return a BOLT11 payable invoice. + rpc Bolt11Receive(Bolt11ReceiveRequest) returns (Bolt11ReceiveResponse); + // Return a BOLT11 payable invoice for a given payment hash. + rpc Bolt11ReceiveForHash(Bolt11ReceiveForHashRequest) returns (Bolt11ReceiveForHashResponse); + // Manually claim a payment for a given payment hash. + rpc Bolt11ClaimForHash(Bolt11ClaimForHashRequest) returns (Bolt11ClaimForHashResponse); + // Manually fail a payment for a given payment hash. + rpc Bolt11FailForHash(Bolt11FailForHashRequest) returns (Bolt11FailForHashResponse); + // Return a BOLT11 invoice for receiving via a JIT channel. + rpc Bolt11ReceiveViaJitChannel(Bolt11ReceiveViaJitChannelRequest) returns (Bolt11ReceiveViaJitChannelResponse); + // Return a variable-amount BOLT11 invoice for receiving via a JIT channel. + rpc Bolt11ReceiveVariableAmountViaJitChannel(Bolt11ReceiveVariableAmountViaJitChannelRequest) returns (Bolt11ReceiveVariableAmountViaJitChannelResponse); + // Send a payment for a BOLT11 invoice. + rpc Bolt11Send(Bolt11SendRequest) returns (Bolt11SendResponse); + // Return a BOLT12 offer. + rpc Bolt12Receive(Bolt12ReceiveRequest) returns (Bolt12ReceiveResponse); + // Send a payment for a BOLT12 offer. + rpc Bolt12Send(Bolt12SendRequest) returns (Bolt12SendResponse); + // Send a spontaneous payment (keysend). + rpc SpontaneousSend(SpontaneousSendRequest) returns (SpontaneousSendResponse); + // Create a new outbound channel. + rpc OpenChannel(OpenChannelRequest) returns (OpenChannelResponse); + // Splice funds into a channel. + rpc SpliceIn(SpliceInRequest) returns (SpliceInResponse); + // Splice funds out of a channel. + rpc SpliceOut(SpliceOutRequest) returns (SpliceOutResponse); + // Update the config for a channel. + rpc UpdateChannelConfig(UpdateChannelConfigRequest) returns (UpdateChannelConfigResponse); + // Close a channel cooperatively. + rpc CloseChannel(CloseChannelRequest) returns (CloseChannelResponse); + // Force close a channel. + rpc ForceCloseChannel(ForceCloseChannelRequest) returns (ForceCloseChannelResponse); + // List known channels. + rpc ListChannels(ListChannelsRequest) returns (ListChannelsResponse); + // Get payment details by payment ID. + rpc GetPaymentDetails(GetPaymentDetailsRequest) returns (GetPaymentDetailsResponse); + // List all payments. + rpc ListPayments(ListPaymentsRequest) returns (ListPaymentsResponse); + // List all forwarded payments. + rpc ListForwardedPayments(ListForwardedPaymentsRequest) returns (ListForwardedPaymentsResponse); + // Connect to a peer. + rpc ConnectPeer(ConnectPeerRequest) returns (ConnectPeerResponse); + // Disconnect from a peer. + rpc DisconnectPeer(DisconnectPeerRequest) returns (DisconnectPeerResponse); + // List peers. + rpc ListPeers(ListPeersRequest) returns (ListPeersResponse); + // Sign a message with the node's secret key. + rpc SignMessage(SignMessageRequest) returns (SignMessageResponse); + // Verify a signature against a message and public key. + rpc VerifySignature(VerifySignatureRequest) returns (VerifySignatureResponse); + // Export the pathfinding scores used by the router. + rpc ExportPathfindingScores(ExportPathfindingScoresRequest) returns (ExportPathfindingScoresResponse); + // Send a payment given a BIP 21 URI or BIP 353 Human-Readable Name. + rpc UnifiedSend(UnifiedSendRequest) returns (UnifiedSendResponse); + // List all known short channel IDs in the network graph. + rpc GraphListChannels(GraphListChannelsRequest) returns (GraphListChannelsResponse); + // Get channel info from the network graph by short channel ID. + rpc GraphGetChannel(GraphGetChannelRequest) returns (GraphGetChannelResponse); + // List all known node IDs in the network graph. + rpc GraphListNodes(GraphListNodesRequest) returns (GraphListNodesResponse); + // Get node info from the network graph by node ID. + rpc GraphGetNode(GraphGetNodeRequest) returns (GraphGetNodeResponse); + // Subscribe to a stream of server events. + rpc SubscribeEvents(SubscribeEventsRequest) returns (stream events.EventEnvelope); +} diff --git a/ldk-server-protos/src/serde_utils.rs b/ldk-server-protos/src/serde_utils.rs index 5f10d137..10174871 100644 --- a/ldk-server-protos/src/serde_utils.rs +++ b/ldk-server-protos/src/serde_utils.rs @@ -25,9 +25,9 @@ macro_rules! stringify_enum_serializer { where S: serde::Serializer, { - let name = match <$enum_type>::from_i32(*value) { - Some(v) => v.as_str_name(), - None => "UNKNOWN", + let name = match <$enum_type>::try_from(*value) { + Ok(v) => v.as_str_name(), + Err(_) => "UNKNOWN", }; serializer.serialize_str(name) } diff --git a/ldk-server-protos/src/types.rs b/ldk-server-protos/src/types.rs index 280e34f4..65d0f71a 100644 --- a/ldk-server-protos/src/types.rs +++ b/ldk-server-protos/src/types.rs @@ -7,11 +7,11 @@ // You may not use this file except in accordance with one or both of these // licenses. +// This file is @generated by prost-build. /// 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 { /// An identifier used to uniquely identify a payment in hex-encoded form. @@ -49,7 +49,6 @@ pub struct 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 PaymentKind { #[prost(oneof = "payment_kind::Kind", tags = "1, 2, 3, 4, 5, 6")] @@ -59,7 +58,6 @@ pub struct 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 { #[prost(message, tag = "1")] @@ -79,7 +77,6 @@ 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 { /// The transaction identifier of this payment. @@ -91,7 +88,6 @@ pub struct Onchain { } #[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 { #[prost(oneof = "confirmation_status::Status", tags = "1, 2")] @@ -101,7 +97,6 @@ pub struct 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 { #[prost(message, tag = "1")] @@ -113,7 +108,6 @@ 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 { /// The hex representation of hash of the block in which the transaction was confirmed. @@ -129,13 +123,11 @@ pub struct Confirmed { /// 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)] +#[derive(Clone, Copy, 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 { /// The payment hash, i.e., the hash of the preimage. @@ -155,7 +147,6 @@ pub struct Bolt11 { /// 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 { /// The payment hash, i.e., the hash of the preimage. @@ -175,7 +166,7 @@ pub struct Bolt11Jit { /// /// 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`\]() + /// See [`LdkChannelConfig::accept_underpaying_htlcs`]() /// for more information. #[prost(message, optional, tag = "4")] pub lsp_fee_limits: ::core::option::Option, @@ -189,7 +180,6 @@ pub struct Bolt11Jit { /// 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 { /// The payment hash, i.e., the hash of the preimage. @@ -209,7 +199,7 @@ pub struct Bolt12Offer { #[prost(string, tag = "4")] pub offer_id: ::prost::alloc::string::String, /// The payer's note for the payment. - /// Truncated to \[PAYER_NOTE_LIMIT\](). + /// 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. @@ -222,7 +212,6 @@ pub struct Bolt12Offer { /// 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 { /// The payment hash, i.e., the hash of the preimage. @@ -239,7 +228,7 @@ pub struct Bolt12Refund { )] pub secret: ::core::option::Option<::prost::bytes::Bytes>, /// The payer's note for the payment. - /// Truncated to \[PAYER_NOTE_LIMIT\](). + /// 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. @@ -252,7 +241,6 @@ pub struct Bolt12Refund { /// 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 { /// The payment hash, i.e., the hash of the preimage. @@ -268,8 +256,7 @@ pub struct Spontaneous { /// \[`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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct LspFeeLimits { /// The maximal total amount we allow any configured LSP withhold from us when forwarding the /// payment. @@ -284,7 +271,6 @@ pub struct LspFeeLimits { /// 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 { /// The channel id of the incoming channel between the previous node and us. @@ -336,7 +322,6 @@ pub struct ForwardedPayment { } #[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 { /// The channel ID (prior to funding transaction generation, this is a random 32-byte @@ -470,8 +455,7 @@ pub struct 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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct ChannelConfig { /// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound /// over the channel. @@ -515,8 +499,7 @@ pub mod channel_config { /// 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)] + #[derive(Clone, Copy, PartialEq, ::prost::Oneof)] pub enum MaxDustHtlcExposure { /// This sets a fixed limit on the total dust exposure in millisatoshis. /// See more: @@ -531,7 +514,6 @@ 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 { /// The referenced transaction's txid. @@ -543,7 +525,6 @@ pub struct 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 BestBlock { /// The block’s hash @@ -556,7 +537,6 @@ pub struct BestBlock { /// 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 { #[prost(oneof = "lightning_balance::BalanceType", tags = "1, 2, 3, 4, 5, 6")] @@ -566,7 +546,6 @@ pub struct 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 { #[prost(message, tag = "1")] @@ -588,7 +567,6 @@ pub mod lightning_balance { /// 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 { /// The identifier of the channel this balance belongs to. @@ -645,7 +623,6 @@ pub struct ClaimableOnChannelClose { /// 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 { /// The identifier of the channel this balance belongs to. @@ -678,7 +655,6 @@ pub struct 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 { /// The identifier of the channel this balance belongs to. @@ -706,7 +682,6 @@ pub struct ContentiousClaimable { /// 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 { /// The identifier of the channel this balance belongs to. @@ -735,7 +710,6 @@ pub struct MaybeTimeoutClaimableHtlc { /// 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 { /// The identifier of the channel this balance belongs to. @@ -763,7 +737,6 @@ pub struct MaybePreimageClaimableHtlc { /// 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 { /// The identifier of the channel this balance belongs to. @@ -779,7 +752,6 @@ pub struct CounterpartyRevokedOutputClaimable { /// 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 { #[prost(oneof = "pending_sweep_balance::BalanceType", tags = "1, 2, 3")] @@ -789,7 +761,6 @@ pub struct 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 { #[prost(message, tag = "1")] @@ -804,7 +775,6 @@ pub mod pending_sweep_balance { /// 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 { /// The identifier of the channel this balance belongs to. @@ -818,7 +788,6 @@ pub struct PendingBroadcast { /// 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 { /// The identifier of the channel this balance belongs to. @@ -840,7 +809,6 @@ pub struct BroadcastAwaitingConfirmation { /// 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 { /// The identifier of the channel this balance belongs to. @@ -862,7 +830,6 @@ pub struct AwaitingThresholdConfirmations { /// 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 { #[prost(string, tag = "1")] @@ -872,7 +839,6 @@ pub struct PageToken { } #[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 { #[prost(oneof = "bolt11_invoice_description::Kind", tags = "1, 2")] @@ -882,7 +848,6 @@ pub struct 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 { #[prost(string, tag = "1")] @@ -895,8 +860,7 @@ pub mod bolt11_invoice_description { /// 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)] +#[derive(Clone, Copy, 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 @@ -919,8 +883,7 @@ pub struct RouteParametersConfig { /// Routing fees for a channel as part of the network graph. #[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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct GraphRoutingFees { /// Flat routing fee in millisatoshis. #[prost(uint32, tag = "1")] @@ -933,8 +896,7 @@ pub struct GraphRoutingFees { /// as received within a `ChannelUpdate`. #[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)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct GraphChannelUpdate { /// When the last update to the channel direction was issued. /// Value is opaque, as set in the announcement. @@ -960,7 +922,6 @@ pub struct GraphChannelUpdate { /// Received within a channel announcement. #[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 GraphChannel { /// Source node of the first direction of the channel (hex-encoded public key). @@ -982,7 +943,6 @@ pub struct GraphChannel { /// Information received in the latest node_announcement from this 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 GraphNodeAnnouncement { /// When the last known update to the node state was issued. @@ -1004,7 +964,6 @@ pub struct GraphNodeAnnouncement { /// 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 Peer { /// The hex-encoded node ID of the peer. @@ -1023,7 +982,6 @@ pub struct Peer { /// Details about a node in the network graph, known from the network announcement. #[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 GraphNode { /// All valid channels a node has announced. @@ -1053,8 +1011,8 @@ impl PaymentDirection { /// (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", + Self::Inbound => "INBOUND", + Self::Outbound => "OUTBOUND", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1086,9 +1044,9 @@ impl PaymentStatus { /// (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", + Self::Pending => "PENDING", + Self::Succeeded => "SUCCEEDED", + Self::Failed => "FAILED", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1124,10 +1082,10 @@ impl BalanceSource { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - BalanceSource::HolderForceClosed => "HOLDER_FORCE_CLOSED", - BalanceSource::CounterpartyForceClosed => "COUNTERPARTY_FORCE_CLOSED", - BalanceSource::CoopClose => "COOP_CLOSE", - BalanceSource::Htlc => "HTLC", + Self::HolderForceClosed => "HOLDER_FORCE_CLOSED", + Self::CounterpartyForceClosed => "COUNTERPARTY_FORCE_CLOSED", + Self::CoopClose => "COOP_CLOSE", + Self::Htlc => "HTLC", } } /// Creates an enum from field names used in the ProtoBuf definition. diff --git a/ldk-server/Cargo.toml b/ldk-server/Cargo.toml index 4156a649..fd7bfe35 100644 --- a/ldk-server/Cargo.toml +++ b/ldk-server/Cargo.toml @@ -6,37 +6,26 @@ edition = "2021" [dependencies] ldk-node = { git = "https://github.com/lightningdevkit/ldk-node", rev = "9e0a8124cbe2c00a06fc5c880113213d4b36d8aa" } 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 } -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"] } +tonic = { version = "0.12", features = ["tls"] } +tokio = { version = "1.38.0", default-features = false, features = ["time", "signal", "rt-multi-thread", "sync"] } +tokio-stream = { version = "0.1", default-features = false, features = ["sync"] } ring = { version = "0.17", default-features = false } getrandom = { version = "0.2", default-features = false } -prost = { version = "0.11.6", default-features = false, features = ["std"] } -ldk-server-protos = { path = "../ldk-server-protos" } +prost = { version = "0.13", default-features = false, features = ["std"] } +ldk-server-protos = { path = "../ldk-server-protos", features = ["server"] } 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"] } -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"] } clap = { version = "4.0.5", default-features = false, features = ["derive", "std", "error-context", "suggestions", "help", "env"] } -# 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"] # Experimental Features. experimental-lsps2-support = [] -# 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-config.toml b/ldk-server/ldk-server-config.toml index 48b6c7b1..c6ecfb82 100644 --- a/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server-config.toml @@ -3,7 +3,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:3536" # LDK Server REST address (optional, defaults to 127.0.0.1:3536) +#grpc_service_address = "127.0.0.1:3536" # LDK Server gRPC address (optional, defaults to 127.0.0.1:3536) alias = "ldk_server" # Lightning node alias #pathfinding_scores_source_url = "" # External Pathfinding Scores Source #rgs_server_url = "https://rapidsync.lightningdevkit.org/snapshot/v2/" # Optional: RGS URL for rapid gossip sync @@ -38,11 +38,6 @@ server_url = "ssl://electrum.blockstream.info:50002" # Electrum endpoint [esplora] server_url = "https://mempool.space/api" # Esplora endpoint -# RabbitMQ settings (only required if using events-rabbitmq feature) -[rabbitmq] -connection_string = "" # RabbitMQ connection string -exchange_name = "" - # LSPS2 Client Support [liquidity.lsps2_client] # The public key of the LSPS2 LSP we source just-in-time liquidity from. diff --git a/ldk-server/src/api/bolt11_claim_for_hash.rs b/ldk-server/src/api/bolt11_claim_for_hash.rs index e1e62288..b7ef3b99 100644 --- a/ldk-server/src/api/bolt11_claim_for_hash.rs +++ b/ldk-server/src/api/bolt11_claim_for_hash.rs @@ -14,7 +14,7 @@ use ldk_server_protos::api::{Bolt11ClaimForHashRequest, Bolt11ClaimForHashRespon use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_bolt11_claim_for_hash_request( context: Context, request: Bolt11ClaimForHashRequest, diff --git a/ldk-server/src/api/bolt11_fail_for_hash.rs b/ldk-server/src/api/bolt11_fail_for_hash.rs index 9f349164..aa25c604 100644 --- a/ldk-server/src/api/bolt11_fail_for_hash.rs +++ b/ldk-server/src/api/bolt11_fail_for_hash.rs @@ -13,7 +13,7 @@ use ldk_server_protos::api::{Bolt11FailForHashRequest, Bolt11FailForHashResponse use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_bolt11_fail_for_hash_request( context: Context, request: Bolt11FailForHashRequest, diff --git a/ldk-server/src/api/bolt11_receive.rs b/ldk-server/src/api/bolt11_receive.rs index 793a0928..e637cd7e 100644 --- a/ldk-server/src/api/bolt11_receive.rs +++ b/ldk-server/src/api/bolt11_receive.rs @@ -11,7 +11,7 @@ use hex::DisplayHex; use ldk_server_protos::api::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; use crate::util::proto_adapter::proto_to_bolt11_description; pub(crate) fn handle_bolt11_receive_request( diff --git a/ldk-server/src/api/bolt11_receive_for_hash.rs b/ldk-server/src/api/bolt11_receive_for_hash.rs index 8f687067..803f1667 100644 --- a/ldk-server/src/api/bolt11_receive_for_hash.rs +++ b/ldk-server/src/api/bolt11_receive_for_hash.rs @@ -13,7 +13,7 @@ use ldk_server_protos::api::{Bolt11ReceiveForHashRequest, Bolt11ReceiveForHashRe use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use crate::grpc_service::Context; use crate::util::proto_adapter::proto_to_bolt11_description; pub(crate) fn handle_bolt11_receive_for_hash_request( diff --git a/ldk-server/src/api/bolt11_receive_via_jit_channel.rs b/ldk-server/src/api/bolt11_receive_via_jit_channel.rs index 552a1823..2c528d42 100644 --- a/ldk-server/src/api/bolt11_receive_via_jit_channel.rs +++ b/ldk-server/src/api/bolt11_receive_via_jit_channel.rs @@ -14,7 +14,7 @@ use ldk_server_protos::api::{ }; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; use crate::util::proto_adapter::proto_to_bolt11_description; pub(crate) fn handle_bolt11_receive_via_jit_channel_request( diff --git a/ldk-server/src/api/bolt11_send.rs b/ldk-server/src/api/bolt11_send.rs index 1298896e..28060e59 100644 --- a/ldk-server/src/api/bolt11_send.rs +++ b/ldk-server/src/api/bolt11_send.rs @@ -14,7 +14,7 @@ use ldk_server_protos::api::{Bolt11SendRequest, Bolt11SendResponse}; use crate::api::build_route_parameters_config_from_proto; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_bolt11_send_request( context: Context, request: Bolt11SendRequest, diff --git a/ldk-server/src/api/bolt12_receive.rs b/ldk-server/src/api/bolt12_receive.rs index 42f4b489..62dd4d95 100644 --- a/ldk-server/src/api/bolt12_receive.rs +++ b/ldk-server/src/api/bolt12_receive.rs @@ -11,7 +11,7 @@ use hex::DisplayHex; use ldk_server_protos::api::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_bolt12_receive_request( context: Context, request: Bolt12ReceiveRequest, diff --git a/ldk-server/src/api/bolt12_send.rs b/ldk-server/src/api/bolt12_send.rs index 30df2dd8..2ea3ca3f 100644 --- a/ldk-server/src/api/bolt12_send.rs +++ b/ldk-server/src/api/bolt12_send.rs @@ -14,7 +14,7 @@ use ldk_server_protos::api::{Bolt12SendRequest, Bolt12SendResponse}; use crate::api::build_route_parameters_config_from_proto; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_bolt12_send_request( context: Context, request: Bolt12SendRequest, diff --git a/ldk-server/src/api/close_channel.rs b/ldk-server/src/api/close_channel.rs index 5ae4070b..2d982134 100644 --- a/ldk-server/src/api/close_channel.rs +++ b/ldk-server/src/api/close_channel.rs @@ -17,7 +17,7 @@ use ldk_server_protos::api::{ use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_close_channel_request( context: Context, request: CloseChannelRequest, diff --git a/ldk-server/src/api/connect_peer.rs b/ldk-server/src/api/connect_peer.rs index d3fac3a0..d5628a8f 100644 --- a/ldk-server/src/api/connect_peer.rs +++ b/ldk-server/src/api/connect_peer.rs @@ -14,7 +14,7 @@ use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_server_protos::api::{ConnectPeerRequest, ConnectPeerResponse}; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_connect_peer( context: Context, request: ConnectPeerRequest, diff --git a/ldk-server/src/api/disconnect_peer.rs b/ldk-server/src/api/disconnect_peer.rs index 76f2ecce..0ee4ac84 100644 --- a/ldk-server/src/api/disconnect_peer.rs +++ b/ldk-server/src/api/disconnect_peer.rs @@ -13,7 +13,7 @@ use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_server_protos::api::{DisconnectPeerRequest, DisconnectPeerResponse}; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_disconnect_peer( context: Context, request: DisconnectPeerRequest, diff --git a/ldk-server/src/api/error.rs b/ldk-server/src/api/error.rs index ad1c152f..2d161529 100644 --- a/ldk-server/src/api/error.rs +++ b/ldk-server/src/api/error.rs @@ -39,7 +39,7 @@ impl fmt::Display for LdkServerError { } #[derive(Clone, Debug, PartialEq, Eq)] -#[allow(clippy::enum_variant_names)] +#[allow(clippy::enum_variant_names, dead_code)] pub(crate) enum LdkServerErrorCode { /// Please refer to [`protos::error::ErrorCode::InvalidRequestError`]. InvalidRequestError, diff --git a/ldk-server/src/api/export_pathfinding_scores.rs b/ldk-server/src/api/export_pathfinding_scores.rs index a6924a22..612c9130 100644 --- a/ldk-server/src/api/export_pathfinding_scores.rs +++ b/ldk-server/src/api/export_pathfinding_scores.rs @@ -10,7 +10,7 @@ use ldk_server_protos::api::{ExportPathfindingScoresRequest, ExportPathfindingScoresResponse}; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_export_pathfinding_scores_request( context: Context, _request: ExportPathfindingScoresRequest, diff --git a/ldk-server/src/api/get_balances.rs b/ldk-server/src/api/get_balances.rs index 82ab69b7..b92ae3b0 100644 --- a/ldk-server/src/api/get_balances.rs +++ b/ldk-server/src/api/get_balances.rs @@ -10,7 +10,7 @@ use ldk_server_protos::api::{GetBalancesRequest, GetBalancesResponse}; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; use crate::util::proto_adapter::{lightning_balance_to_proto, pending_sweep_balance_to_proto}; pub(crate) fn handle_get_balances_request( diff --git a/ldk-server/src/api/get_node_info.rs b/ldk-server/src/api/get_node_info.rs index c1b81279..d331704e 100644 --- a/ldk-server/src/api/get_node_info.rs +++ b/ldk-server/src/api/get_node_info.rs @@ -11,7 +11,7 @@ use ldk_server_protos::api::{GetNodeInfoRequest, GetNodeInfoResponse}; use ldk_server_protos::types::BestBlock; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_get_node_info_request( context: Context, _request: GetNodeInfoRequest, diff --git a/ldk-server/src/api/get_payment_details.rs b/ldk-server/src/api/get_payment_details.rs index 1d7b266a..59b6f57d 100644 --- a/ldk-server/src/api/get_payment_details.rs +++ b/ldk-server/src/api/get_payment_details.rs @@ -13,7 +13,7 @@ use ldk_server_protos::api::{GetPaymentDetailsRequest, GetPaymentDetailsResponse use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use crate::grpc_service::Context; use crate::util::proto_adapter::payment_to_proto; pub(crate) fn handle_get_payment_details_request( diff --git a/ldk-server/src/api/graph_get_channel.rs b/ldk-server/src/api/graph_get_channel.rs index 3e20a2a0..4906c8bc 100644 --- a/ldk-server/src/api/graph_get_channel.rs +++ b/ldk-server/src/api/graph_get_channel.rs @@ -11,7 +11,7 @@ use ldk_server_protos::api::{GraphGetChannelRequest, GraphGetChannelResponse}; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use crate::grpc_service::Context; use crate::util::proto_adapter::graph_channel_to_proto; pub(crate) fn handle_graph_get_channel_request( diff --git a/ldk-server/src/api/graph_get_node.rs b/ldk-server/src/api/graph_get_node.rs index 9ddb0eac..373f0ce4 100644 --- a/ldk-server/src/api/graph_get_node.rs +++ b/ldk-server/src/api/graph_get_node.rs @@ -12,7 +12,7 @@ use ldk_server_protos::api::{GraphGetNodeRequest, GraphGetNodeResponse}; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use crate::grpc_service::Context; use crate::util::proto_adapter::graph_node_to_proto; pub(crate) fn handle_graph_get_node_request( diff --git a/ldk-server/src/api/graph_list_channels.rs b/ldk-server/src/api/graph_list_channels.rs index 60543292..1ec7d009 100644 --- a/ldk-server/src/api/graph_list_channels.rs +++ b/ldk-server/src/api/graph_list_channels.rs @@ -10,7 +10,7 @@ use ldk_server_protos::api::{GraphListChannelsRequest, GraphListChannelsResponse}; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_graph_list_channels_request( context: Context, _request: GraphListChannelsRequest, diff --git a/ldk-server/src/api/graph_list_nodes.rs b/ldk-server/src/api/graph_list_nodes.rs index 64ccd295..76700bd7 100644 --- a/ldk-server/src/api/graph_list_nodes.rs +++ b/ldk-server/src/api/graph_list_nodes.rs @@ -10,7 +10,7 @@ use ldk_server_protos::api::{GraphListNodesRequest, GraphListNodesResponse}; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_graph_list_nodes_request( context: Context, _request: GraphListNodesRequest, diff --git a/ldk-server/src/api/list_channels.rs b/ldk-server/src/api/list_channels.rs index 84d1584b..09f1a5e5 100644 --- a/ldk-server/src/api/list_channels.rs +++ b/ldk-server/src/api/list_channels.rs @@ -10,7 +10,7 @@ use ldk_server_protos::api::{ListChannelsRequest, ListChannelsResponse}; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; use crate::util::proto_adapter::channel_to_proto; pub(crate) fn handle_list_channels_request( diff --git a/ldk-server/src/api/list_forwarded_payments.rs b/ldk-server/src/api/list_forwarded_payments.rs index 78ce3dc4..c3ab0d23 100644 --- a/ldk-server/src/api/list_forwarded_payments.rs +++ b/ldk-server/src/api/list_forwarded_payments.rs @@ -14,11 +14,11 @@ use prost::Message; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InternalServerError; +use crate::grpc_service::Context; use crate::io::persist::{ FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, }; -use crate::service::Context; pub(crate) fn handle_list_forwarded_payments_request( context: Context, request: ListForwardedPaymentsRequest, diff --git a/ldk-server/src/api/list_payments.rs b/ldk-server/src/api/list_payments.rs index fbaf7c55..0ce843c1 100644 --- a/ldk-server/src/api/list_payments.rs +++ b/ldk-server/src/api/list_payments.rs @@ -14,10 +14,10 @@ use prost::Message; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InternalServerError; +use crate::grpc_service::Context; use crate::io::persist::{ PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, }; -use crate::service::Context; pub(crate) fn handle_list_payments_request( context: Context, request: ListPaymentsRequest, diff --git a/ldk-server/src/api/list_peers.rs b/ldk-server/src/api/list_peers.rs index c75e119e..d3a868b7 100644 --- a/ldk-server/src/api/list_peers.rs +++ b/ldk-server/src/api/list_peers.rs @@ -10,7 +10,7 @@ use ldk_server_protos::api::{ListPeersRequest, ListPeersResponse}; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; use crate::util::proto_adapter::peer_to_proto; pub(crate) fn handle_list_peers_request( diff --git a/ldk-server/src/api/onchain_receive.rs b/ldk-server/src/api/onchain_receive.rs index cad2837e..7e4ee8e2 100644 --- a/ldk-server/src/api/onchain_receive.rs +++ b/ldk-server/src/api/onchain_receive.rs @@ -10,7 +10,7 @@ use ldk_server_protos::api::{OnchainReceiveRequest, OnchainReceiveResponse}; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_onchain_receive_request( context: Context, _request: OnchainReceiveRequest, diff --git a/ldk-server/src/api/onchain_send.rs b/ldk-server/src/api/onchain_send.rs index 6eb1d63a..2098190d 100644 --- a/ldk-server/src/api/onchain_send.rs +++ b/ldk-server/src/api/onchain_send.rs @@ -14,7 +14,7 @@ use ldk_server_protos::api::{OnchainSendRequest, OnchainSendResponse}; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_onchain_send_request( context: Context, request: OnchainSendRequest, diff --git a/ldk-server/src/api/open_channel.rs b/ldk-server/src/api/open_channel.rs index 6c470b71..6611e607 100644 --- a/ldk-server/src/api/open_channel.rs +++ b/ldk-server/src/api/open_channel.rs @@ -16,7 +16,7 @@ use ldk_server_protos::api::{OpenChannelRequest, OpenChannelResponse}; use crate::api::build_channel_config_from_proto; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_open_channel( context: Context, request: OpenChannelRequest, diff --git a/ldk-server/src/api/sign_message.rs b/ldk-server/src/api/sign_message.rs index 8ef0e015..a344d472 100644 --- a/ldk-server/src/api/sign_message.rs +++ b/ldk-server/src/api/sign_message.rs @@ -10,7 +10,7 @@ use ldk_server_protos::api::{SignMessageRequest, SignMessageResponse}; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_sign_message_request( context: Context, request: SignMessageRequest, diff --git a/ldk-server/src/api/splice_channel.rs b/ldk-server/src/api/splice_channel.rs index 5d6edfec..db78e458 100644 --- a/ldk-server/src/api/splice_channel.rs +++ b/ldk-server/src/api/splice_channel.rs @@ -18,7 +18,7 @@ use ldk_server_protos::api::{ use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_splice_in_request( context: Context, request: SpliceInRequest, diff --git a/ldk-server/src/api/spontaneous_send.rs b/ldk-server/src/api/spontaneous_send.rs index 77fe3b8a..98d63e86 100644 --- a/ldk-server/src/api/spontaneous_send.rs +++ b/ldk-server/src/api/spontaneous_send.rs @@ -15,7 +15,7 @@ use ldk_server_protos::api::{SpontaneousSendRequest, SpontaneousSendResponse}; use crate::api::build_route_parameters_config_from_proto; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_spontaneous_send_request( context: Context, request: SpontaneousSendRequest, diff --git a/ldk-server/src/api/unified_send.rs b/ldk-server/src/api/unified_send.rs index 3f7807b4..86a3d150 100644 --- a/ldk-server/src/api/unified_send.rs +++ b/ldk-server/src/api/unified_send.rs @@ -14,7 +14,7 @@ use tokio::runtime::Handle; use crate::api::build_route_parameters_config_from_proto; use crate::api::error::LdkServerError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_unified_send_request( context: Context, request: UnifiedSendRequest, diff --git a/ldk-server/src/api/update_channel_config.rs b/ldk-server/src/api/update_channel_config.rs index 780374c5..c67472f6 100644 --- a/ldk-server/src/api/update_channel_config.rs +++ b/ldk-server/src/api/update_channel_config.rs @@ -16,7 +16,7 @@ use ldk_server_protos::api::{UpdateChannelConfigRequest, UpdateChannelConfigResp 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 crate::grpc_service::Context; pub(crate) fn handle_update_channel_config_request( context: Context, request: UpdateChannelConfigRequest, diff --git a/ldk-server/src/api/verify_signature.rs b/ldk-server/src/api/verify_signature.rs index 9b7551ea..0cac9a94 100644 --- a/ldk-server/src/api/verify_signature.rs +++ b/ldk-server/src/api/verify_signature.rs @@ -14,7 +14,7 @@ use ldk_server_protos::api::{VerifySignatureRequest, VerifySignatureResponse}; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::service::Context; +use crate::grpc_service::Context; pub(crate) fn handle_verify_signature_request( context: Context, request: VerifySignatureRequest, diff --git a/ldk-server/src/grpc_service.rs b/ldk-server/src/grpc_service.rs new file mode 100644 index 00000000..85788820 --- /dev/null +++ b/ldk-server/src/grpc_service.rs @@ -0,0 +1,401 @@ +// 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::pin::Pin; +use std::sync::Arc; + +use ldk_node::bitcoin::hashes::hmac::{Hmac, HmacEngine}; +use ldk_node::bitcoin::hashes::{sha256, Hash, HashEngine}; +use ldk_node::Node; +use ldk_server_protos::api::lightning_node_server::LightningNode; +use ldk_server_protos::api::*; +use ldk_server_protos::events::EventEnvelope; +use tokio::sync::broadcast; +use tokio_stream::wrappers::BroadcastStream; +use tokio_stream::StreamExt; +use tonic::service::Interceptor; +use tonic::{Request, Response, Status}; + +use crate::api::bolt11_claim_for_hash::handle_bolt11_claim_for_hash_request; +use crate::api::bolt11_fail_for_hash::handle_bolt11_fail_for_hash_request; +use crate::api::bolt11_receive::handle_bolt11_receive_request; +use crate::api::bolt11_receive_for_hash::handle_bolt11_receive_for_hash_request; +use crate::api::bolt11_receive_via_jit_channel::{ + handle_bolt11_receive_variable_amount_via_jit_channel_request, + handle_bolt11_receive_via_jit_channel_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::connect_peer::handle_connect_peer; +use crate::api::disconnect_peer::handle_disconnect_peer; +use crate::api::error::{LdkServerError, LdkServerErrorCode}; +use crate::api::export_pathfinding_scores::handle_export_pathfinding_scores_request; +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::graph_get_channel::handle_graph_get_channel_request; +use crate::api::graph_get_node::handle_graph_get_node_request; +use crate::api::graph_list_channels::handle_graph_list_channels_request; +use crate::api::graph_list_nodes::handle_graph_list_nodes_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::list_peers::handle_list_peers_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::sign_message::handle_sign_message_request; +use crate::api::splice_channel::{handle_splice_in_request, handle_splice_out_request}; +use crate::api::spontaneous_send::handle_spontaneous_send_request; +use crate::api::unified_send::handle_unified_send_request; +use crate::api::update_channel_config::handle_update_channel_config_request; +use crate::api::verify_signature::handle_verify_signature_request; +use crate::io::persist::paginated_kv_store::PaginatedKVStore; + +/// Maximum allowed time difference between client timestamp and server time (1 minute). +const AUTH_TIMESTAMP_TOLERANCE_SECS: u64 = 60; + +/// Interceptor that validates HMAC auth metadata on incoming gRPC requests. +#[derive(Clone)] +pub(crate) struct AuthInterceptor { + api_key: String, +} + +impl AuthInterceptor { + pub(crate) fn new(api_key: String) -> Self { + Self { api_key } + } +} + +impl Interceptor for AuthInterceptor { + fn call(&mut self, request: Request<()>) -> Result, Status> { + let auth_header = request + .metadata() + .get("x-auth") + .and_then(|v| v.to_str().ok()) + .ok_or_else(|| Status::unauthenticated("Missing x-auth metadata"))?; + + let auth_data = auth_header + .strip_prefix("HMAC ") + .ok_or_else(|| Status::unauthenticated("Invalid x-auth format"))?; + + let (timestamp_str, provided_hmac_hex) = auth_data + .split_once(':') + .ok_or_else(|| Status::unauthenticated("Invalid x-auth format"))?; + + let timestamp = timestamp_str + .parse::() + .map_err(|_| Status::unauthenticated("Invalid timestamp in x-auth"))?; + + if provided_hmac_hex.len() != 64 + || !provided_hmac_hex.chars().all(|c| c.is_ascii_hexdigit()) + { + return Err(Status::unauthenticated("Invalid HMAC in x-auth")); + } + + // Validate timestamp is within acceptable window + let now = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map_err(|_| Status::internal("System time error"))? + .as_secs(); + + if now.abs_diff(timestamp) > AUTH_TIMESTAMP_TOLERANCE_SECS { + return Err(Status::unauthenticated("Request timestamp expired")); + } + + // Compute expected HMAC: HMAC-SHA256(api_key, timestamp_bytes) + let mut hmac_engine: HmacEngine = HmacEngine::new(self.api_key.as_bytes()); + hmac_engine.input(×tamp.to_be_bytes()); + let expected_hmac = Hmac::::from_engine(hmac_engine); + + if expected_hmac.to_string() != provided_hmac_hex { + return Err(Status::unauthenticated("Invalid credentials")); + } + + Ok(request) + } +} + +pub(crate) struct Context { + pub(crate) node: Arc, + pub(crate) paginated_kv_store: Arc, +} + +pub(crate) struct NodeGrpcService { + node: Arc, + paginated_kv_store: Arc, + event_sender: broadcast::Sender, +} + +impl NodeGrpcService { + pub(crate) fn new( + node: Arc, paginated_kv_store: Arc, + event_sender: broadcast::Sender, + ) -> Self { + Self { node, paginated_kv_store, event_sender } + } + + fn context(&self) -> Context { + Context { + node: Arc::clone(&self.node), + paginated_kv_store: Arc::clone(&self.paginated_kv_store), + } + } +} + +fn into_status(e: LdkServerError) -> Status { + let code = match e.error_code { + LdkServerErrorCode::InvalidRequestError => tonic::Code::InvalidArgument, + LdkServerErrorCode::AuthError => tonic::Code::Unauthenticated, + LdkServerErrorCode::LightningError => tonic::Code::FailedPrecondition, + LdkServerErrorCode::InternalServerError => tonic::Code::Internal, + }; + Status::new(code, e.message) +} + +/// A helper macro to implement a unary gRPC method by delegating to an existing handler function. +macro_rules! impl_unary { + ($self:ident, $request:ident, $handler:ident) => {{ + let ctx = $self.context(); + $handler(ctx, $request.into_inner()).map(Response::new).map_err(into_status) + }}; +} + +type EventStream = Pin> + Send>>; + +#[tonic::async_trait] +impl LightningNode for NodeGrpcService { + async fn get_node_info( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_get_node_info_request) + } + + async fn get_balances( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_get_balances_request) + } + + async fn onchain_receive( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_onchain_receive_request) + } + + async fn onchain_send( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_onchain_send_request) + } + + async fn bolt11_receive( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_bolt11_receive_request) + } + + async fn bolt11_receive_for_hash( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_bolt11_receive_for_hash_request) + } + + async fn bolt11_claim_for_hash( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_bolt11_claim_for_hash_request) + } + + async fn bolt11_fail_for_hash( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_bolt11_fail_for_hash_request) + } + + async fn bolt11_receive_via_jit_channel( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_bolt11_receive_via_jit_channel_request) + } + + async fn bolt11_receive_variable_amount_via_jit_channel( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_bolt11_receive_variable_amount_via_jit_channel_request) + } + + async fn bolt11_send( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_bolt11_send_request) + } + + async fn bolt12_receive( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_bolt12_receive_request) + } + + async fn bolt12_send( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_bolt12_send_request) + } + + async fn spontaneous_send( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_spontaneous_send_request) + } + + async fn open_channel( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_open_channel) + } + + async fn splice_in( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_splice_in_request) + } + + async fn splice_out( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_splice_out_request) + } + + async fn update_channel_config( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_update_channel_config_request) + } + + async fn close_channel( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_close_channel_request) + } + + async fn force_close_channel( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_force_close_channel_request) + } + + async fn list_channels( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_list_channels_request) + } + + async fn get_payment_details( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_get_payment_details_request) + } + + async fn list_payments( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_list_payments_request) + } + + async fn list_forwarded_payments( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_list_forwarded_payments_request) + } + + async fn connect_peer( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_connect_peer) + } + + async fn disconnect_peer( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_disconnect_peer) + } + + async fn list_peers( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_list_peers_request) + } + + async fn sign_message( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_sign_message_request) + } + + async fn verify_signature( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_verify_signature_request) + } + + async fn export_pathfinding_scores( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_export_pathfinding_scores_request) + } + + async fn unified_send( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_unified_send_request) + } + + async fn graph_list_channels( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_graph_list_channels_request) + } + + async fn graph_get_channel( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_graph_get_channel_request) + } + + async fn graph_list_nodes( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_graph_list_nodes_request) + } + + async fn graph_get_node( + &self, request: Request, + ) -> Result, Status> { + impl_unary!(self, request, handle_graph_get_node_request) + } + + type SubscribeEventsStream = EventStream; + + async fn subscribe_events( + &self, _request: Request, + ) -> Result, Status> { + let rx = self.event_sender.subscribe(); + let stream = BroadcastStream::new(rx).filter_map(|result| match result { + Ok(event) => Some(Ok(event)), + Err(tokio_stream::wrappers::errors::BroadcastStreamRecvError::Lagged(n)) => { + log::warn!("Event subscriber lagged by {} events", n); + None + }, + }); + Ok(Response::new(Box::pin(stream))) + } +} diff --git a/ldk-server/src/io/events/event_publisher.rs b/ldk-server/src/io/events/event_publisher.rs deleted file mode 100644 index 308bde25..00000000 --- a/ldk-server/src/io/events/event_publisher.rs +++ /dev/null @@ -1,68 +0,0 @@ -// 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 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 -/// 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: Send + Sync { - /// 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>; -} - -/// 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. - /// - /// 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(()) - } -} diff --git a/ldk-server/src/io/events/mod.rs b/ldk-server/src/io/events/mod.rs deleted file mode 100644 index 4ec9a65a..00000000 --- a/ldk-server/src/io/events/mod.rs +++ /dev/null @@ -1,26 +0,0 @@ -// 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")] -pub(crate) mod rabbitmq; - -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", - event_envelope::Event::PaymentClaimable(_) => "PaymentClaimable", - } -} diff --git a/ldk-server/src/io/events/rabbitmq/mod.rs b/ldk-server/src/io/events/rabbitmq/mod.rs deleted file mode 100644 index a20b5bd9..00000000 --- a/ldk-server/src/io/events/rabbitmq/mod.rs +++ /dev/null @@ -1,244 +0,0 @@ -// 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::sync::Arc; - -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 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. - 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())) - }, - } - } -} - -#[cfg(test)] -#[cfg(feature = "integration-tests-events-rabbitmq")] -mod integration_tests_events_rabbitmq { - 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 tokio; - - use super::*; - #[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(()) - } -} diff --git a/ldk-server/src/io/mod.rs b/ldk-server/src/io/mod.rs index ab1df5f6..8f1ebca4 100644 --- a/ldk-server/src/io/mod.rs +++ b/ldk-server/src/io/mod.rs @@ -7,6 +7,5 @@ // 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/src/main.rs b/ldk-server/src/main.rs index 3de2a408..097fc4a4 100644 --- a/ldk-server/src/main.rs +++ b/ldk-server/src/main.rs @@ -8,8 +8,8 @@ // licenses. mod api; +mod grpc_service; mod io; -mod service; mod util; use std::fs; @@ -20,26 +20,23 @@ use std::time::{SystemTime, UNIX_EPOCH}; use clap::Parser; 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; use ldk_node::{Builder, Event, Node}; +use ldk_server_protos::api::lightning_node_server::LightningNodeServer; use ldk_server_protos::events; use ldk_server_protos::events::{event_envelope, EventEnvelope}; use ldk_server_protos::types::Payment; use log::{debug, error, info}; use prost::Message; -use tokio::net::TcpListener; use tokio::select; use tokio::signal::unix::SignalKind; +use tokio::sync::broadcast; +use tonic::transport::{Identity, ServerTlsConfig}; -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}; +use crate::grpc_service::{AuthInterceptor, NodeGrpcService}; use crate::io::persist::paginated_kv_store::PaginatedKVStore; use crate::io::persist::sqlite_store::SqliteStore; use crate::io::persist::{ @@ -47,12 +44,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, ArgsConfig, ChainSource}; use crate::util::logger::ServerLogger; use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto}; use crate::util::systemd; -use crate::util::tls::get_or_generate_tls_config; +use crate::util::tls::get_or_generate_tls_pem; const API_KEY_FILE: &str = "api_key"; @@ -222,18 +218,7 @@ fn main() { }, }); - #[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 = { - let rabbitmq_config = RabbitMqConfig { - connection_string: config_file.rabbitmq_connection_string, - exchange_name: config_file.rabbitmq_exchange_name, - }; - Arc::new(RabbitMqEventPublisher::new(rabbitmq_config)) - }; + let (event_sender, _) = broadcast::channel::(1024); info!("Starting up..."); match node.start() { @@ -256,7 +241,6 @@ fn main() { } 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) => { @@ -272,112 +256,117 @@ fn main() { 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"); - let server_config = match get_or_generate_tls_config( + let tls_pem = match get_or_generate_tls_pem( config_file.tls_config, storage_dir.to_str().unwrap(), ) { - Ok(config) => config, + Ok(pem) => pem, 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); + let identity = Identity::from_pem(&tls_pem.cert_pem, &tls_pem.key_pem); + let tls_config = ServerTlsConfig::new().identity(identity); + + let grpc_service = NodeGrpcService::new( + Arc::clone(&node), + Arc::clone(&paginated_store), + event_sender.clone(), + ); + + let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel::<()>(); + + let auth_interceptor = AuthInterceptor::new(api_key); + let grpc_server = tonic::transport::Server::builder() + .tls_config(tls_config) + .expect("Failed to configure TLS for gRPC server") + .add_service(LightningNodeServer::with_interceptor(grpc_service, auth_interceptor)) + .serve_with_shutdown(config_file.grpc_service_addr, async { + let _ = shutdown_rx.await; + }); + + info!("gRPC service listening on {} with TLS", config_file.grpc_service_addr); systemd::notify_ready(); + let event_node = Arc::clone(&node); + let event_paginated_store = Arc::clone(&paginated_store); + let event_tx = event_sender.clone(); + + let grpc_handle = tokio::spawn(grpc_server); + + // Event processing and signal handling loop loop { select! { event = event_node.next_event_async() => { - match event { - Event::ChannelPending { channel_id, counterparty_node_id, .. } => { - info!( - "CHANNEL_PENDING: {} from counterparty {}", - channel_id, counterparty_node_id - ); - if let Err(e) = event_node.event_handled() { - error!("Failed to mark event as handled: {e}"); - } - }, - Event::ChannelReady { channel_id, counterparty_node_id, .. } => { - info!( - "CHANNEL_READY: {} from counterparty {:?}", - channel_id, counterparty_node_id - ); - if let Err(e) = event_node.event_handled() { - error!("Failed to mark event as handled: {e}"); - } - }, - Event::PaymentReceived { payment_id, payment_hash, amount_msat, .. } => { - info!( - "PAYMENT_RECEIVED: with id {:?}, hash {}, amount_msat {}", - payment_id, payment_hash, amount_msat - ); - let payment_id = payment_id.expect("PaymentId expected for ldk-server >=0.1"); - - 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"); - - 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"); - - 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, ..} => { - publish_event_and_upsert_payment(&payment_id, - |payment_ref| event_envelope::Event::PaymentClaimable(events::PaymentClaimable { - payment: Some(payment_ref.clone()), - }), - &event_node, - Arc::clone(&event_publisher), - Arc::clone(&paginated_store)).await; - }, - Event::PaymentForwarded { - prev_channel_id, - 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, - outbound_amount_forwarded_msat - } => { - - 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 - ); - - let forwarded_payment = forwarded_payment_to_proto( + match event { + Event::ChannelPending { channel_id, counterparty_node_id, .. } => { + info!( + "CHANNEL_PENDING: {} from counterparty {}", + channel_id, counterparty_node_id + ); + if let Err(e) = event_node.event_handled() { + error!("Failed to mark event as handled: {e}"); + } + }, + Event::ChannelReady { channel_id, counterparty_node_id, .. } => { + info!( + "CHANNEL_READY: {} from counterparty {:?}", + channel_id, counterparty_node_id + ); + if let Err(e) = event_node.event_handled() { + error!("Failed to mark event as handled: {e}"); + } + }, + Event::PaymentReceived { payment_id, payment_hash, amount_msat, .. } => { + info!( + "PAYMENT_RECEIVED: with id {:?}, hash {}, amount_msat {}", + payment_id, payment_hash, amount_msat + ); + let payment_id = payment_id.expect("PaymentId expected for ldk-server >=0.1"); + + publish_event_and_upsert_payment(&payment_id, + |payment_ref| event_envelope::Event::PaymentReceived(events::PaymentReceived { + payment: Some(payment_ref.clone()), + }), + &event_node, + &event_tx, + Arc::clone(&event_paginated_store)); + }, + Event::PaymentSuccessful {payment_id, ..} => { + let payment_id = payment_id.expect("PaymentId expected for ldk-server >=0.1"); + + publish_event_and_upsert_payment(&payment_id, + |payment_ref| event_envelope::Event::PaymentSuccessful(events::PaymentSuccessful { + payment: Some(payment_ref.clone()), + }), + &event_node, + &event_tx, + Arc::clone(&event_paginated_store)); + }, + Event::PaymentFailed {payment_id, ..} => { + let payment_id = payment_id.expect("PaymentId expected for ldk-server >=0.1"); + + publish_event_and_upsert_payment(&payment_id, + |payment_ref| event_envelope::Event::PaymentFailed(events::PaymentFailed { + payment: Some(payment_ref.clone()), + }), + &event_node, + &event_tx, + Arc::clone(&event_paginated_store)); + }, + Event::PaymentClaimable {payment_id, ..} => { + publish_event_and_upsert_payment(&payment_id, + |payment_ref| event_envelope::Event::PaymentClaimable(events::PaymentClaimable { + payment: Some(payment_ref.clone()), + }), + &event_node, + &event_tx, + Arc::clone(&event_paginated_store)); + }, + Event::PaymentForwarded { prev_channel_id, next_channel_id, prev_user_channel_id, @@ -388,84 +377,80 @@ fn main() { 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]; - getrandom::getrandom(&mut forwarded_payment_id).expect("Failed to generate random bytes"); - - 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 { + } => { + + 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 + ); + + let forwarded_payment = forwarded_payment_to_proto( + prev_channel_id, + 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, + outbound_amount_forwarded_msat + ); + + let mut forwarded_payment_id = [0u8; 32]; + getrandom::getrandom(&mut forwarded_payment_id).expect("Failed to generate random bytes"); + + let forwarded_payment_creation_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs() as i64; + + // Broadcast event to subscribers + if let Err(e) = event_tx.send(EventEnvelope { event: Some(event_envelope::Event::PaymentForwarded(events::PaymentForwarded { - forwarded_payment: Some(forwarded_payment.clone()), + forwarded_payment: Some(forwarded_payment.clone()), })), - }).await { - Ok(_) => {}, - Err(e) => { - error!("Failed to publish 'PaymentForwarded' event: {}", e); - continue; + }) { + debug!("No event subscribers connected: {e}"); } - }; - - 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(_) => { - if let Err(e) = event_node.event_handled() { - error!("Failed to mark event as handled: {e}"); + + match event_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(_) => { + if let Err(e) = event_node.event_handled() { + error!("Failed to mark event as handled: {e}"); + } + } + Err(e) => { + error!("Failed to write forwarded payment to persistence: {}", e); } } - Err(e) => { - error!("Failed to write forwarded payment to persistence: {}", e); + }, + _ => { + if let Err(e) = event_node.event_handled() { + error!("Failed to mark event as handled: {e}"); } - } - }, - _ => { - if let Err(e) = event_node.event_handled() { - error!("Failed to mark event as handled: {e}"); - } - }, + }, + } + }, + _ = sighup_stream.recv() => { + if let Err(e) = logger.reopen() { + error!("Failed to reopen log file on SIGHUP: {e}"); + } } - }, - res = rest_svc_listener.accept() => { - match res { - Ok((stream, _)) => { - 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 { - 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}"), - } - }); - }, - Err(e) => error!("Failed to accept connection: {}", e), + _ = tokio::signal::ctrl_c() => { + info!("Received CTRL-C, shutting down.."); + break; } - } - _ = tokio::signal::ctrl_c() => { - 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() => { + info!("Received SIGTERM, shutting down.."); + break; } } - _ = sigterm_stream.recv() => { - info!("Received SIGTERM, shutting down.."); - break; - } } + + let _ = shutdown_tx.send(()); + if let Err(e) = grpc_handle.await { + error!("gRPC server error: {e}"); } }); @@ -474,23 +459,19 @@ fn main() { info!("Shutdown complete.."); } -async fn publish_event_and_upsert_payment( +fn publish_event_and_upsert_payment( payment_id: &PaymentId, payment_to_event: fn(&Payment) -> event_envelope::Event, - event_node: &Node, event_publisher: Arc, + event_node: &Node, event_sender: &broadcast::Sender, paginated_store: Arc, ) { if let Some(payment_details) = event_node.payment(payment_id) { let payment = payment_to_proto(payment_details); 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) => { - error!("Failed to publish '{event_name}' event, : {e}"); - return; - }, - }; + // Broadcast event to subscribers + if let Err(e) = event_sender.send(EventEnvelope { event: Some(event) }) { + debug!("No event subscribers connected: {e}"); + } upsert_payment_details(event_node, Arc::clone(&paginated_store), &payment); } else { @@ -545,7 +526,7 @@ fn load_or_generate_api_key(storage_dir: &Path) -> std::io::Result { let permissions = fs::Permissions::from_mode(0o400); fs::set_permissions(&api_key_path, permissions)?; - debug!("Generated new API key at {}", api_key_path.display()); + log::debug!("Generated new API key at {}", api_key_path.display()); Ok(key_bytes.to_lower_hex_string()) } } diff --git a/ldk-server/src/service.rs b/ldk-server/src/service.rs deleted file mode 100644 index 05004ae6..00000000 --- a/ldk-server/src/service.rs +++ /dev/null @@ -1,618 +0,0 @@ -// 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::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_CLAIM_FOR_HASH_PATH, BOLT11_FAIL_FOR_HASH_PATH, BOLT11_RECEIVE_FOR_HASH_PATH, - BOLT11_RECEIVE_PATH, BOLT11_RECEIVE_VARIABLE_AMOUNT_VIA_JIT_CHANNEL_PATH, - BOLT11_RECEIVE_VIA_JIT_CHANNEL_PATH, BOLT11_SEND_PATH, BOLT12_RECEIVE_PATH, BOLT12_SEND_PATH, - CLOSE_CHANNEL_PATH, CONNECT_PEER_PATH, DISCONNECT_PEER_PATH, EXPORT_PATHFINDING_SCORES_PATH, - FORCE_CLOSE_CHANNEL_PATH, GET_BALANCES_PATH, GET_NODE_INFO_PATH, GET_PAYMENT_DETAILS_PATH, - GRAPH_GET_CHANNEL_PATH, GRAPH_GET_NODE_PATH, GRAPH_LIST_CHANNELS_PATH, GRAPH_LIST_NODES_PATH, - LIST_CHANNELS_PATH, LIST_FORWARDED_PAYMENTS_PATH, LIST_PAYMENTS_PATH, LIST_PEERS_PATH, - ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SIGN_MESSAGE_PATH, SPLICE_IN_PATH, - SPLICE_OUT_PATH, SPONTANEOUS_SEND_PATH, UNIFIED_SEND_PATH, UPDATE_CHANNEL_CONFIG_PATH, - VERIFY_SIGNATURE_PATH, -}; -use prost::Message; - -use crate::api::bolt11_claim_for_hash::handle_bolt11_claim_for_hash_request; -use crate::api::bolt11_fail_for_hash::handle_bolt11_fail_for_hash_request; -use crate::api::bolt11_receive::handle_bolt11_receive_request; -use crate::api::bolt11_receive_for_hash::handle_bolt11_receive_for_hash_request; -use crate::api::bolt11_receive_via_jit_channel::{ - handle_bolt11_receive_variable_amount_via_jit_channel_request, - handle_bolt11_receive_via_jit_channel_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::connect_peer::handle_connect_peer; -use crate::api::disconnect_peer::handle_disconnect_peer; -use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::{AuthError, InvalidRequestError}; -use crate::api::export_pathfinding_scores::handle_export_pathfinding_scores_request; -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::graph_get_channel::handle_graph_get_channel_request; -use crate::api::graph_get_node::handle_graph_get_node_request; -use crate::api::graph_list_channels::handle_graph_list_channels_request; -use crate::api::graph_list_nodes::handle_graph_list_nodes_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::list_peers::handle_list_peers_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::sign_message::handle_sign_message_request; -use crate::api::splice_channel::{handle_splice_in_request, handle_splice_out_request}; -use crate::api::spontaneous_send::handle_spontaneous_send_request; -use crate::api::unified_send::handle_unified_send_request; -use crate::api::update_channel_config::handle_update_channel_config_request; -use crate::api::verify_signature::handle_verify_signature_request; -use crate::io::persist::paginated_kv_store::PaginatedKVStore; -use crate::util::proto_adapter::to_error_response; - -// 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, - paginated_kv_store: Arc, - api_key: String, -} - -impl NodeService { - 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, -} - -impl Service> for NodeService { - type Response = Response>; - type Error = hyper::Error; - 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, - 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_RECEIVE_FOR_HASH_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_bolt11_receive_for_hash_request, - )), - BOLT11_CLAIM_FOR_HASH_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_bolt11_claim_for_hash_request, - )), - BOLT11_FAIL_FOR_HASH_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_bolt11_fail_for_hash_request, - )), - BOLT11_RECEIVE_VIA_JIT_CHANNEL_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_bolt11_receive_via_jit_channel_request, - )), - BOLT11_RECEIVE_VARIABLE_AMOUNT_VIA_JIT_CHANNEL_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_bolt11_receive_variable_amount_via_jit_channel_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, - )), - CONNECT_PEER_PATH => { - Box::pin(handle_request(context, req, auth_params, api_key, handle_connect_peer)) - }, - DISCONNECT_PEER_PATH => { - Box::pin(handle_request(context, req, auth_params, api_key, handle_disconnect_peer)) - }, - LIST_PEERS_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_list_peers_request, - )), - SPONTANEOUS_SEND_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_spontaneous_send_request, - )), - UNIFIED_SEND_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_unified_send_request, - )), - SIGN_MESSAGE_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_sign_message_request, - )), - VERIFY_SIGNATURE_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_verify_signature_request, - )), - EXPORT_PATHFINDING_SCORES_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_export_pathfinding_scores_request, - )), - GRAPH_LIST_CHANNELS_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_graph_list_channels_request, - )), - GRAPH_GET_CHANNEL_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_graph_get_channel_request, - )), - GRAPH_LIST_NODES_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_graph_list_nodes_request, - )), - GRAPH_GET_NODE_PATH => Box::pin(handle_request( - context, - req, - auth_params, - api_key, - handle_graph_get_node_request, - )), - 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(Context, T) -> Result, ->( - 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); - 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()); - }, - }; - - // 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() - .body(Full::new(Bytes::from(response.encode_to_vec()))) - // unwrap safety: body only errors when previous chained calls failed. - .unwrap()), - 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()) - }, - } -} - -#[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/src/util/config.rs b/ldk-server/src/util/config.rs index 2a6976d3..409c07a0 100644 --- a/ldk-server/src/util/config.rs +++ b/ldk-server/src/util/config.rs @@ -21,7 +21,7 @@ use ldk_node::liquidity::LSPS2ServiceConfig; use log::LevelFilter; use serde::{Deserialize, Serialize}; -const DEFAULT_REST_SERVICE_ADDRESS: &str = "127.0.0.1:3536"; +const DEFAULT_GRPC_SERVICE_ADDRESS: &str = "127.0.0.1:3536"; #[cfg(not(test))] const DEFAULT_CONFIG_FILE: &str = "config.toml"; @@ -46,14 +46,10 @@ pub struct Config { pub alias: Option, pub network: Network, pub tls_config: Option, - pub rest_service_addr: SocketAddr, + pub grpc_service_addr: SocketAddr, pub storage_dir_path: Option, pub chain_source: ChainSource, pub rgs_server_url: Option, - #[cfg_attr(not(feature = "events-rabbitmq"), allow(dead_code))] - pub rabbitmq_connection_string: String, - #[cfg_attr(not(feature = "events-rabbitmq"), allow(dead_code))] - pub rabbitmq_exchange_name: String, pub lsps2_client_config: Option, #[cfg_attr(not(feature = "experimental-lsps2-support"), allow(dead_code))] pub lsps2_service_config: Option, @@ -91,7 +87,7 @@ struct ConfigBuilder { alias: Option, network: Option, tls_config: Option, - rest_service_address: Option, + grpc_service_address: Option, storage_dir_path: Option, electrum_url: Option, esplora_url: Option, @@ -99,8 +95,6 @@ struct ConfigBuilder { bitcoind_rpc_user: Option, bitcoind_rpc_password: Option, rgs_server_url: Option, - rabbitmq_connection_string: Option, - rabbitmq_exchange_name: Option, lsps2: Option, log_level: Option, log_file_path: Option, @@ -115,8 +109,8 @@ impl ConfigBuilder { node.listening_addresses.or(self.listening_addresses.clone()); self.announcement_addresses = node.announcement_addresses.or(self.announcement_addresses.clone()); - self.rest_service_address = - node.rest_service_address.or(self.rest_service_address.clone()); + self.grpc_service_address = + node.grpc_service_address.or(self.grpc_service_address.clone()); self.alias = node.alias.or(self.alias.clone()); self.pathfinding_scores_source_url = node.pathfinding_scores_source_url.or(self.pathfinding_scores_source_url.clone()); @@ -148,11 +142,6 @@ impl ConfigBuilder { self.log_file_path = log.file.or(self.log_file_path.clone()); } - if let Some(rabbitmq) = toml.rabbitmq { - self.rabbitmq_connection_string = Some(rabbitmq.connection_string); - self.rabbitmq_exchange_name = Some(rabbitmq.exchange_name); - } - if let Some(liquidity) = toml.liquidity { self.lsps2 = Some(liquidity); } @@ -179,8 +168,8 @@ impl ConfigBuilder { self.announcement_addresses = Some(node_announcement_addresses.clone()); } - if let Some(node_rest_service_address) = &args.node_rest_service_address { - self.rest_service_address = Some(node_rest_service_address.clone()); + if let Some(node_grpc_service_address) = &args.node_grpc_service_address { + self.grpc_service_address = Some(node_grpc_service_address.clone()); } if let Some(node_alias) = &args.node_alias { @@ -211,9 +200,9 @@ impl ConfigBuilder { fn build(self) -> io::Result { let network = self.network.ok_or_else(|| missing_field_err("network"))?; - let rest_service_addr = self - .rest_service_address - .unwrap_or_else(|| DEFAULT_REST_SERVICE_ADDRESS.to_string()) + let grpc_service_addr = self + .grpc_service_address + .unwrap_or_else(|| DEFAULT_GRPC_SERVICE_ADDRESS.to_string()) .parse::() .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; @@ -315,30 +304,6 @@ impl ConfigBuilder { .transpose()? .unwrap_or(LevelFilter::Debug); - #[cfg(feature = "events-rabbitmq")] - let (rabbitmq_connection_string, rabbitmq_exchange_name) = { - let connection_string = self.rabbitmq_connection_string.ok_or_else(|| io::Error::new( - io::ErrorKind::InvalidInput, - "Both `rabbitmq.connection_string` and `rabbitmq.exchange_name` must be configured if enabling `events-rabbitmq` feature." - ))?; - let exchange_name = self.rabbitmq_exchange_name.ok_or_else(|| io::Error::new( - io::ErrorKind::InvalidInput, - "Both `rabbitmq.connection_string` and `rabbitmq.exchange_name` must be configured if enabling `events-rabbitmq` feature." - ))?; - - if connection_string.is_empty() || 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." - )); - } - - (connection_string, exchange_name) - }; - - #[cfg(not(feature = "events-rabbitmq"))] - let (rabbitmq_connection_string, rabbitmq_exchange_name) = (String::new(), String::new()); - let lsps2_client_config = self .lsps2 .as_ref() @@ -370,12 +335,10 @@ impl ConfigBuilder { announcement_addrs, alias, tls_config: self.tls_config, - rest_service_addr, + grpc_service_addr, storage_dir_path: self.storage_dir_path, chain_source, rgs_server_url: self.rgs_server_url, - rabbitmq_connection_string, - rabbitmq_exchange_name, lsps2_client_config, lsps2_service_config, log_level, @@ -393,7 +356,6 @@ pub struct TomlConfig { bitcoind: Option, electrum: Option, esplora: Option, - rabbitmq: Option, liquidity: Option, log: Option, tls: Option, @@ -404,7 +366,7 @@ struct NodeConfig { network: Option, listening_addresses: Option>, announcement_addresses: Option>, - rest_service_address: Option, + grpc_service_address: Option, alias: Option, pathfinding_scores_source_url: Option, rgs_server_url: Option, @@ -443,12 +405,6 @@ struct LogConfig { file: Option, } -#[derive(Deserialize, Serialize)] -struct RabbitmqConfig { - connection_string: String, - exchange_name: String, -} - #[derive(Deserialize, Serialize)] struct TomlTlsConfig { cert_path: Option, @@ -568,10 +524,10 @@ pub struct ArgsConfig { #[arg( long, - env = "LDK_SERVER_NODE_REST_SERVICE_ADDRESS", - help = "The rest service address for the LDK Server API." + env = "LDK_SERVER_NODE_LISTEN_ADDRESS", + help = "The listen address for the LDK Server API." )] - node_rest_service_address: Option, + node_grpc_service_address: Option, #[arg( long, @@ -692,7 +648,7 @@ mod tests { network = "regtest" listening_addresses = ["localhost:3001"] announcement_addresses = ["54.3.7.81:3001"] - rest_service_address = "127.0.0.1:3002" + grpc_service_address = "127.0.0.1:3002" alias = "LDK Server" rgs_server_url = "https://rapidsync.lightningdevkit.org/snapshot/v2/" @@ -713,10 +669,6 @@ mod tests { rpc_user = "bitcoind-testuser" rpc_password = "bitcoind-testpassword" - [rabbitmq] - connection_string = "rabbitmq_connection_string" - exchange_name = "rabbitmq_exchange_name" - [liquidity.lsps2_client] node_pubkey = "0217890e3aad8d35bc054f43acc00084b25229ecff0ab68debd82883ad65ee8266" address = "127.0.0.1:39735" @@ -740,7 +692,7 @@ mod tests { node_network: Some(Network::Regtest), node_listening_addresses: Some(vec!["localhost:3008".to_string()]), node_announcement_addresses: Some(vec!["54.3.7.81:3001".to_string()]), - node_rest_service_address: Some(String::from("127.0.0.1:3009")), + node_grpc_service_address: Some(String::from("127.0.0.1:3009")), bitcoind_rpc_address: Some(String::from("127.0.1.9:18443")), bitcoind_rpc_user: Some(String::from("bitcoind-testuser_cli")), bitcoind_rpc_password: Some(String::from("bitcoind-testpassword_cli")), @@ -756,7 +708,7 @@ mod tests { node_network: None, node_listening_addresses: None, node_announcement_addresses: None, - node_rest_service_address: None, + node_grpc_service_address: None, node_alias: None, bitcoind_rpc_address: None, bitcoind_rpc_user: None, @@ -788,19 +740,12 @@ mod tests { let alias = "LDK Server"; - #[cfg(feature = "events-rabbitmq")] - let (expected_rabbit_conn, expected_rabbit_exchange) = - ("rabbitmq_connection_string".to_string(), "rabbitmq_exchange_name".to_string()); - - #[cfg(not(feature = "events-rabbitmq"))] - let (expected_rabbit_conn, expected_rabbit_exchange) = (String::new(), String::new()); - let expected = Config { 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(parse_alias(alias).unwrap()), network: Network::Regtest, - rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(), + grpc_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(), storage_dir_path: Some("/tmp".to_string()), tls_config: Some(TlsConfig { cert_path: Some("/path/to/tls.crt".to_string()), @@ -814,8 +759,6 @@ mod tests { rpc_password: "bitcoind-testpassword".to_string(), }, rgs_server_url: Some("https://rapidsync.lightningdevkit.org/snapshot/v2/".to_string()), - rabbitmq_connection_string: expected_rabbit_conn, - rabbitmq_exchange_name: expected_rabbit_exchange, lsps2_client_config: Some(LSPSClientConfig { node_id: PublicKey::from_str( "0217890e3aad8d35bc054f43acc00084b25229ecff0ab68debd82883ad65ee8266", @@ -845,12 +788,10 @@ mod tests { 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.grpc_service_addr, expected.grpc_service_addr); assert_eq!(config.storage_dir_path, expected.storage_dir_path); assert_eq!(config.chain_source, expected.chain_source); assert_eq!(config.rgs_server_url, expected.rgs_server_url); - assert_eq!(config.rabbitmq_connection_string, expected.rabbitmq_connection_string); - assert_eq!(config.rabbitmq_exchange_name, expected.rabbitmq_exchange_name); assert_eq!(config.lsps2_client_config, expected.lsps2_client_config); #[cfg(feature = "experimental-lsps2-support")] assert_eq!(config.lsps2_service_config.is_some(), expected.lsps2_service_config.is_some()); @@ -865,7 +806,7 @@ mod tests { network = "regtest" listening_addresses = ["localhost:3001"] announcement_addresses = ["54.3.7.81:3001"] - rest_service_address = "127.0.0.1:3002" + grpc_service_address = "127.0.0.1:3002" alias = "LDK Server" pathfinding_scores_source_url = "https://example.com/" @@ -884,10 +825,6 @@ mod tests { [electrum] server_url = "ssl://electrum.blockstream.info:50002" - [rabbitmq] - connection_string = "rabbitmq_connection_string" - exchange_name = "rabbitmq_exchange_name" - [liquidity.lsps2_client] node_pubkey = "0217890e3aad8d35bc054f43acc00084b25229ecff0ab68debd82883ad65ee8266" address = "127.0.0.1:39735" @@ -920,7 +857,7 @@ mod tests { network = "regtest" listening_addresses = ["localhost:3001"] announcement_addresses = ["54.3.7.81:3001"] - rest_service_address = "127.0.0.1:3002" + grpc_service_address = "127.0.0.1:3002" alias = "LDK Server" pathfinding_scores_source_url = "https://example.com/" @@ -941,10 +878,6 @@ mod tests { rpc_user = "bitcoind-testuser" rpc_password = "bitcoind-testpassword" - [rabbitmq] - connection_string = "rabbitmq_connection_string" - exchange_name = "rabbitmq_exchange_name" - [liquidity.lsps2_client] node_pubkey = "0217890e3aad8d35bc054f43acc00084b25229ecff0ab68debd82883ad65ee8266" address = "127.0.0.1:39735" @@ -981,7 +914,7 @@ mod tests { network = "regtest" listening_addresses = ["localhost:3001"] announcement_addresses = ["54.3.7.81:3001"] - rest_service_address = "127.0.0.1:3002" + grpc_service_address = "127.0.0.1:3002" alias = "LDK Server" pathfinding_scores_source_url = "https://example.com/" @@ -1005,10 +938,6 @@ mod tests { [esplora] server_url = "https://mempool.space/api" - [rabbitmq] - connection_string = "rabbitmq_connection_string" - exchange_name = "rabbitmq_exchange_name" - [liquidity.lsps2_client] node_pubkey = "0217890e3aad8d35bc054f43acc00084b25229ecff0ab68debd82883ad65ee8266" address = "127.0.0.1:39735" @@ -1043,17 +972,13 @@ mod tests { let toml_config = r#" [node] network = "regtest" - rest_service_address = "127.0.0.1:3002" + grpc_service_address = "127.0.0.1:3002" [bitcoind] rpc_address = "127.0.0.1:8332" 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 @@ -1100,14 +1025,6 @@ mod tests { ); } - #[cfg(feature = "events-rabbitmq")] - { - validate_missing!( - "[rabbitmq]", - "Both `rabbitmq.connection_string` and `rabbitmq.exchange_name` must be configured if enabling `events-rabbitmq` feature." - ); - } - validate_missing!("rpc_password", missing_field_msg("bitcoind_rpc_password")); validate_missing!("rpc_user", missing_field_msg("bitcoind_rpc_user")); validate_missing!("rpc_address", missing_field_msg("bitcoind_rpc_address")); @@ -1124,7 +1041,6 @@ mod tests { #[test] #[cfg(not(feature = "experimental-lsps2-support"))] - #[cfg(not(feature = "events-rabbitmq"))] fn test_config_from_args_config() { let args_config = default_args_config(); let config = load_config(&args_config).unwrap(); @@ -1141,8 +1057,8 @@ mod tests { ) .unwrap()]), network: Network::Regtest, - rest_service_addr: SocketAddr::from_str( - args_config.node_rest_service_address.as_deref().unwrap(), + grpc_service_addr: SocketAddr::from_str( + args_config.node_grpc_service_address.as_deref().unwrap(), ) .unwrap(), alias: Some(parse_alias(args_config.node_alias.as_deref().unwrap()).unwrap()), @@ -1155,8 +1071,6 @@ mod tests { rpc_password: args_config.bitcoind_rpc_password.unwrap(), }, rgs_server_url: None, - rabbitmq_connection_string: String::new(), - rabbitmq_exchange_name: String::new(), lsps2_client_config: None, lsps2_service_config: None, log_level: LevelFilter::Trace, @@ -1167,19 +1081,16 @@ mod tests { 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); + assert_eq!(config.grpc_service_addr, expected.grpc_service_addr); assert_eq!(config.storage_dir_path, expected.storage_dir_path); assert_eq!(config.chain_source, expected.chain_source); assert_eq!(config.rgs_server_url, expected.rgs_server_url); - assert_eq!(config.rabbitmq_connection_string, expected.rabbitmq_connection_string); - assert_eq!(config.rabbitmq_exchange_name, expected.rabbitmq_exchange_name); assert!(config.lsps2_service_config.is_none()); assert_eq!(config.pathfinding_scores_source_url, expected.pathfinding_scores_source_url); } #[test] #[cfg(not(feature = "experimental-lsps2-support"))] - #[cfg(not(feature = "events-rabbitmq"))] fn test_config_missing_fields_in_args_config() { macro_rules! validate_missing { ($field:ident, $err_msg:expr) => { @@ -1209,13 +1120,6 @@ mod tests { args_config.config_file = Some(storage_path.join(config_file_name).to_string_lossy().to_string()); - #[cfg(feature = "events-rabbitmq")] - let (expected_rabbit_conn, expected_rabbit_exchange) = - ("rabbitmq_connection_string".to_string(), "rabbitmq_exchange_name".to_string()); - - #[cfg(not(feature = "events-rabbitmq"))] - let (expected_rabbit_conn, expected_rabbit_exchange) = (String::new(), String::new()); - let (host, port) = parse_host_port(args_config.bitcoind_rpc_address.clone().unwrap().as_str()).unwrap(); @@ -1230,8 +1134,8 @@ mod tests { ) .unwrap()]), network: Network::Regtest, - rest_service_addr: SocketAddr::from_str( - args_config.node_rest_service_address.as_deref().unwrap(), + grpc_service_addr: SocketAddr::from_str( + args_config.node_grpc_service_address.as_deref().unwrap(), ) .unwrap(), alias: Some(parse_alias(args_config.node_alias.as_deref().unwrap()).unwrap()), @@ -1248,8 +1152,6 @@ mod tests { rpc_password: args_config.bitcoind_rpc_password.unwrap(), }, rgs_server_url: Some("https://rapidsync.lightningdevkit.org/snapshot/v2/".to_string()), - rabbitmq_connection_string: expected_rabbit_conn, - rabbitmq_exchange_name: expected_rabbit_exchange, lsps2_client_config: Some(LSPSClientConfig { node_id: PublicKey::from_str( "0217890e3aad8d35bc054f43acc00084b25229ecff0ab68debd82883ad65ee8266", @@ -1278,28 +1180,16 @@ mod tests { 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); + assert_eq!(config.grpc_service_addr, expected.grpc_service_addr); assert_eq!(config.storage_dir_path, expected.storage_dir_path); assert_eq!(config.chain_source, expected.chain_source); assert_eq!(config.rgs_server_url, expected.rgs_server_url); - assert_eq!(config.rabbitmq_connection_string, expected.rabbitmq_connection_string); - assert_eq!(config.rabbitmq_exchange_name, expected.rabbitmq_exchange_name); assert_eq!(config.lsps2_client_config, expected.lsps2_client_config); #[cfg(feature = "experimental-lsps2-support")] assert_eq!(config.lsps2_service_config.is_some(), expected.lsps2_service_config.is_some()); assert_eq!(config.pathfinding_scores_source_url, expected.pathfinding_scores_source_url); } - #[test] - #[cfg(feature = "events-rabbitmq")] - fn test_error_if_rabbitmq_feature_without_valid_config_file() { - let args_config = empty_args_config(); - let result = load_config(&args_config); - assert!(result.is_err()); - let err = result.unwrap_err(); - assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - } - #[test] #[cfg(feature = "experimental-lsps2-support")] fn test_error_if_lsps2_feature_without_valid_config_file() { @@ -1312,12 +1202,11 @@ mod tests { #[test] #[cfg(not(feature = "experimental-lsps2-support"))] - #[cfg(not(feature = "events-rabbitmq"))] - fn test_default_rest_service_address() { + fn test_default_grpc_service_address() { let storage_path = std::env::temp_dir(); - let config_file_name = "test_default_rest_service_address.toml"; + let config_file_name = "test_default_grpc_service_address.toml"; - // Config without rest_service_address + // Config without grpc_service_address let toml_config = r#" [node] network = "regtest" @@ -1336,8 +1225,8 @@ mod tests { let config = load_config(&args_config).unwrap(); assert_eq!( - config.rest_service_addr, - SocketAddr::from_str(DEFAULT_REST_SERVICE_ADDRESS).unwrap() + config.grpc_service_addr, + SocketAddr::from_str(DEFAULT_GRPC_SERVICE_ADDRESS).unwrap() ); } } diff --git a/ldk-server/src/util/proto_adapter.rs b/ldk-server/src/util/proto_adapter.rs index 77441dfd..7bdca494 100644 --- a/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/src/util/proto_adapter.rs @@ -9,7 +9,6 @@ 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}; @@ -23,7 +22,6 @@ use ldk_node::payment::{ ConfirmationStatus, PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus, }; use ldk_node::{ChannelDetails, LightningBalance, PeerDetails, 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, @@ -40,9 +38,7 @@ use ldk_server_protos::types::{ }; use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::{ - AuthError, InternalServerError, InvalidRequestError, LightningError, -}; +use crate::api::error::LdkServerErrorCode::InvalidRequestError; pub(crate) fn peer_to_proto(peer: PeerDetails) -> Peer { Peer { @@ -518,23 +514,3 @@ pub(crate) fn graph_node_to_proto(node: NodeInfo) -> ldk_server_protos::types::G announcement_info: node.announcement_info.map(graph_node_announcement_to_proto), } } - -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) -} diff --git a/ldk-server/src/util/tls.rs b/ldk-server/src/util/tls.rs index aae5e94a..97998548 100644 --- a/ldk-server/src/util/tls.rs +++ b/ldk-server/src/util/tls.rs @@ -13,8 +13,6 @@ use std::net::IpAddr; use base64::Engine; use ring::rand::SystemRandom; use ring::signature::{EcdsaKeyPair, KeyPair, ECDSA_P256_SHA256_ASN1_SIGNING}; -use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer}; -use tokio_rustls::rustls::ServerConfig; use crate::util::config::TlsConfig; @@ -44,71 +42,41 @@ const TAG_UTC_TIME: u8 = 0x17; const TAG_SEQUENCE: u8 = 0x30; const TAG_SET: u8 = 0x31; -/// Gets or generates TLS configuration. If custom paths are provided, uses those. +/// TLS certificate and key PEM data. +pub struct TlsPem { + pub cert_pem: String, + pub key_pem: String, +} + +/// Gets or generates TLS certificate/key PEM files. If custom paths are provided, uses those. /// Otherwise, generates a self-signed certificate in the storage directory. -pub fn get_or_generate_tls_config( +/// Returns the PEM-encoded certificate and key. +pub fn get_or_generate_tls_pem( tls_config: Option, storage_dir: &str, -) -> Result { - if let Some(config) = tls_config { +) -> Result { + let (cert_path, key_path, hosts) = 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) + (cert_path, key_path, config.hosts) } 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(); + (cert_path, key_path, vec![]) + }; - 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)); - } + if !fs::exists(&cert_path).unwrap_or(false) || !fs::exists(&key_path).unwrap_or(false) { + generate_self_signed_cert(&cert_path, &key_path, &hosts)?; } - 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}"))?; + 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}"))?; - Ok(PrivateKeyDer::Pkcs8(der.into())) + Ok(TlsPem { cert_pem, key_pem }) } /// 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> { @@ -392,76 +360,12 @@ fn der_context_implicit(tag_num: u8, content: &[u8]) -> Vec { der_tag_length_value(0x80 | tag_num, content) } -/// 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() { + fn test_generate_roundtrip() { let temp_dir = std::env::temp_dir(); let mut suffix_bytes = [0u8; 8]; getrandom::getrandom(&mut suffix_bytes).unwrap(); @@ -469,23 +373,27 @@ mod tests { 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()); + let cert_pem = fs::read_to_string(&cert_path).unwrap(); + let key_pem = fs::read_to_string(&key_path).unwrap(); + assert!(cert_pem.contains(PEM_CERT_BEGIN)); + assert!(key_pem.contains(PEM_KEY_BEGIN)); + + // Verify the generated cert/key can be loaded as a valid TLS identity + let identity = tonic::transport::Identity::from_pem(&cert_pem, &key_pem); + let tls_config = tonic::transport::ServerTlsConfig::new().identity(identity); + tonic::transport::Server::builder() + .tls_config(tls_config) + .expect("Generated cert/key should produce a valid TLS config"); - // Clean up let _ = fs::remove_file(&cert_path); let _ = fs::remove_file(&key_path); }