diff --git a/.github/workflows/check-protos.yml b/.github/workflows/check-protos.yml deleted file mode 100644 index 629bc0bb..00000000 --- a/.github/workflows/check-protos.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Check Generated Protos - -on: - push: - paths: - - 'ldk-server-protos/**' - pull_request: - paths: - - 'ldk-server-protos/**' - workflow_dispatch: - -jobs: - check-protos: - runs-on: ubuntu-latest - steps: - - name: Checkout source code - uses: actions/checkout@v3 - - 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: Generate protos - run: RUSTFLAGS="--cfg genproto" cargo build -p ldk-server-protos - - name: Format generated code - run: rustup component add rustfmt && cargo fmt --all - - name: Check for differences - run: | - if ! git diff --exit-code; then - echo "error: Generated protobuf files are out of date. Run: RUSTFLAGS=\"--cfg genproto\" cargo build -p ldk-server-protos && cargo fmt --all" - exit 1 - fi diff --git a/.github/workflows/integration-tests-events-rabbitmq.yml b/.github/workflows/integration-tests.yml similarity index 67% rename from .github/workflows/integration-tests-events-rabbitmq.yml rename to .github/workflows/integration-tests.yml index 6caeb4a0..6f8ae819 100644 --- a/.github/workflows/integration-tests-events-rabbitmq.yml +++ b/.github/workflows/integration-tests.yml @@ -10,20 +10,6 @@ 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 @@ -45,11 +31,6 @@ jobs: - 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: diff --git a/CLAUDE.md b/CLAUDE.md index aa1da645..f4bd6434 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,7 +9,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for build commands, testing, code style, - **ldk-server** - Main daemon server (entry point: `src/main.rs`) - **ldk-server-cli** - CLI client using clap - **ldk-server-client** - Reqwest-based client library -- **ldk-server-protos** - Protocol buffer definitions and generated Rust code +- **ldk-server-json-models** - Shared JSON request/response types with serde ## Development Rules diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9a783dfb..76fae4fd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,18 +37,11 @@ cargo clippy --all-features -- -D warnings -A clippy::drop_non_drop # Lint (CI - Hard tabs, max width 100 chars - Imports grouped: std, external crates, local crates -## Protocol Buffer Generation - -```bash -RUSTFLAGS="--cfg genproto" cargo build -p ldk-server-protos -cargo fmt --all -``` - ## Adding a New API Endpoint -1. Define request/response messages in `ldk-server-protos/src/proto/api.proto` -2. Regenerate protos (see above) -3. Create handler in `ldk-server/src/api/` (follow existing patterns) +1. Define request/response types in `ldk-server-json-models/src/api.rs` +2. Create handler in `ldk-server/src/api/` (follow existing patterns) +3. Add endpoint constant in `ldk-server-json-models/src/endpoints.rs` 4. Add route in `ldk-server/src/service.rs` 5. Add CLI command in `ldk-server-cli/src/main.rs` diff --git a/Cargo.lock b/Cargo.lock index 99a74a7d..1465cc47 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,171 +51,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] -name = "asn1-rs" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" -dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror", - "time", -] - -[[package]] -name = "asn1-rs-derive" -version = "0.6.0" +name = "async-stream" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", - "synstructure", + "async-stream-impl", + "futures-core", + "pin-project-lite", ] [[package]] -name = "asn1-rs-impl" -version = "0.2.0" +name = "async-stream-impl" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", "syn 2.0.108", ] -[[package]] -name = "async-channel" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand 2.3.0", - "futures-lite 2.6.1", - "pin-project-lite", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f937e26114b93193065fd44f507aa2e9169ad0cdabbb996920b1fe1ddea7ba" -dependencies = [ - "async-channel", - "async-executor", - "async-io 2.6.0", - "async-lock 3.4.1", - "blocking", - "futures-lite 2.6.1", -] - -[[package]] -name = "async-global-executor-trait" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af57045d58eeb1f7060e7025a1631cbc6399e0a1d10ad6735b3d0ea7f8346ce" -dependencies = [ - "async-global-executor", - "async-trait", - "executor-trait", -] - -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.28", - "slab", - "socket2 0.4.10", - "waker-fn", -] - -[[package]] -name = "async-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" -dependencies = [ - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite 2.6.1", - "parking", - "polling 3.11.0", - "rustix 1.1.2", - "slab", - "windows-sys 0.61.2", -] - -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - -[[package]] -name = "async-lock" -version = "3.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" -dependencies = [ - "event-listener 5.4.1", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-reactor-trait" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6012d170ad00de56c9ee354aef2e358359deb1ec504254e0e5a3774771de0e" -dependencies = [ - "async-io 1.13.0", - "async-trait", - "futures-core", - "reactor-trait", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - [[package]] name = "async-trait" version = "0.1.89" @@ -320,12 +117,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" @@ -525,37 +316,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" @@ -573,18 +333,6 @@ name = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" -dependencies = [ - "serde", -] - -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher", -] [[package]] name = "cc" @@ -626,16 +374,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" @@ -684,39 +422,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" -[[package]] -name = "cms" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b77c319abfd5219629c45c34c89ba945ed3c5e49fcde9d16b6c3885f118a730" -dependencies = [ - "const-oid", - "der", - "spki", - "x509-cert", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "cookie-factory" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" - [[package]] name = "core-foundation" version = "0.9.4" @@ -733,104 +438,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "data-encoding" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" - -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "der_derive", - "flagset", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "der-parser" -version = "10.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" -dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", -] - -[[package]] -name = "der_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "deranged" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "des" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" -dependencies = [ - "cipher", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - [[package]] name = "displaydoc" version = "0.2.5" @@ -852,12 +459,6 @@ dependencies = [ "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" @@ -920,42 +521,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "5.4.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" @@ -968,15 +533,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" @@ -995,23 +551,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 +614,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 +655,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" @@ -1243,24 +744,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 +765,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" @@ -1603,36 +1077,8 @@ checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown 0.16.0", -] - -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "block-padding", - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", + "serde", + "serde_core", ] [[package]] @@ -1676,28 +1122,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" @@ -1751,28 +1175,25 @@ 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", + "ldk-server-json-models", "log", - "prost", "ring", "rusqlite", "serde", + "serde_json", "tokio", "tokio-rustls 0.26.4", "toml", + "utoipa", ] [[package]] @@ -1781,6 +1202,7 @@ version = "0.1.0" dependencies = [ "clap", "clap_complete", + "futures-util", "hex-conservative 0.2.1", "ldk-server-client", "serde", @@ -1793,20 +1215,21 @@ dependencies = [ name = "ldk-server-client" version = "0.1.0" dependencies = [ + "async-stream", "bitcoin_hashes 0.14.0", - "ldk-server-protos", - "prost", + "futures-util", + "ldk-server-json-models", "reqwest 0.11.27", + "serde", + "serde_json", ] [[package]] -name = "ldk-server-protos" +name = "ldk-server-json-models" version = "0.1.0" dependencies = [ - "bytes", - "prost", - "prost-build", "serde", + "utoipa", ] [[package]] @@ -1964,12 +1387,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 +1405,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" @@ -2021,12 +1429,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" @@ -2060,143 +1462,23 @@ name = "musig2" version = "0.1.0" source = "git+https://github.com/arik-so/rust-musig2?rev=6f95a05718cbb44d8fe3fa6021aea8117aa38d50#6f95a05718cbb44d8fe3fa6021aea8117aa38d50" dependencies = [ - "bitcoin", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "oid-registry" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" -dependencies = [ - "asn1-rs", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "p12-keystore" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cae83056e7cb770211494a0ecf66d9fa7eba7d00977e5bb91f0e925b40b937f" -dependencies = [ - "cbc", - "cms", - "der", - "des", - "hex", - "hmac", - "pkcs12", - "pkcs5", - "rand 0.9.2", - "rc2", - "sha1", - "sha2", - "thiserror", - "x509-parser", -] - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", + "bitcoin", ] [[package]] -name = "pbkdf2" -version = "0.12.2" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "digest", - "hmac", + "autocfg", ] [[package]] -name = "pem-rfc7468" -version = "0.7.0" +name = "once_cell" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "percent-encoding" @@ -2232,95 +1514,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pinky-swear" -version = "6.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1ea6e230dd3a64d61bcb8b79e597d3ab6b4c94ec7a234ce687dd718b4f2e657" -dependencies = [ - "doc-comment", - "flume", - "parking_lot", - "tracing", -] - -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand 2.3.0", - "futures-io", -] - -[[package]] -name = "pkcs12" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "695b3df3d3cc1015f12d70235e35b6b79befc5fa7a9b95b951eab1dd07c9efc2" -dependencies = [ - "cms", - "const-oid", - "der", - "digest", - "spki", - "x509-cert", - "zeroize", -] - -[[package]] -name = "pkcs5" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" -dependencies = [ - "aes", - "cbc", - "der", - "pbkdf2", - "scrypt", - "sha2", - "spki", -] - [[package]] name = "pkg-config" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - -[[package]] -name = "polling" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.5.2", - "pin-project-lite", - "rustix 1.1.2", - "windows-sys 0.61.2", -] - [[package]] name = "possiblyrandom" version = "0.2.0" @@ -2338,12 +1537,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" @@ -2555,35 +1748,6 @@ 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" @@ -2637,7 +1801,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls 0.21.12", - "rustls-pemfile 1.0.4", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", @@ -2645,10 +1809,12 @@ dependencies = [ "system-configuration", "tokio", "tokio-rustls 0.24.1", + "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", "webpki-roots 0.25.4", "winreg", @@ -2726,29 +1892,6 @@ 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" @@ -2802,32 +1945,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" @@ -2837,15 +1954,6 @@ dependencies = [ "base64 0.21.7", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" version = "1.13.0" @@ -2889,41 +1997,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 +2028,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 +2092,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 +2119,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 +2139,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" @@ -3227,25 +2226,13 @@ dependencies = [ "libc", ] -[[package]] -name = "tcp-stream" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495b0abdce3dc1f8fd27240651c9e68890c14e9d9c61527b1ce44d8a5a7bd3d5" -dependencies = [ - "cfg-if", - "p12-keystore", - "rustls-connector", - "rustls-pemfile 2.2.0", -] - [[package]] name = "tempfile" version = "3.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 +2259,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" @@ -3492,12 +2448,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" @@ -3537,6 +2487,29 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utoipa" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fcc29c80c21c31608227e0912b2d7fddba57ad76b606890627ba8ee7964e993" +dependencies = [ + "indexmap", + "serde", + "serde_json", + "utoipa-gen", +] + +[[package]] +name = "utoipa-gen" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d79d08d92ab8af4c5e8a6da20c47ae3f61a0f1dabc1997cdf2d082b757ca08b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.108", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -3570,12 +2543,6 @@ dependencies = [ "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" @@ -3658,6 +2625,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.82" @@ -4048,34 +3028,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/Cargo.toml b/Cargo.toml index 2a8c8b9b..aaa6637f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["ldk-server-cli", "ldk-server-client", "ldk-server-protos", "ldk-server"] +members = ["ldk-server-cli", "ldk-server-client", "ldk-server-json-models", "ldk-server"] exclude = ["e2e-tests"] [profile.release] diff --git a/README.md b/README.md index f14d2881..04ddfc34 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ The primary goal of LDK Server is to provide an efficient, stable, and API-first solution for deploying and managing a Lightning Network node. With its streamlined setup, LDK Server enables users to easily set up, configure, and run -a Lightning node while exposing a robust, language-agnostic API via [Protocol Buffers (Protobuf)](https://protobuf.dev/). +a Lightning node while exposing a robust, language-agnostic REST API with JSON. ### Features @@ -15,7 +15,7 @@ a Lightning node while exposing a robust, language-agnostic API via [Protocol Bu - Deploy a Lightning Network node with minimal configuration, no coding required. - **API-First Design**: - - Exposes a well-defined API using Protobuf, allowing seamless integration with HTTP-clients or applications. + - Exposes a well-defined JSON REST API, allowing seamless integration with HTTP-clients or applications. - **Powered by LDK**: - Built on top of LDK-Node, leveraging the modular, reliable, and high-performance architecture of LDK. diff --git a/e2e-tests/Cargo.lock b/e2e-tests/Cargo.lock index 13326fd6..5e64bda9 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,171 +51,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] -name = "asn1-rs" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" -dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror", - "time", -] - -[[package]] -name = "asn1-rs-derive" -version = "0.6.0" +name = "async-stream" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.116", - "synstructure", + "async-stream-impl", + "futures-core", + "pin-project-lite", ] [[package]] -name = "asn1-rs-impl" -version = "0.2.0" +name = "async-stream-impl" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", "syn 2.0.116", ] -[[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" -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", -] - -[[package]] -name = "async-global-executor" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f937e26114b93193065fd44f507aa2e9169ad0cdabbb996920b1fe1ddea7ba" -dependencies = [ - "async-channel", - "async-executor", - "async-io 2.6.0", - "async-lock 3.4.2", - "blocking", - "futures-lite 2.6.1", -] - -[[package]] -name = "async-global-executor-trait" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af57045d58eeb1f7060e7025a1631cbc6399e0a1d10ad6735b3d0ea7f8346ce" -dependencies = [ - "async-global-executor", - "async-trait", - "executor-trait", -] - -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.28", - "slab", - "socket2 0.4.10", - "waker-fn", -] - -[[package]] -name = "async-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" -dependencies = [ - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite 2.6.1", - "parking", - "polling 3.11.0", - "rustix 1.1.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", - "pin-project-lite", -] - -[[package]] -name = "async-reactor-trait" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6012d170ad00de56c9ee354aef2e358359deb1ec504254e0e5a3774771de0e" -dependencies = [ - "async-io 1.13.0", - "async-trait", - "futures-core", - "reactor-trait", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - [[package]] name = "async-trait" version = "0.1.89" @@ -326,12 +123,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" @@ -500,37 +291,6 @@ 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" @@ -548,9 +308,6 @@ name = "bytes" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" -dependencies = [ - "serde", -] [[package]] name = "bzip2" @@ -572,15 +329,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,49 +375,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" @@ -730,15 +435,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" @@ -754,89 +450,6 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "der_derive", - "flagset", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "der-parser" -version = "10.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" -dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", -] - -[[package]] -name = "der_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.116", -] - -[[package]] -name = "deranged" -version = "0.5.6" -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" @@ -858,24 +471,15 @@ dependencies = [ "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", + "ldk-server-json-models", "serde_json", "tempfile", "tokio", @@ -944,42 +548,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "5.4.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 +560,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 +589,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 +599,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 +668,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 +708,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" @@ -1315,24 +819,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 +834,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" @@ -1526,7 +1003,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.2", "tokio", "tower-service", "tracing", @@ -1676,36 +1153,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 +1206,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" @@ -1833,19 +1258,19 @@ dependencies = [ name = "ldk-server-client" version = "0.1.0" dependencies = [ + "async-stream", "bitcoin_hashes", - "ldk-server-protos", - "prost", + "futures-util", + "ldk-server-json-models", "reqwest 0.11.27", + "serde", + "serde_json", ] [[package]] -name = "ldk-server-protos" +name = "ldk-server-json-models" version = "0.1.0" dependencies = [ - "bytes", - "prost", - "prost-build", "serde", ] @@ -1875,7 +1300,7 @@ checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ "bitflags 2.11.0", "libc", - "redox_syscall 0.7.1", + "redox_syscall", ] [[package]] @@ -2021,12 +1446,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 +1464,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" @@ -2078,12 +1488,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" @@ -2133,150 +1537,30 @@ dependencies = [ name = "multimap" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "musig2" -version = "0.1.0" -source = "git+https://github.com/arik-so/rust-musig2?rev=6f95a05718cbb44d8fe3fa6021aea8117aa38d50#6f95a05718cbb44d8fe3fa6021aea8117aa38d50" -dependencies = [ - "bitcoin", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "oid-registry" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" -dependencies = [ - "asn1-rs", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "p12-keystore" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cae83056e7cb770211494a0ecf66d9fa7eba7d00977e5bb91f0e925b40b937f" -dependencies = [ - "cbc", - "cms", - "der", - "des", - "hex", - "hmac", - "pkcs12", - "pkcs5", - "rand 0.9.2", - "rc2", - "sha1", - "sha2", - "thiserror", - "x509-parser", -] - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +name = "musig2" +version = "0.1.0" +source = "git+https://github.com/arik-so/rust-musig2?rev=6f95a05718cbb44d8fe3fa6021aea8117aa38d50#6f95a05718cbb44d8fe3fa6021aea8117aa38d50" dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.5.18", - "smallvec", - "windows-link", + "bitcoin", ] [[package]] -name = "pbkdf2" -version = "0.12.2" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "digest", - "hmac", + "autocfg", ] [[package]] -name = "pem-rfc7468" -version = "0.7.0" +name = "once_cell" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "percent-encoding" @@ -2312,95 +1596,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pinky-swear" -version = "6.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1ea6e230dd3a64d61bcb8b79e597d3ab6b4c94ec7a234ce687dd718b4f2e657" -dependencies = [ - "doc-comment", - "flume", - "parking_lot", - "tracing", -] - -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand 2.3.0", - "futures-io", -] - -[[package]] -name = "pkcs12" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "695b3df3d3cc1015f12d70235e35b6b79befc5fa7a9b95b951eab1dd07c9efc2" -dependencies = [ - "cms", - "const-oid", - "der", - "digest", - "spki", - "x509-cert", - "zeroize", -] - -[[package]] -name = "pkcs5" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" -dependencies = [ - "aes", - "cbc", - "der", - "pbkdf2", - "scrypt", - "sha2", - "spki", -] - [[package]] name = "pkg-config" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - -[[package]] -name = "polling" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.5.2", - "pin-project-lite", - "rustix 1.1.3", - "windows-sys 0.61.2", -] - [[package]] name = "possiblyrandom" version = "0.2.0" @@ -2418,12 +1619,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" @@ -2529,7 +1724,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls 0.23.36", - "socket2 0.5.10", + "socket2 0.6.2", "thiserror", "tokio", "tracing", @@ -2566,9 +1761,9 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2 0.6.2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -2645,35 +1840,6 @@ 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" @@ -2736,7 +1902,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls 0.21.12", - "rustls-pemfile 1.0.4", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", @@ -2744,10 +1910,12 @@ dependencies = [ "system-configuration", "tokio", "tokio-rustls 0.24.1", + "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", "webpki-roots 0.25.4", "winreg", @@ -2827,29 +1995,6 @@ 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" @@ -2903,32 +2048,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" @@ -2938,15 +2057,6 @@ dependencies = [ "base64 0.21.7", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" version = "1.14.0" @@ -2990,41 +2100,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 +2131,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 +2192,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 +2216,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 +2236,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" @@ -3327,25 +2328,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 +2361,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" @@ -3557,12 +2515,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" @@ -3642,12 +2594,6 @@ dependencies = [ "url", ] -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - [[package]] name = "want" version = "0.3.1" @@ -3762,6 +2708,19 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wasmparser" version = "0.244.0" @@ -4246,34 +3205,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..81755335 100644 --- a/e2e-tests/Cargo.toml +++ b/e2e-tests/Cargo.toml @@ -8,10 +8,7 @@ corepc-node = { version = "0.10", features = ["download", "29_0"] } tempfile = "3" tokio = { version = "1.38.0", features = ["rt-multi-thread", "macros", "time"] } ldk-server-client = { path = "../ldk-server-client" } -ldk-server-protos = { path = "../ldk-server-protos", features = ["serde"] } +ldk-server-json-models = { path = "../ldk-server-json-models" } 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" 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..3902586d 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", ]) @@ -45,6 +45,6 @@ fn main() { println!("cargo:rerun-if-changed=../ldk-server/Cargo.toml"); println!("cargo:rerun-if-changed=../ldk-server-cli/src"); println!("cargo:rerun-if-changed=../ldk-server-cli/Cargo.toml"); - println!("cargo:rerun-if-changed=../ldk-server-protos/src"); - println!("cargo:rerun-if-changed=../ldk-server-protos/Cargo.toml"); + println!("cargo:rerun-if-changed=../ldk-server-json-models/src"); + println!("cargo:rerun-if-changed=../ldk-server-json-models/Cargo.toml"); } diff --git a/e2e-tests/src/lib.rs b/e2e-tests/src/lib.rs index 083c08e7..44ae7202 100644 --- a/e2e-tests/src/lib.rs +++ b/e2e-tests/src/lib.rs @@ -16,9 +16,9 @@ use std::time::Duration; use corepc_node::Node; use hex_conservative::DisplayHex; use ldk_server_client::client::LdkServerClient; -use ldk_server_client::ldk_server_protos::api::{GetNodeInfoRequest, GetNodeInfoResponse}; -use ldk_server_protos::api::{ - GetBalancesRequest, ListChannelsRequest, OnchainReceiveRequest, OpenChannelRequest, +use ldk_server_json_models::api::{ + GetBalancesRequest, GetNodeInfoRequest, GetNodeInfoResponse, ListChannelsRequest, + OnchainReceiveRequest, OpenChannelRequest, }; /// Wrapper around a managed bitcoind process for regtest. @@ -92,8 +92,7 @@ pub struct LdkServerHandle { pub storage_dir: PathBuf, pub api_key: String, pub tls_cert_path: PathBuf, - pub node_id: String, - pub exchange_name: String, + pub node_id: [u8; 33], client: LdkServerClient, } @@ -109,8 +108,6 @@ impl LdkServerHandle { 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" @@ -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 @@ -201,8 +194,7 @@ client_trusts_lsp = true storage_dir, api_key, tls_cert_path, - node_id: String::new(), - exchange_name, + node_id: [0u8; 33], client, }; @@ -217,7 +209,7 @@ client_trusts_lsp = true &self.client } - pub fn node_id(&self) -> &str { + pub fn node_id(&self) -> &[u8; 33] { &self.node_id } @@ -325,16 +317,14 @@ pub async fn mine_and_sync( let start = std::time::Instant::now(); loop { if let Ok(info) = client.get_node_info(GetNodeInfoRequest {}).await { - if info.current_best_block.as_ref().map(|b| b.height).unwrap_or(0) - >= expected_height as u32 - { + if info.current_best_block.height >= expected_height as u32 { break; } } if start.elapsed() > timeout { panic!( "Timed out waiting for server {} to sync to height {}", - server.node_id(), + server.node_id().to_lower_hex_string(), expected_height ); } @@ -409,7 +399,7 @@ pub async fn setup_funded_channel( let open_resp = server_a .client() .open_channel(OpenChannelRequest { - node_pubkey: server_b.node_id().to_string(), + node_pubkey: *server_b.node_id(), address: format!("127.0.0.1:{}", server_b.p2p_port), channel_amount_sats, push_to_counterparty_msat: None, @@ -428,100 +418,72 @@ 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, +/// Event consumer that spawns `ldk-server-cli subscribe` and reads JSON events from stdout. +pub struct CliEventConsumer { + receiver: tokio::sync::mpsc::Receiver, + child: Option, } -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}; +impl CliEventConsumer { + /// Start the CLI subscribe command and begin receiving events in the background. + pub fn new(server: &LdkServerHandle) -> Self { + let cli_path = cli_binary_path(); + let mut child = Command::new(&cli_path) + .arg("--base-url") + .arg(server.base_url()) + .arg("--api-key") + .arg(&server.api_key) + .arg("--tls-cert") + .arg(server.tls_cert_path.to_str().unwrap()) + .arg("subscribe") + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .unwrap_or_else(|e| panic!("Failed to start CLI subscribe at {:?}: {}", cli_path, e)); - 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 } + let stdout = child.stdout.take().unwrap(); + let (tx, rx) = tokio::sync::mpsc::channel(64); + + std::thread::spawn(move || { + let reader = BufReader::new(stdout); + for line in reader.lines().map_while(Result::ok) { + let trimmed = line.trim(); + if trimmed.is_empty() { + continue; + } + if let Ok(event) = + serde_json::from_str::(trimmed) + { + if tx.blocking_send(event).is_err() { + break; + } + } + } + }); + + Self { receiver: rx, child: Some(child) } } /// 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; - + ) -> Vec { 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"); - events.push(event); - }, + match tokio::time::timeout(timeout, self.receiver.recv()).await { + Ok(Some(event)) => events.push(event), _ => break, } } events } } + +impl Drop for CliEventConsumer { + fn drop(&mut self) { + if let Some(mut child) = self.child.take() { + let _ = child.kill(); + let _ = child.wait(); + } + } +} diff --git a/e2e-tests/tests/e2e.rs b/e2e-tests/tests/e2e.rs index 577b74c1..6409c40e 100644 --- a/e2e-tests/tests/e2e.rs +++ b/e2e-tests/tests/e2e.rs @@ -12,20 +12,20 @@ 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, LdkServerHandle, CliEventConsumer, TestBitcoind, }; use hex_conservative::{DisplayHex, FromHex}; use ldk_node::bitcoin::hashes::{sha256, Hash}; +use ldk_node::bitcoin::secp256k1::PublicKey; +use ldk_node::bitcoin::Network; use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_node::lightning::offers::offer::Offer; use ldk_node::lightning_invoice::Bolt11Invoice; -use ldk_server_client::ldk_server_protos::api::{ +use ldk_server_json_models::api::{ Bolt11ReceiveRequest, Bolt12ReceiveRequest, OnchainReceiveRequest, }; -use ldk_server_client::ldk_server_protos::types::{ - bolt11_invoice_description, Bolt11InvoiceDescription, -}; -use ldk_server_protos::events::event_envelope::Event; +use ldk_server_json_models::events::Event; +use ldk_server_json_models::types::Bolt11InvoiceDescription; #[tokio::test] async fn test_cli_get_node_info() { @@ -33,8 +33,13 @@ async fn test_cli_get_node_info() { let server = LdkServerHandle::start(&bitcoind).await; let output = run_cli(&server, &["get-node-info"]); - assert!(output.get("node_id").is_some()); - assert_eq!(output["node_id"], server.node_id()); + assert_eq!(output["node_id"], server.node_id().to_lower_hex_string()); + + // Verify block hash is a parseable 32-byte value and height is nonzero + let block_hash_hex = output["current_best_block"]["block_hash"].as_str().unwrap(); + assert_eq!(block_hash_hex.len(), 64); + <[u8; 32]>::from_hex(block_hash_hex).expect("block_hash should be valid 32-byte hex"); + assert!(output["current_best_block"]["height"].as_u64().unwrap() > 0); } #[tokio::test] @@ -102,7 +107,8 @@ async fn test_cli_verify_signature() { let sign_output = run_cli(&server, &["sign-message", "hello"]); let signature = sign_output["signature"].as_str().unwrap(); - let output = run_cli(&server, &["verify-signature", "hello", signature, server.node_id()]); + let node_id_hex = server.node_id().to_lower_hex_string(); + let output = run_cli(&server, &["verify-signature", "hello", signature, &node_id_hex]); assert_eq!(output["valid"], true); } @@ -118,9 +124,7 @@ async fn test_cli_export_pathfinding_scores() { .client() .bolt11_receive(Bolt11ReceiveRequest { amount_msat: Some(10_000_000), - description: Some(Bolt11InvoiceDescription { - kind: Some(bolt11_invoice_description::Kind::Direct("test".to_string())), - }), + description: Some(Bolt11InvoiceDescription::Direct("test".to_string())), expiry_secs: 3600, }) .await @@ -142,10 +146,18 @@ async fn test_cli_bolt11_receive() { assert!(invoice_str.starts_with("lnbcrt"), "Expected lnbcrt prefix, got: {}", invoice_str); let invoice: Bolt11Invoice = invoice_str.parse().unwrap(); - let payment_hash = sha256::Hash::from_str(output["payment_hash"].as_str().unwrap()).unwrap(); - assert_eq!(*invoice.payment_hash(), payment_hash); - let payment_secret = <[u8; 32]>::from_hex(output["payment_secret"].as_str().unwrap()).unwrap(); - assert_eq!(invoice.payment_secret().0, payment_secret); + + // Cross-check payment_hash bytes: API response vs parsed invoice + let api_hash = <[u8; 32]>::from_hex(output["payment_hash"].as_str().unwrap()).unwrap(); + assert_eq!( + api_hash, + *invoice.payment_hash().as_byte_array(), + "payment_hash bytes should match invoice" + ); + + // Cross-check payment_secret bytes: API response vs parsed invoice + let api_secret = <[u8; 32]>::from_hex(output["payment_secret"].as_str().unwrap()).unwrap(); + assert_eq!(api_secret, invoice.payment_secret().0, "payment_secret bytes should match invoice"); } #[tokio::test] @@ -181,7 +193,9 @@ async fn test_cli_onchain_send() { let dest_addr = recv_output["address"].as_str().unwrap(); let output = run_cli(&server, &["onchain-send", dest_addr, "50000sat"]); - assert!(!output["txid"].as_str().unwrap().is_empty()); + let txid_hex = output["txid"].as_str().unwrap(); + assert_eq!(txid_hex.len(), 64); + <[u8; 32]>::from_hex(txid_hex).expect("txid should be valid 32-byte hex"); } #[tokio::test] @@ -191,7 +205,8 @@ async fn test_cli_connect_peer() { let server_b = LdkServerHandle::start(&bitcoind).await; let addr = format!("127.0.0.1:{}", server_b.p2p_port); - let output = run_cli(&server_a, &["connect-peer", server_b.node_id(), &addr]); + let node_id_hex = server_b.node_id().to_lower_hex_string(); + let output = run_cli(&server_a, &["connect-peer", &node_id_hex, &addr]); // ConnectPeerResponse is empty assert!(output.is_object()); } @@ -208,12 +223,13 @@ async fn test_cli_list_peers() { assert!(output["peers"].as_array().unwrap().is_empty()); let addr = format!("127.0.0.1:{}", server_b.p2p_port); - run_cli(&server_a, &["connect-peer", server_b.node_id(), &addr]); + let node_id_hex = server_b.node_id().to_lower_hex_string(); + run_cli(&server_a, &["connect-peer", &node_id_hex, &addr]); let output = run_cli(&server_a, &["list-peers"]); let peers = output["peers"].as_array().unwrap(); assert_eq!(peers.len(), 1); - assert_eq!(peers[0]["node_id"], server_b.node_id()); + assert_eq!(peers[0]["node_id"], node_id_hex); assert_eq!(peers[0]["address"], addr); assert_eq!(peers[0]["is_persisted"], false); assert_eq!(peers[0]["is_connected"], true); @@ -238,9 +254,10 @@ async fn test_cli_open_channel() { // Open channel via CLI let addr = format!("127.0.0.1:{}", server_b.p2p_port); + let node_id_hex = server_b.node_id().to_lower_hex_string(); let output = run_cli( &server_a, - &["open-channel", server_b.node_id(), &addr, "100000sat", "--announce-channel"], + &["open-channel", &node_id_hex, &addr, "100000sat", "--announce-channel"], ); assert!(!output["user_channel_id"].as_str().unwrap().is_empty()); } @@ -255,7 +272,32 @@ async fn test_cli_list_channels() { let output = run_cli(&server_a, &["list-channels"]); let channels = output["channels"].as_array().unwrap(); assert!(!channels.is_empty()); - assert_eq!(channels[0]["counterparty_node_id"], server_b.node_id()); + + let ch = &channels[0]; + // Verify counterparty_node_id is server_b's actual pubkey + let cp_id = <[u8; 33]>::from_hex(ch["counterparty_node_id"].as_str().unwrap()).unwrap(); + assert_eq!(cp_id, *server_b.node_id(), "counterparty should be server_b"); + + // Verify channel_id is a valid 32-byte value + let channel_id = <[u8; 32]>::from_hex(ch["channel_id"].as_str().unwrap()).unwrap(); + assert_ne!(channel_id, [0u8; 32], "channel_id should not be all zeros"); + + // Verify funding txo has a valid txid + let funding_txid_hex = ch["funding_txo"]["txid"].as_str().unwrap(); + assert_eq!(funding_txid_hex.len(), 64); + <[u8; 32]>::from_hex(funding_txid_hex).expect("funding txid should be valid 32-byte hex"); + + // Both sides should see the same channel — cross-check from server_b + let output_b = run_cli(&server_b, &["list-channels"]); + let channels_b = output_b["channels"].as_array().unwrap(); + assert!(!channels_b.is_empty()); + let ch_b = &channels_b[0]; + let cp_id_b = <[u8; 33]>::from_hex(ch_b["counterparty_node_id"].as_str().unwrap()).unwrap(); + assert_eq!(cp_id_b, *server_a.node_id(), "server_b's counterparty should be server_a"); + assert_eq!( + ch_b["funding_txo"]["txid"], ch["funding_txo"]["txid"], + "both sides should report same funding txid" + ); } #[tokio::test] @@ -265,12 +307,13 @@ async fn test_cli_update_channel_config() { let server_b = LdkServerHandle::start(&bitcoind).await; let user_channel_id = setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await; + let node_id_hex = server_b.node_id().to_lower_hex_string(); let output = run_cli( &server_a, &[ "update-channel-config", &user_channel_id, - server_b.node_id(), + &node_id_hex, "--forwarding-fee-base-msat", "100", ], @@ -285,8 +328,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 = CliEventConsumer::new(&server_a); + let mut consumer_b = CliEventConsumer::new(&server_b); setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await; @@ -295,9 +338,7 @@ async fn test_cli_bolt11_send() { .client() .bolt11_receive(Bolt11ReceiveRequest { amount_msat: Some(10_000_000), - description: Some(Bolt11InvoiceDescription { - kind: Some(bolt11_invoice_description::Kind::Direct("test".to_string())), - }), + description: Some(Bolt11InvoiceDescription::Direct("test".to_string())), expiry_secs: 3600, }) .await @@ -312,13 +353,13 @@ async fn test_cli_bolt11_send() { let events_a = consumer_a.consume_events(5, Duration::from_secs(10)).await; assert!( - events_a.iter().any(|e| matches!(&e.event, Some(Event::PaymentSuccessful(_)))), + events_a.iter().any(|e| matches!(e, Event::PaymentSuccessful(_))), "Expected PaymentSuccessful on sender" ); let events_b = consumer_b.consume_events(5, Duration::from_secs(10)).await; assert!( - events_b.iter().any(|e| matches!(&e.event, Some(Event::PaymentReceived(_)))), + events_b.iter().any(|e| matches!(e, Event::PaymentReceived(_))), "Expected PaymentReceived on receiver" ); } @@ -335,9 +376,7 @@ async fn test_cli_pay() { .client() .bolt11_receive(Bolt11ReceiveRequest { amount_msat: Some(10_000_000), - description: Some(Bolt11InvoiceDescription { - kind: Some(bolt11_invoice_description::Kind::Direct("test".to_string())), - }), + description: Some(Bolt11InvoiceDescription::Direct("test".to_string())), expiry_secs: 3600, }) .await @@ -390,12 +429,13 @@ 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 = CliEventConsumer::new(&server_a); + let mut consumer_b = CliEventConsumer::new(&server_b); setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await; - let output = run_cli(&server_a, &["spontaneous-send", server_b.node_id(), "10000sat"]); + let node_id_hex = server_b.node_id().to_lower_hex_string(); + let output = run_cli(&server_a, &["spontaneous-send", &node_id_hex, "10000sat"]); assert!(!output["payment_id"].as_str().unwrap().is_empty()); // Verify events @@ -403,13 +443,13 @@ async fn test_cli_spontaneous_send() { let events_a = consumer_a.consume_events(5, Duration::from_secs(10)).await; assert!( - events_a.iter().any(|e| matches!(&e.event, Some(Event::PaymentSuccessful(_)))), + events_a.iter().any(|e| matches!(e, Event::PaymentSuccessful(_))), "Expected PaymentSuccessful on sender" ); let events_b = consumer_b.consume_events(5, Duration::from_secs(10)).await; assert!( - events_b.iter().any(|e| matches!(&e.event, Some(Event::PaymentReceived(_)))), + events_b.iter().any(|e| matches!(e, Event::PaymentReceived(_))), "Expected PaymentReceived on receiver" ); } @@ -426,14 +466,14 @@ async fn test_cli_get_payment_details() { .client() .bolt11_receive(Bolt11ReceiveRequest { amount_msat: Some(10_000_000), - description: Some(Bolt11InvoiceDescription { - kind: Some(bolt11_invoice_description::Kind::Direct("test".to_string())), - }), + description: Some(Bolt11InvoiceDescription::Direct("test".to_string())), expiry_secs: 3600, }) .await .unwrap(); + let invoice: Bolt11Invoice = invoice_resp.invoice.parse().unwrap(); + let send_output = run_cli(&server_a, &["bolt11-send", &invoice_resp.invoice]); let payment_id = send_output["payment_id"].as_str().unwrap(); @@ -441,8 +481,19 @@ async fn test_cli_get_payment_details() { tokio::time::sleep(Duration::from_secs(3)).await; let output = run_cli(&server_a, &["get-payment-details", payment_id]); - assert!(output.get("payment").is_some()); - assert_eq!(output["payment"]["id"], payment_id); + let payment = &output["payment"]; + assert_eq!(payment["id"], payment_id); + assert_eq!(payment["status"], "succeeded"); + assert_eq!(payment["direction"], "outbound"); + + // Verify the payment hash in the details matches the invoice + let details_hash_hex = payment["kind"]["bolt11"]["hash"].as_str().unwrap(); + let details_hash = <[u8; 32]>::from_hex(details_hash_hex).unwrap(); + assert_eq!( + details_hash, + *invoice.payment_hash().as_byte_array(), + "payment hash in details should match invoice" + ); } #[tokio::test] @@ -457,9 +508,7 @@ async fn test_cli_list_payments() { .client() .bolt11_receive(Bolt11ReceiveRequest { amount_msat: Some(10_000_000), - description: Some(Bolt11InvoiceDescription { - kind: Some(bolt11_invoice_description::Kind::Direct("test".to_string())), - }), + description: Some(Bolt11InvoiceDescription::Direct("test".to_string())), expiry_secs: 3600, }) .await @@ -479,7 +528,8 @@ async fn test_cli_close_channel() { let server_b = LdkServerHandle::start(&bitcoind).await; let user_channel_id = setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await; - let output = run_cli(&server_a, &["close-channel", &user_channel_id, server_b.node_id()]); + let node_id_hex = server_b.node_id().to_lower_hex_string(); + let output = run_cli(&server_a, &["close-channel", &user_channel_id, &node_id_hex]); assert!(output.is_object()); mine_and_sync(&bitcoind, &[&server_a, &server_b], 6).await; @@ -496,7 +546,8 @@ async fn test_cli_force_close_channel() { let server_b = LdkServerHandle::start(&bitcoind).await; let user_channel_id = setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await; - let output = run_cli(&server_a, &["force-close-channel", &user_channel_id, server_b.node_id()]); + let node_id_hex = server_b.node_id().to_lower_hex_string(); + let output = run_cli(&server_a, &["force-close-channel", &user_channel_id, &node_id_hex]); assert!(output.is_object()); mine_and_sync(&bitcoind, &[&server_a, &server_b], 6).await; @@ -513,8 +564,8 @@ async fn test_cli_splice_in() { let server_b = LdkServerHandle::start(&bitcoind).await; let user_channel_id = setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await; - let output = - run_cli(&server_a, &["splice-in", &user_channel_id, server_b.node_id(), "50000sat"]); + let node_id_hex = server_b.node_id().to_lower_hex_string(); + let output = run_cli(&server_a, &["splice-in", &user_channel_id, &node_id_hex, "50000sat"]); assert!(output.is_object()); } @@ -525,8 +576,8 @@ async fn test_cli_splice_out() { let server_b = LdkServerHandle::start(&bitcoind).await; let user_channel_id = setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await; - let output = - run_cli(&server_a, &["splice-out", &user_channel_id, server_b.node_id(), "10000sat"]); + let node_id_hex = server_b.node_id().to_lower_hex_string(); + let output = run_cli(&server_a, &["splice-out", &user_channel_id, &node_id_hex, "10000sat"]); let address = output["address"].as_str().unwrap(); assert!(address.starts_with("bcrt1"), "Expected regtest address, got: {}", address); } @@ -577,7 +628,9 @@ async fn test_cli_graph_with_channel() { let channel = &output["channel"]; let node_one = channel["node_one"].as_str().unwrap(); let node_two = channel["node_two"].as_str().unwrap(); - let nodes = [server_a.node_id(), server_b.node_id()]; + let node_a_hex = server_a.node_id().to_lower_hex_string(); + let node_b_hex = server_b.node_id().to_lower_hex_string(); + let nodes = [node_a_hex.as_str(), node_b_hex.as_str()]; assert!(nodes.contains(&node_one), "node_one {} not one of our nodes", node_one); assert!(nodes.contains(&node_two), "node_two {} not one of our nodes", node_two); @@ -585,11 +638,11 @@ async fn test_cli_graph_with_channel() { let output = run_cli(&server_a, &["graph-list-nodes"]); let node_ids: Vec<&str> = output["node_ids"].as_array().unwrap().iter().map(|n| n.as_str().unwrap()).collect(); - assert!(node_ids.contains(&server_a.node_id()), "Expected server_a in graph nodes"); - assert!(node_ids.contains(&server_b.node_id()), "Expected server_b in graph nodes"); + assert!(node_ids.contains(&node_a_hex.as_str()), "Expected server_a in graph nodes"); + assert!(node_ids.contains(&node_b_hex.as_str()), "Expected server_b in graph nodes"); // Test GraphGetNode: should return node info with at least one channel. - let output = run_cli(&server_a, &["graph-get-node", server_b.node_id()]); + let output = run_cli(&server_a, &["graph-get-node", &node_b_hex]); let node = &output["node"]; let channels = node["channels"].as_array().unwrap(); assert!(!channels.is_empty(), "Expected node to have at least one channel"); @@ -614,8 +667,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 SSE consumer on B before any payments + let mut consumer_b = CliEventConsumer::new(&server_b); // Open channel A -> B (1M sats, larger for JIT forwarding) setup_funded_channel(&bitcoind, &server_a, &server_b, 1_000_000).await; @@ -630,7 +683,7 @@ async fn test_forwarded_payment_event() { let storage_dir_c = tempfile::tempdir().unwrap().into_path(); let p2p_port_c = find_available_port(); let config_c = ldk_node::config::Config { - network: ldk_node::bitcoin::Network::Regtest, + network: Network::Regtest, storage_dir_path: storage_dir_c.to_str().unwrap().to_string(), listening_addresses: Some(vec![SocketAddress::from_str(&format!( "127.0.0.1:{p2p_port_c}" @@ -644,7 +697,8 @@ async fn test_forwarded_payment_event() { builder_c.set_chain_source_bitcoind_rpc(rpc_host, rpc_port, rpc_user, rpc_password); // Set B as LSPS2 LSP for C - let b_node_id = ldk_node::bitcoin::secp256k1::PublicKey::from_str(server_b.node_id()).unwrap(); + let b_node_id_hex = server_b.node_id().to_lower_hex_string(); + let b_node_id = PublicKey::from_str(&b_node_id_hex).unwrap(); let b_addr = SocketAddress::from_str(&format!("127.0.0.1:{}", server_b.p2p_port)).unwrap(); builder_c.set_liquidity_source_lsps2(b_node_id, b_addr, None); @@ -678,9 +732,9 @@ async fn test_forwarded_payment_event() { // Verify PaymentForwarded event on B let events_b = consumer_b.consume_events(10, Duration::from_secs(15)).await; assert!( - events_b.iter().any(|e| matches!(&e.event, Some(Event::PaymentForwarded(_)))), + events_b.iter().any(|e| matches!(e, Event::PaymentForwarded(_))), "Expected PaymentForwarded event on LSP node B, got events: {:?}", - events_b.iter().map(|e| &e.event).collect::>() + events_b.iter().map(|e| e).collect::>() ); node_c.stop().unwrap(); @@ -692,8 +746,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 = CliEventConsumer::new(&server_a); + let mut consumer_b = CliEventConsumer::new(&server_b); setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await; @@ -731,9 +785,9 @@ async fn test_hodl_invoice_claim() { // Verify PaymentClaimable event on B let events_b = consumer_b.consume_events(1, Duration::from_secs(10)).await; assert!( - events_b.iter().any(|e| matches!(&e.event, Some(Event::PaymentClaimable(_)))), + events_b.iter().any(|e| matches!(e, Event::PaymentClaimable(_))), "Expected PaymentClaimable on receiver, got events: {:?}", - events_b.iter().map(|e| &e.event).collect::>() + events_b.iter().map(|e| e).collect::>() ); // Claim the payment on B @@ -749,33 +803,30 @@ async fn test_hodl_invoice_claim() { // Verify PaymentReceived event on B let events_b = consumer_b.consume_events(1, Duration::from_secs(10)).await; assert!( - events_b.iter().any(|e| matches!(&e.event, Some(Event::PaymentReceived(_)))), + events_b.iter().any(|e| matches!(e, Event::PaymentReceived(_))), "Expected PaymentReceived on receiver after claim, got events: {:?}", - events_b.iter().map(|e| &e.event).collect::>() + events_b.iter().map(|e| e).collect::>() ); // Verify PaymentSuccessful on A let events_a = consumer_a.consume_events(1, Duration::from_secs(10)).await; assert!( - events_a.iter().any(|e| matches!(&e.event, Some(Event::PaymentSuccessful(_)))), + events_a.iter().any(|e| matches!(e, Event::PaymentSuccessful(_))), "Expected PaymentSuccessful on sender, got events: {:?}", - events_a.iter().map(|e| &e.event).collect::>() + events_a.iter().map(|e| e).collect::>() ); } } #[tokio::test] async fn test_hodl_invoice_fail() { - use hex_conservative::DisplayHex; - use ldk_node::bitcoin::hashes::{sha256, Hash}; - let bitcoind = TestBitcoind::new(); let server_a = LdkServerHandle::start(&bitcoind).await; 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 = CliEventConsumer::new(&server_a); + let mut consumer_b = CliEventConsumer::new(&server_b); setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await; @@ -808,9 +859,9 @@ async fn test_hodl_invoice_fail() { // Verify PaymentClaimable event on B let events_b = consumer_b.consume_events(5, Duration::from_secs(10)).await; assert!( - events_b.iter().any(|e| matches!(&e.event, Some(Event::PaymentClaimable(_)))), + events_b.iter().any(|e| matches!(e, Event::PaymentClaimable(_))), "Expected PaymentClaimable on receiver, got events: {:?}", - events_b.iter().map(|e| &e.event).collect::>() + events_b.iter().map(|e| e).collect::>() ); // Fail the payment on B using CLI @@ -822,8 +873,8 @@ async fn test_hodl_invoice_fail() { // Verify PaymentFailed on A let events_a = consumer_a.consume_events(10, Duration::from_secs(10)).await; assert!( - events_a.iter().any(|e| matches!(&e.event, Some(Event::PaymentFailed(_)))), + events_a.iter().any(|e| matches!(e, Event::PaymentFailed(_))), "Expected PaymentFailed on sender after hodl rejection, got events: {:?}", - events_a.iter().map(|e| &e.event).collect::>() + events_a.iter().map(|e| e).collect::>() ); } diff --git a/index.html b/index.html new file mode 100644 index 00000000..6be48881 --- /dev/null +++ b/index.html @@ -0,0 +1,264 @@ + + + + + LDK Server + + + +

LDK Server

+ +
+

Connection

+ + +

+ + +

+ + +

+ + +
+ +
+

Peers

+ +
+

+  
+ +
+

Send Payment

+ + +

+  
+ +
+

Events

+ +

+  
+ + + + diff --git a/ldk-server-cli/Cargo.toml b/ldk-server-cli/Cargo.toml index 5d006001..e9cccebb 100644 --- a/ldk-server-cli/Cargo.toml +++ b/ldk-server-cli/Cargo.toml @@ -4,11 +4,12 @@ version = "0.1.0" edition = "2021" [dependencies] -ldk-server-client = { path = "../ldk-server-client", features = ["serde"] } +ldk-server-client = { path = "../ldk-server-client" } clap = { version = "4.0.5", default-features = false, features = ["derive", "std", "error-context", "suggestions", "help"] } clap_complete = { version = "4.0", default-features = false } hex-conservative = { version = "0.2", default-features = false, features = ["std"] } tokio = { version = "1.38.0", default-features = false, features = ["rt-multi-thread", "macros"] } serde = "1.0" serde_json = "1.0" +futures-util = { version = "0.3", default-features = false } toml = { version = "0.8", default-features = false, features = ["parse"] } diff --git a/ldk-server-cli/src/main.rs b/ldk-server-cli/src/main.rs index d960f087..c53fc9fe 100644 --- a/ldk-server-cli/src/main.rs +++ b/ldk-server-cli/src/main.rs @@ -15,13 +15,14 @@ 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, }; -use hex_conservative::DisplayHex; +use hex_conservative::{DisplayHex, FromHex}; use ldk_server_client::client::LdkServerClient; use ldk_server_client::error::LdkServerError; use ldk_server_client::error::LdkServerErrorCode::{ - AuthError, InternalError, InternalServerError, InvalidRequestError, LightningError, + AuthError, InternalError, InternalServerError, InvalidRequestError, JsonParseError, + LightningError, }; -use ldk_server_client::ldk_server_protos::api::{ +use ldk_server_client::ldk_server_json_models::api::{ Bolt11ClaimForHashRequest, Bolt11ClaimForHashResponse, Bolt11FailForHashRequest, Bolt11FailForHashResponse, Bolt11ReceiveForHashRequest, Bolt11ReceiveForHashResponse, Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11ReceiveVariableAmountViaJitChannelRequest, @@ -42,9 +43,8 @@ use ldk_server_client::ldk_server_protos::api::{ SpontaneousSendResponse, UnifiedSendRequest, UnifiedSendResponse, UpdateChannelConfigRequest, UpdateChannelConfigResponse, VerifySignatureRequest, VerifySignatureResponse, }; -use ldk_server_client::ldk_server_protos::types::{ - bolt11_invoice_description, Bolt11InvoiceDescription, ChannelConfig, PageToken, - RouteParametersConfig, +use ldk_server_client::ldk_server_json_models::types::{ + Bolt11InvoiceDescription, ChannelConfig, PageToken, RouteParametersConfig, }; use serde::Serialize; use serde_json::{json, Value}; @@ -55,9 +55,7 @@ use types::{ mod config; mod types; -// Having these default values as constants in the Proto file and -// importing/reusing them here might be better, but Proto3 removed -// the ability to set default values. +// Default values for route parameters configuration. const DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA: u32 = 1008; const DEFAULT_MAX_PATH_COUNT: u32 = 10; const DEFAULT_MAX_CHANNEL_SATURATION_POWER_OF_HALF: u32 = 2; @@ -524,6 +522,8 @@ enum Commands { #[arg(help = "The hex-encoded node ID to look up")] node_id: String, }, + #[command(about = "Subscribe to server-sent events and print each event as a JSON line")] + Subscribe, #[command(about = "Generate shell completions for the CLI")] Completions { #[arg( @@ -654,12 +654,8 @@ async fn main() { } => { let amount_msat = amount.map(|a| a.to_msat()); let invoice_description = match (description, description_hash) { - (Some(desc), None) => Some(Bolt11InvoiceDescription { - kind: Some(bolt11_invoice_description::Kind::Direct(desc)), - }), - (None, Some(hash)) => Some(Bolt11InvoiceDescription { - kind: Some(bolt11_invoice_description::Kind::Hash(hash)), - }), + (Some(desc), None) => Some(Bolt11InvoiceDescription::Direct(desc)), + (None, Some(hash)) => Some(Bolt11InvoiceDescription::Hash(hash)), (Some(_), Some(_)) => { handle_error(LdkServerError::new( InternalError, @@ -674,7 +670,7 @@ async fn main() { description: invoice_description, expiry_secs, amount_msat, - payment_hash, + payment_hash: parse_hex_32(&payment_hash, "payment_hash"), }; handle_response_result::<_, Bolt11ReceiveForHashResponse>( @@ -685,16 +681,20 @@ async fn main() { handle_response_result::<_, Bolt11ClaimForHashResponse>( client .bolt11_claim_for_hash(Bolt11ClaimForHashRequest { - payment_hash, + payment_hash: payment_hash.map(|h| parse_hex_32(&h, "payment_hash")), claimable_amount_msat: claimable_amount.map(|a| a.to_msat()), - preimage, + preimage: parse_hex_32(&preimage, "preimage"), }) .await, ); }, Commands::Bolt11FailForHash { payment_hash } => { handle_response_result::<_, Bolt11FailForHashResponse>( - client.bolt11_fail_for_hash(Bolt11FailForHashRequest { payment_hash }).await, + client + .bolt11_fail_for_hash(Bolt11FailForHashRequest { + payment_hash: parse_hex_32(&payment_hash, "payment_hash"), + }) + .await, ); }, Commands::Bolt11ReceiveViaJitChannel { @@ -828,7 +828,7 @@ async fn main() { client .spontaneous_send(SpontaneousSendRequest { amount_msat, - node_id, + node_id: parse_hex_33(&node_id, "node_id"), route_parameters: Some(route_parameters), }) .await, @@ -865,7 +865,13 @@ async fn main() { Commands::CloseChannel { user_channel_id, counterparty_node_id } => { handle_response_result::<_, CloseChannelResponse>( client - .close_channel(CloseChannelRequest { user_channel_id, counterparty_node_id }) + .close_channel(CloseChannelRequest { + user_channel_id, + counterparty_node_id: parse_hex_33( + &counterparty_node_id, + "counterparty_node_id", + ), + }) .await, ); }, @@ -878,7 +884,10 @@ async fn main() { client .force_close_channel(ForceCloseChannelRequest { user_channel_id, - counterparty_node_id, + counterparty_node_id: parse_hex_33( + &counterparty_node_id, + "counterparty_node_id", + ), force_close_reason, }) .await, @@ -906,7 +915,7 @@ async fn main() { handle_response_result::<_, OpenChannelResponse>( client .open_channel(OpenChannelRequest { - node_pubkey, + node_pubkey: parse_hex_33(&node_pubkey, "node_pubkey"), address, channel_amount_sats, push_to_counterparty_msat, @@ -923,7 +932,10 @@ async fn main() { client .splice_in(SpliceInRequest { user_channel_id, - counterparty_node_id, + counterparty_node_id: parse_hex_33( + &counterparty_node_id, + "counterparty_node_id", + ), splice_amount_sats, }) .await, @@ -936,7 +948,10 @@ async fn main() { client .splice_out(SpliceOutRequest { user_channel_id, - counterparty_node_id, + counterparty_node_id: parse_hex_33( + &counterparty_node_id, + "counterparty_node_id", + ), address, splice_amount_sats, }) @@ -964,7 +979,11 @@ async fn main() { }, Commands::GetPaymentDetails { payment_id } => { handle_response_result::<_, GetPaymentDetailsResponse>( - client.get_payment_details(GetPaymentDetailsRequest { payment_id }).await, + client + .get_payment_details(GetPaymentDetailsRequest { + payment_id: parse_hex_32(&payment_id, "payment_id"), + }) + .await, ); }, Commands::ListForwardedPayments { number_of_payments, page_token } => { @@ -1005,7 +1024,10 @@ async fn main() { client .update_channel_config(UpdateChannelConfigRequest { user_channel_id, - counterparty_node_id, + counterparty_node_id: parse_hex_33( + &counterparty_node_id, + "counterparty_node_id", + ), channel_config: Some(channel_config), }) .await, @@ -1021,12 +1043,22 @@ async fn main() { std::process::exit(1); }; handle_response_result::<_, ConnectPeerResponse>( - client.connect_peer(ConnectPeerRequest { node_pubkey, address, persist }).await, + client + .connect_peer(ConnectPeerRequest { + node_pubkey: parse_hex_33(&node_pubkey, "node_pubkey"), + address, + persist, + }) + .await, ); }, Commands::DisconnectPeer { node_pubkey } => { handle_response_result::<_, DisconnectPeerResponse>( - client.disconnect_peer(DisconnectPeerRequest { node_pubkey }).await, + client + .disconnect_peer(DisconnectPeerRequest { + node_pubkey: parse_hex_33(&node_pubkey, "node_pubkey"), + }) + .await, ); }, Commands::ListPeers => { @@ -1036,18 +1068,16 @@ async fn main() { }, Commands::SignMessage { message } => { handle_response_result::<_, SignMessageResponse>( - client - .sign_message(SignMessageRequest { message: message.into_bytes().into() }) - .await, + client.sign_message(SignMessageRequest { message: message.into_bytes() }).await, ); }, Commands::VerifySignature { message, signature, public_key } => { handle_response_result::<_, VerifySignatureResponse>( client .verify_signature(VerifySignatureRequest { - message: message.into_bytes().into(), + message: message.into_bytes(), signature, - public_key, + public_key: parse_hex_33(&public_key, "public_key"), }) .await, ); @@ -1079,9 +1109,26 @@ async fn main() { }, Commands::GraphGetNode { node_id } => { handle_response_result::<_, GraphGetNodeResponse>( - client.graph_get_node(GraphGetNodeRequest { node_id }).await, + client + .graph_get_node(GraphGetNodeRequest { + node_id: parse_hex_33(&node_id, "node_id"), + }) + .await, ); }, + Commands::Subscribe => { + use futures_util::StreamExt; + let stream = client.subscribe().await.unwrap_or_else(|e| handle_error(e)); + tokio::pin!(stream); + while let Some(event) = stream.next().await { + match serde_json::to_string(&event) { + Ok(json) => println!("{json}"), + Err(e) => { + eprintln!("Error serializing event: {e}"); + }, + } + } + }, Commands::Completions { .. } => unreachable!("Handled above"), } } @@ -1166,16 +1213,30 @@ where } } +fn parse_hex_32(hex: &str, field_name: &str) -> [u8; 32] { + <[u8; 32]>::from_hex(hex).unwrap_or_else(|_| { + handle_error(LdkServerError::new( + InvalidRequestError, + format!("Invalid {field_name}, must be a 32-byte hex string."), + )) + }) +} + +fn parse_hex_33(hex: &str, field_name: &str) -> [u8; 33] { + <[u8; 33]>::from_hex(hex).unwrap_or_else(|_| { + handle_error(LdkServerError::new( + InvalidRequestError, + format!("Invalid {field_name}, must be a 33-byte hex string."), + )) + }) +} + fn parse_bolt11_invoice_description( description: Option, description_hash: Option, ) -> Option { match (description, description_hash) { - (Some(desc), None) => Some(Bolt11InvoiceDescription { - kind: Some(bolt11_invoice_description::Kind::Direct(desc)), - }), - (None, Some(hash)) => Some(Bolt11InvoiceDescription { - kind: Some(bolt11_invoice_description::Kind::Hash(hash)), - }), + (Some(desc), None) => Some(Bolt11InvoiceDescription::Direct(desc)), + (None, Some(hash)) => Some(Bolt11InvoiceDescription::Hash(hash)), (Some(_), Some(_)) => { handle_error(LdkServerError::new( InternalError, @@ -1211,6 +1272,7 @@ fn handle_error(e: LdkServerError) -> ! { AuthError => "Authentication Error", LightningError => "Lightning Error", InternalServerError => "Internal Server Error", + JsonParseError => "JSON Parse Error", InternalError => "Internal Error", }; eprintln!("Error ({}): {}", error_type, e.message); diff --git a/ldk-server-cli/src/types.rs b/ldk-server-cli/src/types.rs index 92f778ad..ca42760f 100644 --- a/ldk-server-cli/src/types.rs +++ b/ldk-server-cli/src/types.rs @@ -16,7 +16,7 @@ use std::fmt; use std::str::FromStr; -use ldk_server_client::ldk_server_protos::types::{ForwardedPayment, PageToken, Payment}; +use ldk_server_client::ldk_server_json_models::types::{ForwardedPayment, PageToken, Payment}; use serde::Serialize; /// CLI-specific wrapper for paginated responses that formats the page token diff --git a/ldk-server-client/Cargo.toml b/ldk-server-client/Cargo.toml index 13916fa3..f30d5851 100644 --- a/ldk-server-client/Cargo.toml +++ b/ldk-server-client/Cargo.toml @@ -3,12 +3,11 @@ name = "ldk-server-client" version = "0.1.0" edition = "2021" -[features] -default = [] -serde = ["ldk-server-protos/serde"] - [dependencies] -ldk-server-protos = { path = "../ldk-server-protos" } -reqwest = { version = "0.11.13", default-features = false, features = ["rustls-tls"] } -prost = { version = "0.11.6", default-features = false, features = ["std", "prost-derive"] } +ldk-server-json-models = { path = "../ldk-server-json-models" } +reqwest = { version = "0.11.13", default-features = false, features = ["rustls-tls", "stream"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" bitcoin_hashes = "0.14" +futures-util = { version = "0.3", default-features = false } +async-stream = "0.3" diff --git a/ldk-server-client/src/client.rs b/ldk-server-client/src/client.rs index 75459a45..0859f53e 100644 --- a/ldk-server-client/src/client.rs +++ b/ldk-server-client/src/client.rs @@ -11,7 +11,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use bitcoin_hashes::hmac::{Hmac, HmacEngine}; use bitcoin_hashes::{sha256, Hash, HashEngine}; -use ldk_server_protos::api::{ +use ldk_server_json_models::api::{ Bolt11ClaimForHashRequest, Bolt11ClaimForHashResponse, Bolt11FailForHashRequest, Bolt11FailForHashResponse, Bolt11ReceiveForHashRequest, Bolt11ReceiveForHashResponse, Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11ReceiveVariableAmountViaJitChannelRequest, @@ -33,7 +33,7 @@ use ldk_server_protos::api::{ SpontaneousSendResponse, UnifiedSendRequest, UnifiedSendResponse, UpdateChannelConfigRequest, UpdateChannelConfigResponse, VerifySignatureRequest, VerifySignatureResponse, }; -use ldk_server_protos::endpoints::{ +use ldk_server_json_models::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, @@ -42,20 +42,22 @@ use ldk_server_protos::endpoints::{ 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, + SPLICE_OUT_PATH, SPONTANEOUS_SEND_PATH, SUBSCRIBE_PATH, UNIFIED_SEND_PATH, + UPDATE_CHANNEL_CONFIG_PATH, VERIFY_SIGNATURE_PATH, }; -use ldk_server_protos::error::{ErrorCode, ErrorResponse}; -use prost::Message; +use ldk_server_json_models::error::{ErrorCode, ErrorResponse}; use reqwest::header::CONTENT_TYPE; use reqwest::{Certificate, Client}; +use serde::de::DeserializeOwned; +use serde::Serialize; use crate::error::LdkServerError; use crate::error::LdkServerErrorCode::{ - AuthError, InternalError, InternalServerError, InvalidRequestError, LightningError, + AuthError, InternalError, InternalServerError, InvalidRequestError, JsonParseError, + LightningError, }; -const APPLICATION_OCTET_STREAM: &str = "application/octet-stream"; +const APPLICATION_JSON: &str = "application/json"; /// Client to access a hosted instance of LDK Server. /// @@ -427,15 +429,90 @@ impl LdkServerClient { self.post_request(&request, &url).await } - async fn post_request( + /// Subscribe to server-sent events. Returns an async stream of [`Event`] values. + /// + /// The stream yields one item per SSE event. It ends when the server closes the connection. + /// + /// [`Event`]: ldk_server_json_models::events::Event + pub async fn subscribe( + &self, + ) -> Result< + impl futures_util::Stream, + LdkServerError, + > { + use futures_util::StreamExt; + let url = format!("https://{}/{SUBSCRIBE_PATH}", self.base_url); + let auth_header = self.compute_auth_header(&[]); + let response = self + .client + .get(&url) + .header("X-Auth", auth_header) + .header("Accept", "text/event-stream") + .send() + .await + .map_err(|e| { + LdkServerError::new(InternalError, format!("HTTP request failed: {}", e)) + })?; + + if !response.status().is_success() { + let status = response.status(); + let payload = response.bytes().await.map_err(|e| { + LdkServerError::new(InternalError, format!("Failed to read response body: {}", e)) + })?; + let error_response = + serde_json::from_slice::(&payload).map_err(|e| { + LdkServerError::new( + JsonParseError, + format!("Failed to decode error response (status {}): {}", status, e), + ) + })?; + let error_code = match error_response.error_code { + ErrorCode::InvalidRequestError => InvalidRequestError, + ErrorCode::AuthError => AuthError, + ErrorCode::LightningError => LightningError, + ErrorCode::InternalServerError => InternalServerError, + ErrorCode::UnknownError => InternalError, + }; + return Err(LdkServerError::new(error_code, error_response.message)); + } + + let stream = async_stream::stream! { + let mut byte_stream = response.bytes_stream(); + let mut buffer = String::new(); + while let Some(chunk) = byte_stream.next().await { + let chunk = match chunk { + Ok(c) => c, + Err(_) => break, + }; + buffer.push_str(&String::from_utf8_lossy(&chunk)); + while let Some(pos) = buffer.find("\n\n") { + let event_block = buffer[..pos].to_string(); + buffer = buffer[pos + 2..].to_string(); + for line in event_block.lines() { + if let Some(data) = line.strip_prefix("data: ") { + if let Ok(event) = serde_json::from_str::(data) { + yield event; + } + } + } + } + } + }; + + Ok(stream) + } + + async fn post_request( &self, request: &Rq, url: &str, ) -> Result { - let request_body = request.encode_to_vec(); + let request_body = serde_json::to_vec(request).map_err(|e| { + LdkServerError::new(JsonParseError, format!("Failed to serialize request: {}", e)) + })?; let auth_header = self.compute_auth_header(&request_body); let response_raw = self .client .post(url) - .header(CONTENT_TYPE, APPLICATION_OCTET_STREAM) + .header(CONTENT_TYPE, APPLICATION_JSON) .header("X-Auth", auth_header) .body(request_body) .send() @@ -450,26 +527,27 @@ impl LdkServerClient { })?; if status.is_success() { - Ok(Rs::decode(&payload[..]).map_err(|e| { + Ok(serde_json::from_slice::(&payload).map_err(|e| { LdkServerError::new( - InternalError, + JsonParseError, 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, + let error_response = + serde_json::from_slice::(&payload).map_err(|e| { + LdkServerError::new( + JsonParseError, + format!("Failed to decode error response (status {}): {}", status, e), + ) + })?; + + let error_code = match error_response.error_code { + ErrorCode::InvalidRequestError => InvalidRequestError, + ErrorCode::AuthError => AuthError, + ErrorCode::LightningError => LightningError, + ErrorCode::InternalServerError => InternalServerError, + ErrorCode::UnknownError => InternalError, }; Err(LdkServerError::new(error_code, error_response.message)) diff --git a/ldk-server-client/src/error.rs b/ldk-server-client/src/error.rs index 67cba37d..06bc867a 100644 --- a/ldk-server-client/src/error.rs +++ b/ldk-server-client/src/error.rs @@ -41,18 +41,21 @@ impl fmt::Display for LdkServerError { /// Defines error codes for categorizing LDK server errors. #[derive(Clone, Debug, PartialEq, Eq)] pub enum LdkServerErrorCode { - /// Please refer to [`ldk_server_protos::error::ErrorCode::InvalidRequestError`]. + /// Please refer to [`ldk_server_json_models::error::ErrorCode::InvalidRequestError`]. InvalidRequestError, - /// Please refer to [`ldk_server_protos::error::ErrorCode::AuthError`]. + /// Please refer to [`ldk_server_json_models::error::ErrorCode::AuthError`]. AuthError, - /// Please refer to [`ldk_server_protos::error::ErrorCode::LightningError`]. + /// Please refer to [`ldk_server_json_models::error::ErrorCode::LightningError`]. LightningError, - /// Please refer to [`ldk_server_protos::error::ErrorCode::InternalServerError`]. + /// Please refer to [`ldk_server_json_models::error::ErrorCode::InternalServerError`]. InternalServerError, + /// A JSON serialization or deserialization error occurred. + JsonParseError, + /// There is an unknown error, it could be a client-side bug, unrecognized error-code, network error /// or something else. InternalError, @@ -65,6 +68,7 @@ impl fmt::Display for LdkServerErrorCode { LdkServerErrorCode::AuthError => write!(f, "AuthError"), LdkServerErrorCode::LightningError => write!(f, "LightningError"), LdkServerErrorCode::InternalServerError => write!(f, "InternalServerError"), + LdkServerErrorCode::JsonParseError => write!(f, "JsonParseError"), LdkServerErrorCode::InternalError => write!(f, "InternalError"), } } diff --git a/ldk-server-client/src/lib.rs b/ldk-server-client/src/lib.rs index 098c7087..708f23a3 100644 --- a/ldk-server-client/src/lib.rs +++ b/ldk-server-client/src/lib.rs @@ -20,4 +20,4 @@ pub mod client; pub mod error; /// Request/Response structs required for interacting with the ldk-ldk-server-client. -pub use ldk_server_protos; +pub use ldk_server_json_models; diff --git a/ldk-server-json-models/Cargo.toml b/ldk-server-json-models/Cargo.toml new file mode 100644 index 00000000..0805a357 --- /dev/null +++ b/ldk-server-json-models/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "ldk-server-json-models" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +utoipa = { version = "5", features = ["preserve_order"] } diff --git a/ldk-server-protos/src/api.rs b/ldk-server-json-models/src/api.rs similarity index 52% rename from ldk-server-protos/src/api.rs rename to ldk-server-json-models/src/api.rs index f72357d3..a9cb598d 100644 --- a/ldk-server-protos/src/api.rs +++ b/ldk-server-json-models/src/api.rs @@ -7,113 +7,87 @@ // You may not use this file except in accordance with one or both of these // licenses. +use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; + /// 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct GetNodeInfoResponse { /// The hex-encoded `node-id` or public key for our own lightning node. - #[prost(string, tag = "1")] - pub node_id: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub node_id: [u8; 33], /// The best block to which our Lightning wallet is currently synced. - /// - /// Should be always set, will never be `None`. - #[prost(message, optional, tag = "3")] - pub current_best_block: ::core::option::Option, + pub current_best_block: super::types::BestBlock, /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our Lightning wallet to /// the chain tip. /// /// Will be `None` if the wallet hasn't been synced yet. - #[prost(uint64, optional, tag = "4")] - pub latest_lightning_wallet_sync_timestamp: ::core::option::Option, + pub latest_lightning_wallet_sync_timestamp: Option, /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our on-chain /// wallet to the chain tip. /// - /// Will be `None` if the wallet hasn’t been synced since the node was initialized. - #[prost(uint64, optional, tag = "5")] - pub latest_onchain_wallet_sync_timestamp: ::core::option::Option, + /// Will be `None` if the wallet hasn't been synced since the node was initialized. + pub latest_onchain_wallet_sync_timestamp: Option, /// The timestamp, in seconds since start of the UNIX epoch, when we last successfully update our fee rate cache. /// - /// Will be `None` if the cache hasn’t been updated since the node was initialized. - #[prost(uint64, optional, tag = "6")] - pub latest_fee_rate_cache_update_timestamp: ::core::option::Option, + /// Will be `None` if the cache hasn't been updated since the node was initialized. + pub latest_fee_rate_cache_update_timestamp: Option, /// The timestamp, in seconds since start of the UNIX epoch, when the last rapid gossip sync (RGS) snapshot we /// successfully applied was generated. /// - /// Will be `None` if RGS isn’t configured or the snapshot hasn’t been updated since the node was initialized. - #[prost(uint64, optional, tag = "7")] - pub latest_rgs_snapshot_timestamp: ::core::option::Option, + /// Will be `None` if RGS isn't configured or the snapshot hasn't been updated since the node was initialized. + pub latest_rgs_snapshot_timestamp: Option, /// The timestamp, in seconds since start of the UNIX epoch, when we last broadcasted a node announcement. /// - /// Will be `None` if we have no public channels or we haven’t broadcasted since the node was initialized. - #[prost(uint64, optional, tag = "8")] - pub latest_node_announcement_broadcast_timestamp: ::core::option::Option, + /// Will be `None` if we have no public channels or we haven't broadcasted since the node was initialized. + pub latest_node_announcement_broadcast_timestamp: Option, /// The addresses the node is currently listening on for incoming connections. /// /// Will be empty if the node is not listening on any addresses. - #[prost(string, repeated, tag = "9")] - pub listening_addresses: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + pub listening_addresses: Vec, /// The addresses the node announces to the network. /// /// Will be empty if no announcement addresses are configured. - #[prost(string, repeated, tag = "10")] - pub announcement_addresses: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + pub announcement_addresses: Vec, /// The node alias, if configured. /// /// Will be `None` if no alias is configured. - #[prost(string, optional, tag = "11")] - pub node_alias: ::core::option::Option<::prost::alloc::string::String>, + pub node_alias: Option, /// The node URIs that can be used to connect to this node, in the format `node_id@address`. /// /// These are constructed from the announcement addresses and the node's public key. /// Will be empty if no announcement addresses are configured. - #[prost(string, repeated, tag = "12")] - pub node_uris: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + pub node_uris: Vec, } /// Retrieve a new on-chain funding address. /// See more: -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct OnchainReceiveResponse { /// A Bitcoin on-chain address. - #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, + pub address: String, } /// Send an on-chain payment to the given address. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct OnchainSendRequest { /// The address to send coins to. - #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, + pub address: String, /// The amount in satoshis to send. /// While sending the specified amount, we will respect any on-chain reserve we need to keep, /// i.e., won't allow to cut into `total_anchor_channels_reserve_sats`. /// See more: - #[prost(uint64, optional, tag = "2")] - pub amount_sats: ::core::option::Option, + pub amount_sats: Option, /// If set, the amount_sats field should be unset. /// It indicates that node will send full balance to the specified address. /// @@ -121,23 +95,19 @@ pub struct OnchainSendRequest { /// which might be potentially dangerous if you have open Anchor channels for which you can't trust /// the counterparty to spend the Anchor output after channel closure. /// See more: - #[prost(bool, optional, tag = "3")] - pub send_all: ::core::option::Option, + pub send_all: Option, /// If `fee_rate_sat_per_vb` is set it will be used on the resulting transaction. Otherwise we'll retrieve /// a reasonable estimate from BitcoinD. - #[prost(uint64, optional, tag = "4")] - pub fee_rate_sat_per_vb: ::core::option::Option, + pub fee_rate_sat_per_vb: Option, } /// The response `content` for the `OnchainSend` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct OnchainSendResponse { /// The transaction ID of the broadcasted transaction. - #[prost(string, tag = "1")] - pub txid: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub txid: [u8; 32], } /// Return a BOLT11 payable invoice that can be used to request and receive a payment /// for the given amount, if specified. @@ -145,40 +115,32 @@ pub struct OnchainSendResponse { /// See more: /// - /// - -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt11ReceiveRequest { /// The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount invoice is returned. - #[prost(uint64, optional, tag = "1")] - pub amount_msat: ::core::option::Option, + pub amount_msat: Option, /// An optional description to attach along with the invoice. /// Will be set in the description field of the encoded payment request. - #[prost(message, optional, tag = "2")] - pub description: ::core::option::Option, + pub description: Option, /// Invoice expiry time in seconds. - #[prost(uint32, tag = "3")] pub expiry_secs: u32, } /// The response `content` for the `Bolt11Receive` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt11ReceiveResponse { /// An invoice for a payment within the Lightning Network. /// With the details of the invoice, the sender has all the data necessary to send a payment /// to the recipient. - #[prost(string, tag = "1")] - pub invoice: ::prost::alloc::string::String, + pub invoice: String, /// The hex-encoded 32-byte payment hash. - #[prost(string, tag = "2")] - pub payment_hash: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub payment_hash: [u8; 32], /// The hex-encoded 32-byte payment secret. - #[prost(string, tag = "3")] - pub payment_secret: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub payment_secret: [u8; 32], } /// Return a BOLT11 payable invoice for a given payment hash. /// The inbound payment will NOT be automatically claimed upon arrival. @@ -187,495 +149,358 @@ pub struct Bolt11ReceiveResponse { /// 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt11ReceiveForHashRequest { /// The amount in millisatoshi to receive. If unset, a "zero-amount" or variable-amount invoice is returned. - #[prost(uint64, optional, tag = "1")] - pub amount_msat: ::core::option::Option, + pub amount_msat: Option, /// An optional description to attach along with the invoice. /// Will be set in the description field of the encoded payment request. - #[prost(message, optional, tag = "2")] - pub description: ::core::option::Option, + pub description: Option, /// Invoice expiry time in seconds. - #[prost(uint32, tag = "3")] pub expiry_secs: u32, /// The hex-encoded 32-byte payment hash to use for the invoice. - #[prost(string, tag = "4")] - pub payment_hash: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub payment_hash: [u8; 32], } /// The response `content` for the `Bolt11ReceiveForHash` 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt11ReceiveForHashResponse { /// An invoice for a payment within the Lightning Network. /// With the details of the invoice, the sender has all the data necessary to send a payment /// to the recipient. - #[prost(string, tag = "1")] - pub invoice: ::prost::alloc::string::String, + pub invoice: String, } /// Manually claim a payment for a given payment hash with the corresponding preimage. /// This should be used to claim 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt11ClaimForHashRequest { /// The hex-encoded 32-byte payment hash. /// If provided, it will be used to verify that the preimage matches. - #[prost(string, optional, tag = "1")] - pub payment_hash: ::core::option::Option<::prost::alloc::string::String>, + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub payment_hash: Option<[u8; 32]>, /// The amount in millisatoshi that is claimable. /// If not provided, skips amount verification. - #[prost(uint64, optional, tag = "2")] - pub claimable_amount_msat: ::core::option::Option, + pub claimable_amount_msat: Option, /// The hex-encoded 32-byte payment preimage. - #[prost(string, tag = "3")] - pub preimage: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub preimage: [u8; 32], } /// The response `content` for the `Bolt11ClaimForHash` 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt11FailForHashRequest { /// The hex-encoded 32-byte payment hash. - #[prost(string, tag = "1")] - pub payment_hash: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub payment_hash: [u8; 32], } /// The response `content` for the `Bolt11FailForHash` 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt11ReceiveViaJitChannelRequest { /// The amount in millisatoshi to request. - #[prost(uint64, tag = "1")] pub amount_msat: u64, /// An optional description to attach along with the invoice. /// Will be set in the description field of the encoded payment request. - #[prost(message, optional, tag = "2")] - pub description: ::core::option::Option, + pub description: Option, /// Invoice expiry time in seconds. - #[prost(uint32, tag = "3")] pub expiry_secs: u32, /// Optional upper bound for the total fee an LSP may deduct when opening the JIT channel. - #[prost(uint64, optional, tag = "4")] - pub max_total_lsp_fee_limit_msat: ::core::option::Option, + pub max_total_lsp_fee_limit_msat: Option, } /// The response `content` for the `Bolt11ReceiveViaJitChannel` 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt11ReceiveViaJitChannelResponse { /// An invoice for a payment within the Lightning Network. - #[prost(string, tag = "1")] - pub invoice: ::prost::alloc::string::String, + pub invoice: String, } /// Return a variable-amount BOLT11 invoice that can be used to 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt11ReceiveVariableAmountViaJitChannelRequest { /// An optional description to attach along with the invoice. /// Will be set in the description field of the encoded payment request. - #[prost(message, optional, tag = "1")] - pub description: ::core::option::Option, + pub description: Option, /// Invoice expiry time in seconds. - #[prost(uint32, tag = "2")] pub expiry_secs: u32, /// Optional upper bound for the proportional fee, in parts-per-million millisatoshis, that an /// LSP may deduct when opening the JIT channel. - #[prost(uint64, optional, tag = "3")] - pub max_proportional_lsp_fee_limit_ppm_msat: ::core::option::Option, + pub max_proportional_lsp_fee_limit_ppm_msat: Option, } /// The response `content` for the `Bolt11ReceiveVariableAmountViaJitChannel` 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt11ReceiveVariableAmountViaJitChannelResponse { /// An invoice for a payment within the Lightning Network. - #[prost(string, tag = "1")] - pub invoice: ::prost::alloc::string::String, + pub invoice: String, } /// Send a payment for a BOLT11 invoice. /// See more: -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt11SendRequest { /// An invoice for a payment within the Lightning Network. - #[prost(string, tag = "1")] - pub invoice: ::prost::alloc::string::String, + pub invoice: String, /// Set this field when paying a so-called "zero-amount" invoice, i.e., an invoice that leaves the /// amount paid to be determined by the user. /// This operation will fail if the amount specified is less than the value required by the given invoice. - #[prost(uint64, optional, tag = "2")] - pub amount_msat: ::core::option::Option, + pub amount_msat: Option, /// Configuration options for payment routing and pathfinding. - #[prost(message, optional, tag = "3")] - pub route_parameters: ::core::option::Option, + pub route_parameters: Option, } /// The response `content` for the `Bolt11Send` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt11SendResponse { /// An identifier used to uniquely identify a payment in hex-encoded form. - #[prost(string, tag = "1")] - pub payment_id: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub payment_id: [u8; 32], } /// Returns a BOLT12 offer for the given amount, if specified. /// /// 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt12ReceiveRequest { /// An optional description to attach along with the offer. /// Will be set in the description field of the encoded offer. - #[prost(string, tag = "1")] - pub description: ::prost::alloc::string::String, + pub description: String, /// The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount offer is returned. - #[prost(uint64, optional, tag = "2")] - pub amount_msat: ::core::option::Option, + pub amount_msat: Option, /// Offer expiry time in seconds. - #[prost(uint32, optional, tag = "3")] - pub expiry_secs: ::core::option::Option, + pub expiry_secs: Option, /// If set, it represents the number of items requested, can only be set for fixed-amount offers. - #[prost(uint64, optional, tag = "4")] - pub quantity: ::core::option::Option, + pub quantity: Option, } /// The response `content` for the `Bolt12Receive` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt12ReceiveResponse { /// An offer for a payment within the Lightning Network. /// With the details of the offer, the sender has all the data necessary to send a payment /// to the recipient. - #[prost(string, tag = "1")] - pub offer: ::prost::alloc::string::String, + pub offer: String, /// The hex-encoded offer id. - #[prost(string, tag = "2")] - pub offer_id: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub offer_id: [u8; 32], } /// Send a payment for a BOLT12 offer. /// 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt12SendRequest { /// An offer for a payment within the Lightning Network. - #[prost(string, tag = "1")] - pub offer: ::prost::alloc::string::String, + pub offer: String, /// Set this field when paying a so-called "zero-amount" offer, i.e., an offer that leaves the /// amount paid to be determined by the user. /// This operation will fail if the amount specified is less than the value required by the given offer. - #[prost(uint64, optional, tag = "2")] - pub amount_msat: ::core::option::Option, + pub amount_msat: Option, /// If set, it represents the number of items requested. - #[prost(uint64, optional, tag = "3")] - pub quantity: ::core::option::Option, + pub quantity: Option, /// If set, it will be seen by the recipient and reflected back in the invoice. - #[prost(string, optional, tag = "4")] - pub payer_note: ::core::option::Option<::prost::alloc::string::String>, + pub payer_note: Option, /// Configuration options for payment routing and pathfinding. - #[prost(message, optional, tag = "5")] - pub route_parameters: ::core::option::Option, + pub route_parameters: Option, } /// The response `content` for the `Bolt12Send` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct Bolt12SendResponse { /// An identifier used to uniquely identify a payment in hex-encoded form. - #[prost(string, tag = "1")] - pub payment_id: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub payment_id: [u8; 32], } /// Send a spontaneous payment, also known as "keysend", to a node. /// See more: -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct SpontaneousSendRequest { /// The amount in millisatoshis to send. - #[prost(uint64, tag = "1")] pub amount_msat: u64, /// The hex-encoded public key of the node to send the payment to. - #[prost(string, tag = "2")] - pub node_id: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub node_id: [u8; 33], /// Configuration options for payment routing and pathfinding. - #[prost(message, optional, tag = "3")] - pub route_parameters: ::core::option::Option, + pub route_parameters: Option, } /// The response `content` for the `SpontaneousSend` 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct SpontaneousSendResponse { /// An identifier used to uniquely identify a payment in hex-encoded form. - #[prost(string, tag = "1")] - pub payment_id: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub payment_id: [u8; 32], } /// Creates a new outbound channel to the given remote node. /// See more: -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct OpenChannelRequest { /// The hex-encoded public key of the node to open a channel with. - #[prost(string, tag = "1")] - pub node_pubkey: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub node_pubkey: [u8; 33], /// An address which can be used to connect to a remote peer. /// It can be of type IPv4:port, IPv6:port, OnionV3:port or hostname:port - #[prost(string, tag = "2")] - pub address: ::prost::alloc::string::String, + pub address: String, /// The amount of satoshis the caller is willing to commit to the channel. - #[prost(uint64, tag = "3")] pub channel_amount_sats: u64, /// The amount of satoshis to push to the remote side as part of the initial commitment state. - #[prost(uint64, optional, tag = "4")] - pub push_to_counterparty_msat: ::core::option::Option, + pub push_to_counterparty_msat: Option, /// The channel configuration to be used for opening this channel. If unset, default ChannelConfig is used. - #[prost(message, optional, tag = "5")] - pub channel_config: ::core::option::Option, + pub channel_config: Option, /// Whether the channel should be public. - #[prost(bool, tag = "6")] pub announce_channel: bool, } /// The response `content` for the `OpenChannel` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct OpenChannelResponse { /// The local channel id of the created channel that user can use to refer to channel. - #[prost(string, tag = "1")] - pub user_channel_id: ::prost::alloc::string::String, + pub user_channel_id: String, } /// Increases 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct SpliceInRequest { /// The local `user_channel_id` of the channel. - #[prost(string, tag = "1")] - pub user_channel_id: ::prost::alloc::string::String, + pub user_channel_id: String, /// The hex-encoded public key of the channel's counterparty node. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub counterparty_node_id: [u8; 33], /// The amount of sats to splice into the channel. - #[prost(uint64, tag = "3")] pub splice_amount_sats: u64, } /// The response `content` for the `SpliceIn` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct SpliceOutRequest { /// The local `user_channel_id` of this channel. - #[prost(string, tag = "1")] - pub user_channel_id: ::prost::alloc::string::String, + pub user_channel_id: String, /// The hex-encoded public key of the channel's counterparty node. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub counterparty_node_id: [u8; 33], /// A Bitcoin on-chain address to send the spliced-out funds. /// /// If not set, an address from the node's on-chain wallet will be used. - #[prost(string, optional, tag = "3")] - pub address: ::core::option::Option<::prost::alloc::string::String>, + pub address: Option, /// The amount of sats to splice out of the channel. - #[prost(uint64, tag = "4")] pub splice_amount_sats: u64, } /// The response `content` for the `SpliceOut` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct SpliceOutResponse { /// The Bitcoin on-chain address where the funds will be sent. - #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, + pub address: String, } /// Update the config for a previously opened channel. /// See more: -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct UpdateChannelConfigRequest { /// The local `user_channel_id` of this channel. - #[prost(string, tag = "1")] - pub user_channel_id: ::prost::alloc::string::String, + pub user_channel_id: String, /// The hex-encoded public key of the counterparty node to update channel config with. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub counterparty_node_id: [u8; 33], /// The updated channel configuration settings for a channel. - #[prost(message, optional, tag = "3")] - pub channel_config: ::core::option::Option, + pub channel_config: Option, } /// The response `content` for the `UpdateChannelConfig` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct CloseChannelRequest { /// The local `user_channel_id` of this channel. - #[prost(string, tag = "1")] - pub user_channel_id: ::prost::alloc::string::String, + pub user_channel_id: String, /// The hex-encoded public key of the node to close a channel with. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub counterparty_node_id: [u8; 33], } /// The response `content` for the `CloseChannel` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct ForceCloseChannelRequest { /// The local `user_channel_id` of this channel. - #[prost(string, tag = "1")] - pub user_channel_id: ::prost::alloc::string::String, + pub user_channel_id: String, /// The hex-encoded public key of the node to close a channel with. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub counterparty_node_id: [u8; 33], /// The reason for force-closing. - #[prost(string, optional, tag = "3")] - pub force_close_reason: ::core::option::Option<::prost::alloc::string::String>, + pub force_close_reason: Option, } /// The response `content` for the `ForceCloseChannel` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct ListChannelsResponse { /// List of channels. - #[prost(message, repeated, tag = "1")] - pub channels: ::prost::alloc::vec::Vec, + pub channels: Vec, } /// Returns payment details for a given payment_id. /// See more: -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct GetPaymentDetailsRequest { /// An identifier used to uniquely identify a payment in hex-encoded form. - #[prost(string, tag = "1")] - pub payment_id: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub payment_id: [u8; 32], } /// The response `content` for the `GetPaymentDetails` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct GetPaymentDetailsResponse { /// Represents a payment. /// Will be `None` if payment doesn't exist. - #[prost(message, optional, tag = "1")] - pub payment: ::core::option::Option, + pub payment: Option, } /// Retrieves list of all payments. /// See more: -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct ListPaymentsRequest { /// `page_token` is a pagination token. /// @@ -683,19 +508,14 @@ pub struct ListPaymentsRequest { /// /// For subsequent pages, use the value that was returned as `next_page_token` in the previous /// page's response. - #[prost(message, optional, tag = "1")] - pub page_token: ::core::option::Option, + pub page_token: Option, } /// The response `content` for the `ListPayments` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct ListPaymentsResponse { /// List of payments. - #[prost(message, repeated, tag = "1")] - pub payments: ::prost::alloc::vec::Vec, + pub payments: Vec, /// `next_page_token` is a pagination token, used to retrieve the next page of results. /// Use this value to query for next-page of paginated operation, by specifying /// this value as the `page_token` in the next request. @@ -709,15 +529,11 @@ pub struct ListPaymentsResponse { /// /// **Caution**: Clients must not assume a specific number of records to be present in a page for /// paginated response. - #[prost(message, optional, tag = "2")] - pub next_page_token: ::core::option::Option, + pub next_page_token: Option, } /// Retrieves list of all forwarded payments. /// See more: -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct ListForwardedPaymentsRequest { /// `page_token` is a pagination token. /// @@ -725,19 +541,14 @@ pub struct ListForwardedPaymentsRequest { /// /// For subsequent pages, use the value that was returned as `next_page_token` in the previous /// page's response. - #[prost(message, optional, tag = "1")] - pub page_token: ::core::option::Option, + pub page_token: Option, } /// The response `content` for the `ListForwardedPayments` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct ListForwardedPaymentsResponse { /// List of forwarded payments. - #[prost(message, repeated, tag = "1")] - pub forwarded_payments: ::prost::alloc::vec::Vec, + pub forwarded_payments: Vec, /// `next_page_token` is a pagination token, used to retrieve the next page of results. /// Use this value to query for next-page of paginated operation, by specifying /// this value as the `page_token` in the next request. @@ -751,109 +562,81 @@ pub struct ListForwardedPaymentsResponse { /// /// **Caution**: Clients must not assume a specific number of records to be present in a page for /// paginated response. - #[prost(message, optional, tag = "2")] - pub next_page_token: ::core::option::Option, + pub next_page_token: Option, } /// Sign a message with the node's secret key. /// 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct SignMessageRequest { /// The message to sign, as raw bytes. - #[prost(bytes = "bytes", tag = "1")] - pub message: ::prost::bytes::Bytes, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::bytes_hex")] + pub message: Vec, } /// The response `content` for the `SignMessage` 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct SignMessageResponse { /// The signature of the message, as a zbase32-encoded string. - #[prost(string, tag = "1")] - pub signature: ::prost::alloc::string::String, + pub signature: String, } /// Verify a signature against a message and public key. /// 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct VerifySignatureRequest { /// The message that was signed, as raw bytes. - #[prost(bytes = "bytes", tag = "1")] - pub message: ::prost::bytes::Bytes, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::bytes_hex")] + pub message: Vec, /// The signature to verify, as a zbase32-encoded string. - #[prost(string, tag = "2")] - pub signature: ::prost::alloc::string::String, + pub signature: String, /// The hex-encoded public key of the signer. - #[prost(string, tag = "3")] - pub public_key: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub public_key: [u8; 33], } /// The response `content` for the `VerifySignature` 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct VerifySignatureResponse { /// Whether the signature is valid. - #[prost(bool, tag = "1")] pub valid: bool, } /// Export the pathfinding scores used by the router. /// 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct ExportPathfindingScoresResponse { /// The serialized pathfinding scores data. - #[prost(bytes = "bytes", tag = "1")] - pub scores: ::prost::bytes::Bytes, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::bytes_hex")] + pub scores: Vec, } /// Retrieves an overview of all known balances. /// See more: -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct GetBalancesResponse { /// The total balance of our on-chain wallet. - #[prost(uint64, tag = "1")] pub total_onchain_balance_sats: u64, /// The currently spendable balance of our on-chain wallet. /// /// This includes any sufficiently confirmed funds, minus `total_anchor_channels_reserve_sats`. - #[prost(uint64, tag = "2")] pub spendable_onchain_balance_sats: u64, /// The share of our total balance that we retain as an emergency reserve to (hopefully) be /// able to spend the Anchor outputs when one of our channels is closed. - #[prost(uint64, tag = "3")] pub total_anchor_channels_reserve_sats: u64, /// The total balance that we would be able to claim across all our Lightning channels. /// /// Note this excludes balances that we are unsure if we are able to claim (e.g., as we are /// waiting for a preimage or for a timeout to expire). These balances will however be included /// as `MaybePreimageClaimableHTLC` and `MaybeTimeoutClaimableHTLC` in `lightning_balances`. - #[prost(uint64, tag = "4")] pub total_lightning_balance_sats: u64, /// A detailed list of all known Lightning balances that would be claimable on channel closure. /// @@ -861,8 +644,7 @@ pub struct GetBalancesResponse { /// restrictions apply. Please refer to `Channel::outbound_capacity_msat` and /// Channel::next_outbound_htlc_limit_msat as returned by `ListChannels` /// for a better approximation of the spendable amounts. - #[prost(message, repeated, tag = "5")] - pub lightning_balances: ::prost::alloc::vec::Vec, + pub lightning_balances: Vec, /// A detailed list of balances currently being swept from the Lightning to the on-chain /// wallet. /// @@ -871,129 +653,86 @@ pub struct GetBalancesResponse { /// /// Note that, depending on the sync status of the wallets, swept balances listed here might or /// might not already be accounted for in `total_onchain_balance_sats`. - #[prost(message, repeated, tag = "6")] - pub pending_balances_from_channel_closures: - ::prost::alloc::vec::Vec, + pub pending_balances_from_channel_closures: Vec, } /// Connect to a peer on the Lightning Network. /// See more: -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct ConnectPeerRequest { /// The hex-encoded public key of the node to connect to. - #[prost(string, tag = "1")] - pub node_pubkey: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub node_pubkey: [u8; 33], /// An address which can be used to connect to a remote peer. /// It can be of type IPv4:port, IPv6:port, OnionV3:port or hostname:port - #[prost(string, tag = "2")] - pub address: ::prost::alloc::string::String, + pub address: String, /// Whether to persist the peer connection, i.e., whether the peer will be re-connected on /// restart. - #[prost(bool, tag = "3")] pub persist: bool, } /// The response `content` for the `ConnectPeer` API, when HttpStatusCode is OK (200). /// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct DisconnectPeerRequest { /// The hex-encoded public key of the node to disconnect from. - #[prost(string, tag = "1")] - pub node_pubkey: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub node_pubkey: [u8; 33], } /// The response `content` for the `DisconnectPeer` 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct ListPeersResponse { /// List of peers. - #[prost(message, repeated, tag = "1")] - pub peers: ::prost::alloc::vec::Vec, + pub peers: Vec, } /// Returns a list of all known short channel IDs in the network graph. /// 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct GraphListChannelsResponse { /// List of short channel IDs known to the network graph. - #[prost(uint64, repeated, tag = "1")] - pub short_channel_ids: ::prost::alloc::vec::Vec, + pub short_channel_ids: Vec, } /// Returns information on a channel with the given short channel ID from the network graph. /// 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct GraphGetChannelRequest { /// The short channel ID to look up. - #[prost(uint64, tag = "1")] pub short_channel_id: u64, } /// The response `content` for the `GraphGetChannel` 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct GraphGetChannelResponse { /// The channel information. - #[prost(message, optional, tag = "1")] - pub channel: ::core::option::Option, + pub channel: Option, } /// Returns a list of all known node IDs in the network graph. /// 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct GraphListNodesResponse { /// List of hex-encoded node IDs known to the network graph. - #[prost(string, repeated, tag = "1")] - pub node_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + pub node_ids: Vec, } /// Send a payment given a BIP 21 URI or BIP 353 Human-Readable Name. /// @@ -1001,69 +740,50 @@ pub struct GraphListNodesResponse { /// has an offer and/or invoice, it will try to pay the offer first followed by the invoice. /// If they both fail, the on-chain payment will be paid. /// 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct UnifiedSendRequest { /// A BIP 21 URI or BIP 353 Human-Readable Name to pay. - #[prost(string, tag = "1")] - pub uri: ::prost::alloc::string::String, + pub uri: String, /// The amount in millisatoshis to send. Required for "zero-amount" or variable-amount URIs. - #[prost(uint64, optional, tag = "2")] - pub amount_msat: ::core::option::Option, + pub amount_msat: Option, /// Configuration options for payment routing and pathfinding. - #[prost(message, optional, tag = "3")] - pub route_parameters: ::core::option::Option, + pub route_parameters: Option, } /// The response `content` for the `UnifiedSend` 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct UnifiedSendResponse { - #[prost(oneof = "unified_send_response::PaymentResult", tags = "1, 2, 3")] - #[cfg_attr(feature = "serde", serde(flatten))] - pub payment_result: ::core::option::Option, + #[serde(flatten)] + #[schema(inline)] + pub payment_result: Option, } -/// Nested message and enum types in `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. - #[prost(string, tag = "1")] - Txid(::prost::alloc::string::String), - /// A BOLT11 payment was made. Contains the payment ID in hex-encoded form. - #[prost(string, tag = "2")] - Bolt11PaymentId(::prost::alloc::string::String), - /// A BOLT12 payment was made. Contains the payment ID in hex-encoded form. - #[prost(string, tag = "3")] - Bolt12PaymentId(::prost::alloc::string::String), - } +/// The payment result of a unified send operation. +/// +/// Note: Variants use `String` instead of `[u8; 32]` because `#[serde(with)]` +/// is not supported on enum tuple variants. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum UnifiedSendPaymentResult { + /// An on-chain payment was made. Contains the hex-encoded transaction ID. + Txid(String), + /// A BOLT11 payment was made. Contains the hex-encoded payment ID. + Bolt11PaymentId(String), + /// A BOLT12 payment was made. Contains the payment ID in hex-encoded form. + Bolt12PaymentId(String), } /// Returns information on a node with the given ID from the network graph. /// 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, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct GraphGetNodeRequest { /// The hex-encoded node ID to look up. - #[prost(string, tag = "1")] - pub node_id: ::prost::alloc::string::String, + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub node_id: [u8; 33], } /// The response `content` for the `GraphGetNode` 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)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] pub struct GraphGetNodeResponse { /// The node information. - #[prost(message, optional, tag = "1")] - pub node: ::core::option::Option, + pub node: Option, } diff --git a/ldk-server-protos/src/endpoints.rs b/ldk-server-json-models/src/endpoints.rs similarity index 98% rename from ldk-server-protos/src/endpoints.rs rename to ldk-server-json-models/src/endpoints.rs index c6818dee..204216d7 100644 --- a/ldk-server-protos/src/endpoints.rs +++ b/ldk-server-json-models/src/endpoints.rs @@ -43,3 +43,4 @@ 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"; +pub const SUBSCRIBE_PATH: &str = "Subscribe"; diff --git a/ldk-server-json-models/src/error.rs b/ldk-server-json-models/src/error.rs new file mode 100644 index 00000000..b3fa768a --- /dev/null +++ b/ldk-server-json-models/src/error.rs @@ -0,0 +1,45 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; + +/// When HttpStatusCode is not ok (200), the response `content` contains a serialized `ErrorResponse` +/// with the relevant ErrorCode and `message` +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct ErrorResponse { + /// The error message containing a generic description of the error condition in English. + /// It is intended for a human audience only and should not be parsed to extract any information + /// programmatically. Client-side code may use it for logging only. + pub message: String, + /// The error code uniquely identifying an error condition. + /// It is meant to be read and understood programmatically by code that detects/handles errors by + /// type. + pub error_code: ErrorCode, +} + +#[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, ToSchema, +)] +pub enum ErrorCode { + /// Will never be used as `error_code` by server. + UnknownError, + /// Used in the following cases: + /// - The request was missing a required argument. + /// - The specified argument was invalid, incomplete or in the wrong format. + /// - The request body of api cannot be deserialized. + /// - The request does not follow api contract. + InvalidRequestError, + /// Used when authentication fails or in case of an unauthorized request. + AuthError, + /// Used to represent an error while doing a Lightning operation. + LightningError, + /// Used when an internal server error occurred. The client is probably at no fault. + InternalServerError, +} diff --git a/ldk-server-json-models/src/events.rs b/ldk-server-json-models/src/events.rs new file mode 100644 index 00000000..3a0ca29c --- /dev/null +++ b/ldk-server-json-models/src/events.rs @@ -0,0 +1,60 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; + +/// An event emitted by the LDK Server to notify consumers of payment lifecycle changes. +/// +/// Events are published to the configured messaging system (e.g., RabbitMQ) as JSON. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum Event { + PaymentReceived(PaymentReceived), + PaymentSuccessful(PaymentSuccessful), + PaymentFailed(PaymentFailed), + PaymentForwarded(PaymentForwarded), + PaymentClaimable(PaymentClaimable), +} + +/// PaymentReceived indicates a payment has been received. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct PaymentReceived { + /// The payment details for the received payment. + pub payment: super::types::Payment, +} + +/// PaymentSuccessful indicates a sent payment was successful. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct PaymentSuccessful { + /// The payment details for the successful payment. + pub payment: super::types::Payment, +} + +/// PaymentFailed indicates a sent payment has failed. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct PaymentFailed { + /// The payment details for the failed payment. + pub payment: super::types::Payment, +} + +/// PaymentClaimable indicates a payment has arrived and is waiting to be manually claimed or failed. +/// This event is only emitted for payments created via `Bolt11ReceiveForHash`. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct PaymentClaimable { + /// The payment details for the claimable payment. + pub payment: super::types::Payment, +} + +/// PaymentForwarded indicates a payment was forwarded through the node. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct PaymentForwarded { + /// The forwarded payment details. + pub forwarded_payment: super::types::ForwardedPayment, +} diff --git a/ldk-server-protos/src/lib.rs b/ldk-server-json-models/src/lib.rs similarity index 95% rename from ldk-server-protos/src/lib.rs rename to ldk-server-json-models/src/lib.rs index f76f2f73..9b8bed3d 100644 --- a/ldk-server-protos/src/lib.rs +++ b/ldk-server-json-models/src/lib.rs @@ -11,6 +11,5 @@ pub mod api; pub mod endpoints; pub mod error; pub mod events; -#[cfg(feature = "serde")] pub mod serde_utils; pub mod types; diff --git a/ldk-server-json-models/src/serde_utils.rs b/ldk-server-json-models/src/serde_utils.rs new file mode 100644 index 00000000..5fb88ebe --- /dev/null +++ b/ldk-server-json-models/src/serde_utils.rs @@ -0,0 +1,143 @@ +// 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. + +//! Custom serde serializers/deserializers for byte fields. +//! +//! These are used via `#[serde(with = "...")]` attributes on fields to produce +//! human-readable hex output for byte data. + +use std::fmt::Write; + +use serde::{Deserialize, Deserializer, Serializer}; + +/// Module for serializing/deserializing `Vec` as a hex string. +pub mod bytes_hex { + use super::*; + + pub fn serialize(value: &[u8], serializer: S) -> Result + where + S: Serializer, + { + let hex = value.iter().fold(String::with_capacity(value.len() * 2), |mut acc, b| { + let _ = write!(acc, "{b:02x}"); + acc + }); + serializer.serialize_str(&hex) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let hex = String::deserialize(deserializer)?; + hex_to_bytes(&hex).map_err(serde::de::Error::custom) + } +} + +/// Module for serializing/deserializing `[u8; 32]` as a hex string. +pub mod hex_32 { + use super::*; + + pub fn serialize(value: &[u8; 32], serializer: S) -> Result + where + S: Serializer, + { + let hex = value.iter().fold(String::with_capacity(64), |mut acc, b| { + let _ = write!(acc, "{b:02x}"); + acc + }); + serializer.serialize_str(&hex) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error> + where + D: Deserializer<'de>, + { + let hex = String::deserialize(deserializer)?; + hex_to_32_bytes(&hex).map_err(serde::de::Error::custom) + } +} + +/// Module for serializing/deserializing `Option<[u8; 32]>` as a hex string (or null). +pub mod opt_hex_32 { + use super::*; + + pub fn serialize(value: &Option<[u8; 32]>, serializer: S) -> Result + where + S: Serializer, + { + match value { + Some(bytes) => { + let hex = bytes.iter().fold(String::with_capacity(64), |mut acc, b| { + let _ = write!(acc, "{b:02x}"); + acc + }); + serializer.serialize_some(&hex) + }, + None => serializer.serialize_none(), + } + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let opt: Option = Option::deserialize(deserializer)?; + match opt { + Some(hex) => { + let bytes = hex_to_32_bytes(&hex).map_err(serde::de::Error::custom)?; + Ok(Some(bytes)) + }, + None => Ok(None), + } + } +} + +fn hex_to_bytes(hex: &str) -> Result, String> { + if hex.len() % 2 != 0 { + return Err("Hex string must have even length".to_string()); + } + (0..hex.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&hex[i..i + 2], 16).map_err(|e| e.to_string())) + .collect() +} + +/// Module for serializing/deserializing `[u8; 33]` as a hex string. +pub mod hex_33 { + use super::*; + + pub fn serialize(value: &[u8; 33], serializer: S) -> Result + where + S: Serializer, + { + let hex = value.iter().fold(String::with_capacity(66), |mut acc, b| { + let _ = write!(acc, "{b:02x}"); + acc + }); + serializer.serialize_str(&hex) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; 33], D::Error> + where + D: Deserializer<'de>, + { + let hex = String::deserialize(deserializer)?; + hex_to_fixed::<33>(&hex).map_err(serde::de::Error::custom) + } +} + +fn hex_to_fixed(hex: &str) -> Result<[u8; N], String> { + let bytes = hex_to_bytes(hex)?; + bytes.try_into().map_err(|v: Vec| format!("expected {} bytes, got {}", N, v.len())) +} + +fn hex_to_32_bytes(hex: &str) -> Result<[u8; 32], String> { + hex_to_fixed::<32>(hex) +} diff --git a/ldk-server-json-models/src/types.rs b/ldk-server-json-models/src/types.rs new file mode 100644 index 00000000..a408bc03 --- /dev/null +++ b/ldk-server-json-models/src/types.rs @@ -0,0 +1,814 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; + +/// Represents a payment. +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct Payment { + /// An identifier used to uniquely identify a payment in hex-encoded form. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub id: [u8; 32], + /// The kind of the payment. + pub kind: PaymentKind, + /// The amount transferred. + pub amount_msat: Option, + /// The fees that were paid for this payment. + /// + /// For Lightning payments, this will only be updated for outbound payments once they + /// succeeded. + pub fee_paid_msat: Option, + /// The direction of the payment. + pub direction: PaymentDirection, + /// The status of the payment. + pub status: PaymentStatus, + /// The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. + pub latest_update_timestamp: u64, +} +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum PaymentKind { + Onchain(Onchain), + Bolt11(Bolt11), + Bolt11Jit(Bolt11Jit), + Bolt12Offer(Bolt12Offer), + Bolt12Refund(Bolt12Refund), + Spontaneous(Spontaneous), +} +/// Represents an on-chain payment. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct Onchain { + /// The transaction identifier of this payment. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub txid: [u8; 32], + /// The confirmation status of this payment. + pub status: ConfirmationStatus, +} +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum ConfirmationStatus { + Confirmed(Confirmed), + Unconfirmed(Unconfirmed), +} +/// The on-chain transaction is confirmed in the best chain. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct Confirmed { + /// The hex representation of hash of the block in which the transaction was confirmed. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub block_hash: [u8; 32], + /// The height under which the block was confirmed. + pub height: u32, + /// The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. + pub timestamp: u64, +} +/// The on-chain transaction is unconfirmed. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct Unconfirmed {} +/// Represents a BOLT 11 payment. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct Bolt11 { + /// The payment hash, i.e., the hash of the preimage. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub hash: [u8; 32], + /// The pre-image used by the payment. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub preimage: Option<[u8; 32]>, + /// The secret used by the payment. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub secret: Option<[u8; 32]>, +} +/// Represents a BOLT 11 payment intended to open an LSPS 2 just-in-time channel. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct Bolt11Jit { + /// The payment hash, i.e., the hash of the preimage. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub hash: [u8; 32], + /// The pre-image used by the payment. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub preimage: Option<[u8; 32]>, + /// The secret used by the payment. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub secret: Option<[u8; 32]>, + /// Limits applying to how much fee we allow an LSP to deduct from the payment amount. + /// + /// Allowing them to deduct this fee from the first inbound payment will pay for the LSP's channel opening fees. + /// + /// See \[`LdkChannelConfig::accept_underpaying_htlcs`\]() + /// for more information. + pub lsp_fee_limits: Option, + /// The value, in thousands of a satoshi, that was deducted from this payment as an extra + /// fee taken by our channel counterparty. + /// + /// Will only be `Some` once we received the payment. + pub counterparty_skimmed_fee_msat: Option, +} +/// Represents a BOLT 12 'offer' payment, i.e., a payment for an Offer. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct Bolt12Offer { + /// The payment hash, i.e., the hash of the preimage. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub hash: Option<[u8; 32]>, + /// The pre-image used by the payment. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub preimage: Option<[u8; 32]>, + /// The secret used by the payment. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub secret: Option<[u8; 32]>, + /// The hex-encoded ID of the offer this payment is for. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub offer_id: [u8; 32], + /// The payer's note for the payment. + /// Truncated to \[PAYER_NOTE_LIMIT\](). + /// + /// **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, + /// all non-printable characters will be sanitized and replaced with safe characters. + pub payer_note: Option, + /// The quantity of an item requested in the offer. + pub quantity: Option, +} +/// Represents a BOLT 12 'refund' payment, i.e., a payment for a Refund. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct Bolt12Refund { + /// The payment hash, i.e., the hash of the preimage. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub hash: Option<[u8; 32]>, + /// The pre-image used by the payment. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub preimage: Option<[u8; 32]>, + /// The secret used by the payment. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub secret: Option<[u8; 32]>, + /// The payer's note for the payment. + /// Truncated to \[PAYER_NOTE_LIMIT\](). + /// + /// **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, + /// all non-printable characters will be sanitized and replaced with safe characters. + pub payer_note: Option, + /// The quantity of an item requested in the offer. + pub quantity: Option, +} +/// Represents a spontaneous ("keysend") payment. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct Spontaneous { + /// The payment hash, i.e., the hash of the preimage. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub hash: [u8; 32], + /// The pre-image used by the payment. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub preimage: Option<[u8; 32]>, +} +/// Limits applying to how much fee we allow an LSP to deduct from the payment amount. +/// See \[`LdkChannelConfig::accept_underpaying_htlcs`\] for more information. +/// +/// \[`LdkChannelConfig::accept_underpaying_htlcs`\]: lightning::util::config::ChannelConfig::accept_underpaying_htlcs +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct LspFeeLimits { + /// The maximal total amount we allow any configured LSP withhold from us when forwarding the + /// payment. + pub max_total_opening_fee_msat: Option, + /// The maximal proportional fee, in parts-per-million millisatoshi, we allow any configured + /// LSP withhold from us when forwarding the payment. + pub max_proportional_opening_fee_ppm_msat: Option, +} +/// A forwarded payment through our node. +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct ForwardedPayment { + /// The channel id of the incoming channel between the previous node and us. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub prev_channel_id: [u8; 32], + /// The channel id of the outgoing channel between the next node and us. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub next_channel_id: [u8; 32], + /// The `user_channel_id` of the incoming channel between the previous node and us. + pub prev_user_channel_id: String, + /// The node id of the previous node. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub prev_node_id: [u8; 33], + /// The node id of the next node. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub next_node_id: [u8; 33], + /// The `user_channel_id` of the outgoing channel between the next node and us. + /// This will be `None` if the payment was settled via an on-chain transaction. + /// See the caveat described for the `total_fee_earned_msat` field. + pub next_user_channel_id: Option, + /// The total fee, in milli-satoshis, which was earned as a result of the payment. + /// + /// Note that if we force-closed the channel over which we forwarded an HTLC while the HTLC was pending, the amount the + /// next hop claimed will have been rounded down to the nearest whole satoshi. Thus, the fee calculated here may be + /// higher than expected as we still claimed the full value in millisatoshis from the source. + /// In this case, `claim_from_onchain_tx` will be set. + /// + /// If the channel which sent us the payment has been force-closed, we will claim the funds via an on-chain transaction. + /// In that case we do not yet know the on-chain transaction fees which we will spend and will instead set this to `None`. + pub total_fee_earned_msat: Option, + /// The share of the total fee, in milli-satoshis, which was withheld in addition to the forwarding fee. + /// This will only be set if we forwarded an intercepted HTLC with less than the expected amount. This means our + /// counterparty accepted to receive less than the invoice amount. + /// + /// The caveat described above the `total_fee_earned_msat` field applies here as well. + pub skimmed_fee_msat: Option, + /// If this is true, the forwarded HTLC was claimed by our counterparty via an on-chain transaction. + pub claim_from_onchain_tx: bool, + /// The final amount forwarded, in milli-satoshis, after the fee is deducted. + /// + /// The caveat described above the `total_fee_earned_msat` field applies here as well. + pub outbound_amount_forwarded_msat: Option, +} +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct Channel { + /// The channel ID (prior to funding transaction generation, this is a random 32-byte + /// identifier, afterwards this is the transaction ID of the funding transaction XOR the + /// funding transaction output). + /// + /// Note that this means this value is *not* persistent - it can change once during the + /// lifetime of the channel. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub channel_id: [u8; 32], + /// The node ID of our the channel's remote counterparty. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub counterparty_node_id: [u8; 33], + /// The channel's funding transaction output, if we've negotiated the funding transaction with + /// our counterparty already. + pub funding_txo: Option, + /// The hex-encoded local `user_channel_id` of this channel. + pub user_channel_id: String, + /// The value, in satoshis, that must always be held as a reserve in the channel for us. This + /// value ensures that if we broadcast a revoked state, our counterparty can punish us by + /// claiming at least this value on chain. + /// + /// This value is not included in \[`outbound_capacity_msat`\] as it can never be spent. + /// + /// This value will be `None` for outbound channels until the counterparty accepts the channel. + pub unspendable_punishment_reserve: Option, + /// The value, in satoshis, of this channel as it appears in the funding output. + pub channel_value_sats: u64, + /// The currently negotiated fee rate denominated in satoshi per 1000 weight units, + /// which is applied to commitment and HTLC transactions. + pub feerate_sat_per_1000_weight: u32, + /// The available outbound capacity for sending HTLCs to the remote peer. + /// + /// The amount does not include any pending HTLCs which are not yet resolved (and, thus, whose + /// balance is not available for inclusion in new outbound HTLCs). This further does not include + /// any pending outgoing HTLCs which are awaiting some other resolution to be sent. + pub outbound_capacity_msat: u64, + /// The available outbound capacity for sending HTLCs to the remote peer. + /// + /// The amount does not include any pending HTLCs which are not yet resolved + /// (and, thus, whose balance is not available for inclusion in new inbound HTLCs). This further + /// does not include any pending outgoing HTLCs which are awaiting some other resolution to be + /// sent. + pub inbound_capacity_msat: u64, + /// The number of required confirmations on the funding transactions before the funding is + /// considered "locked". The amount is selected by the channel fundee. + /// + /// The value will be `None` for outbound channels until the counterparty accepts the channel. + pub confirmations_required: Option, + /// The current number of confirmations on the funding transaction. + pub confirmations: Option, + /// Is `true` if the channel was initiated (and therefore funded) by us. + pub is_outbound: bool, + /// Is `true` if both parties have exchanged `channel_ready` messages, and the channel is + /// not currently being shut down. Both parties exchange `channel_ready` messages upon + /// independently verifying that the required confirmations count provided by + /// `confirmations_required` has been reached. + pub is_channel_ready: bool, + /// Is `true` if the channel (a) `channel_ready` messages have been exchanged, (b) the + /// peer is connected, and (c) the channel is not currently negotiating shutdown. + /// + /// This is a strict superset of `is_channel_ready`. + pub is_usable: bool, + /// Is `true` if this channel is (or will be) publicly-announced + pub is_announced: bool, + /// Set of configurable parameters set by self that affect channel operation. + pub channel_config: Option, + /// The available outbound capacity for sending a single HTLC to the remote peer. This is + /// similar to `outbound_capacity_msat` but it may be further restricted by + /// the current state and per-HTLC limit(s). This is intended for use when routing, allowing us + /// to use a limit as close as possible to the HTLC limit we can currently send. + pub next_outbound_htlc_limit_msat: u64, + /// The minimum value for sending a single HTLC to the remote peer. This is the equivalent of + /// `next_outbound_htlc_limit_msat` but represents a lower-bound, rather than + /// an upper-bound. This is intended for use when routing, allowing us to ensure we pick a + /// route which is valid. + pub next_outbound_htlc_minimum_msat: u64, + /// The number of blocks (after our commitment transaction confirms) that we will need to wait + /// until we can claim our funds after we force-close the channel. During this time our + /// counterparty is allowed to punish us if we broadcasted a stale state. If our counterparty + /// force-closes the channel and broadcasts a commitment transaction we do not have to wait any + /// time to claim our non-HTLC-encumbered funds. + /// + /// This value will be `None` for outbound channels until the counterparty accepts the channel. + pub force_close_spend_delay: Option, + /// The smallest value HTLC (in msat) the remote peer will accept, for this channel. + /// + /// This field is only `None` before we have received either the `OpenChannel` or + /// `AcceptChannel` message from the remote peer. + pub counterparty_outbound_htlc_minimum_msat: Option, + /// The largest value HTLC (in msat) the remote peer currently will accept, for this channel. + pub counterparty_outbound_htlc_maximum_msat: Option, + /// The value, in satoshis, that must always be held in the channel for our counterparty. This + /// value ensures that if our counterparty broadcasts a revoked state, we can punish them by + /// claiming at least this value on chain. + /// + /// This value is not included in `inbound_capacity_msat` as it can never be spent. + pub counterparty_unspendable_punishment_reserve: u64, + /// Base routing fee in millisatoshis. + pub counterparty_forwarding_info_fee_base_msat: Option, + /// Proportional fee, in millionths of a satoshi the channel will charge per transferred satoshi. + pub counterparty_forwarding_info_fee_proportional_millionths: Option, + /// The minimum difference in CLTV expiry between an ingoing HTLC and its outgoing counterpart, + /// such that the outgoing HTLC is forwardable to this counterparty. + pub counterparty_forwarding_info_cltv_expiry_delta: Option, +} +/// ChannelConfig represents the configuration settings for a channel in a Lightning Network node. +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct ChannelConfig { + /// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound + /// over the channel. + /// See more: + pub forwarding_fee_proportional_millionths: Option, + /// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, + /// in excess of forwarding_fee_proportional_millionths. + /// See more: + pub forwarding_fee_base_msat: Option, + /// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded + /// over the channel this config applies to. + /// See more: + pub cltv_expiry_delta: Option, + /// The maximum additional fee we're willing to pay to avoid waiting for the counterparty's + /// to_self_delay to reclaim funds. + /// See more: + pub force_close_avoidance_max_fee_satoshis: Option, + /// If set, allows this channel's counterparty to skim an additional fee off this node's + /// inbound HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users. + /// See more: + pub accept_underpaying_htlcs: Option, + /// Limit our total exposure to potential loss to on-chain fees on close, including + /// in-flight HTLCs which are burned to fees as they are too small to claim on-chain + /// and fees on commitment transaction(s) broadcasted by our counterparty in excess of + /// our own fee estimate. + /// See more: + pub max_dust_htlc_exposure: Option, +} +/// Limit our total exposure to potential loss to on-chain fees on close, including +/// in-flight HTLCs which are burned to fees as they are too small to claim on-chain +/// and fees on commitment transaction(s) broadcasted by our counterparty in excess of +/// our own fee estimate. +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum MaxDustHtlcExposure { + /// This sets a fixed limit on the total dust exposure in millisatoshis. + /// See more: + FixedLimitMsat(u64), + /// This sets a multiplier on the ConfirmationTarget::OnChainSweep feerate (in sats/KW) to determine the maximum allowed dust exposure. + /// See more: + FeeRateMultiplier(u64), +} +/// Represent a transaction outpoint. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct OutPoint { + /// The referenced transaction's txid. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub txid: [u8; 32], + /// The index of the referenced output in its transaction's vout. + pub vout: u32, +} +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct BestBlock { + /// The block's hash + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub block_hash: [u8; 32], + /// The height at which the block was confirmed. + pub height: u32, +} +/// Details about the status of a known Lightning balance. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum LightningBalance { + ClaimableOnChannelClose(ClaimableOnChannelClose), + ClaimableAwaitingConfirmations(ClaimableAwaitingConfirmations), + ContentiousClaimable(ContentiousClaimable), + MaybeTimeoutClaimableHtlc(MaybeTimeoutClaimableHtlc), + MaybePreimageClaimableHtlc(MaybePreimageClaimableHtlc), + CounterpartyRevokedOutputClaimable(CounterpartyRevokedOutputClaimable), +} +/// The channel is not yet closed (or the commitment or closing transaction has not yet appeared in a block). +/// The given balance is claimable (less on-chain fees) if the channel is force-closed now. +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct ClaimableOnChannelClose { + /// The identifier of the channel this balance belongs to. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub channel_id: [u8; 32], + /// The identifier of our channel counterparty. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub counterparty_node_id: [u8; 33], + /// The amount available to claim, in satoshis, excluding the on-chain fees which will be required to do so. + pub amount_satoshis: u64, + /// The transaction fee we pay for the closing commitment transaction. + /// This amount is not included in the `amount_satoshis` value. + /// + /// Note that if this channel is inbound (and thus our counterparty pays the commitment transaction fee) this value + /// will be zero. + pub transaction_fee_satoshis: u64, + /// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound from us and are related to + /// a payment which was sent by us. This is the sum of the millisatoshis part of all HTLCs which are otherwise + /// represented by `LightningBalance::MaybeTimeoutClaimableHTLC` with their + /// `LightningBalance::MaybeTimeoutClaimableHTLC::outbound_payment` flag set, as well as any dust HTLCs which would + /// otherwise be represented the same. + /// + /// This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. + pub outbound_payment_htlc_rounded_msat: u64, + /// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound from us and are related to + /// a forwarded HTLC. This is the sum of the millisatoshis part of all HTLCs which are otherwise represented by + /// `LightningBalance::MaybeTimeoutClaimableHTLC` with their `LightningBalance::MaybeTimeoutClaimableHTLC::outbound_payment` + /// flag not set, as well as any dust HTLCs which would otherwise be represented the same. + /// + /// This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. + pub outbound_forwarded_htlc_rounded_msat: u64, + /// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound to us and for which we know + /// the preimage. This is the sum of the millisatoshis part of all HTLCs which would be represented by + /// `LightningBalance::ContentiousClaimable` on channel close, but whose current value is included in `amount_satoshis`, + /// as well as any dust HTLCs which would otherwise be represented the same. + /// + /// This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. + pub inbound_claiming_htlc_rounded_msat: u64, + /// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound to us and for which we do + /// not know the preimage. This is the sum of the millisatoshis part of all HTLCs which would be represented by + /// `LightningBalance::MaybePreimageClaimableHTLC` on channel close, as well as any dust HTLCs which would otherwise be + /// represented the same. + /// + /// This amount (rounded up to a whole satoshi value) will not be included in the counterparty's `amount_satoshis`. + pub inbound_htlc_rounded_msat: u64, +} +/// The channel has been closed, and the given balance is ours but awaiting confirmations until we consider it spendable. +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct ClaimableAwaitingConfirmations { + /// The identifier of the channel this balance belongs to. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub channel_id: [u8; 32], + /// The identifier of our channel counterparty. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub counterparty_node_id: [u8; 33], + /// The amount available to claim, in satoshis, possibly excluding the on-chain fees which were spent in broadcasting + /// the transaction. + pub amount_satoshis: u64, + /// The height at which we start tracking it as `SpendableOutput`. + pub confirmation_height: u32, + /// Whether this balance is a result of cooperative close, a force-close, or an HTLC. + pub source: BalanceSource, +} +/// The channel has been closed, and the given balance should be ours but awaiting spending transaction confirmation. +/// If the spending transaction does not confirm in time, it is possible our counterparty can take the funds by +/// broadcasting an HTLC timeout on-chain. +/// +/// Once the spending transaction confirms, before it has reached enough confirmations to be considered safe from chain +/// reorganizations, the balance will instead be provided via `LightningBalance::ClaimableAwaitingConfirmations`. +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct ContentiousClaimable { + /// The identifier of the channel this balance belongs to. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub channel_id: [u8; 32], + /// The identifier of our channel counterparty. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub counterparty_node_id: [u8; 33], + /// The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting + /// the transaction. + pub amount_satoshis: u64, + /// The height at which the counterparty may be able to claim the balance if we have not done so. + pub timeout_height: u32, + /// The payment hash that locks this HTLC. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub payment_hash: [u8; 32], + /// The preimage that can be used to claim this HTLC. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub payment_preimage: [u8; 32], +} +/// HTLCs which we sent to our counterparty which are claimable after a timeout (less on-chain fees) if the counterparty +/// does not know the preimage for the HTLCs. These are somewhat likely to be claimed by our counterparty before we do. +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct MaybeTimeoutClaimableHtlc { + /// The identifier of the channel this balance belongs to. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub channel_id: [u8; 32], + /// The identifier of our channel counterparty. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub counterparty_node_id: [u8; 33], + /// The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting + /// the transaction. + pub amount_satoshis: u64, + /// The height at which we will be able to claim the balance if our counterparty has not done so. + pub claimable_height: u32, + /// The payment hash whose preimage our counterparty needs to claim this HTLC. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub payment_hash: [u8; 32], + /// Indicates whether this HTLC represents a payment which was sent outbound from us. + pub outbound_payment: bool, +} +/// HTLCs which we received from our counterparty which are claimable with a preimage which we do not currently have. +/// This will only be claimable if we receive the preimage from the node to which we forwarded this HTLC before the +/// timeout. +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct MaybePreimageClaimableHtlc { + /// The identifier of the channel this balance belongs to. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub channel_id: [u8; 32], + /// The identifier of our channel counterparty. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub counterparty_node_id: [u8; 33], + /// The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting + /// the transaction. + pub amount_satoshis: u64, + /// The height at which our counterparty will be able to claim the balance if we have not yet received the preimage and + /// claimed it ourselves. + pub expiry_height: u32, + /// The payment hash whose preimage we need to claim this HTLC. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub payment_hash: [u8; 32], +} +/// The channel has been closed, and our counterparty broadcasted a revoked commitment transaction. +/// +/// Thus, we're able to claim all outputs in the commitment transaction, one of which has the following amount. +/// +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct CounterpartyRevokedOutputClaimable { + /// The identifier of the channel this balance belongs to. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub channel_id: [u8; 32], + /// The identifier of our channel counterparty. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub counterparty_node_id: [u8; 33], + /// The amount, in satoshis, of the output which we can claim. + pub amount_satoshis: u64, +} +/// Details about the status of a known balance currently being swept to our on-chain wallet. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum PendingSweepBalance { + PendingBroadcast(PendingBroadcast), + BroadcastAwaitingConfirmation(BroadcastAwaitingConfirmation), + AwaitingThresholdConfirmations(AwaitingThresholdConfirmations), +} +/// The spendable output is about to be swept, but a spending transaction has yet to be generated and broadcast. +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct PendingBroadcast { + /// The identifier of the channel this balance belongs to. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub channel_id: Option<[u8; 32]>, + /// The amount, in satoshis, of the output being swept. + pub amount_satoshis: u64, +} +/// A spending transaction has been generated and broadcast and is awaiting confirmation on-chain. +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct BroadcastAwaitingConfirmation { + /// The identifier of the channel this balance belongs to. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub channel_id: Option<[u8; 32]>, + /// The best height when we last broadcast a transaction spending the output being swept. + pub latest_broadcast_height: u32, + /// The identifier of the transaction spending the swept output we last broadcast. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub latest_spending_txid: [u8; 32], + /// The amount, in satoshis, of the output being swept. + pub amount_satoshis: u64, +} +/// A spending transaction has been confirmed on-chain and is awaiting threshold confirmations. +/// +/// It will be considered irrevocably confirmed after reaching `ANTI_REORG_DELAY`. +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct AwaitingThresholdConfirmations { + /// The identifier of the channel this balance belongs to. + #[schema(value_type = Option)] + #[serde(default, with = "crate::serde_utils::opt_hex_32")] + pub channel_id: Option<[u8; 32]>, + /// The identifier of the confirmed transaction spending the swept output. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub latest_spending_txid: [u8; 32], + /// The hash of the block in which the spending transaction was confirmed. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_32")] + pub confirmation_hash: [u8; 32], + /// The height at which the spending transaction was confirmed. + pub confirmation_height: u32, + /// The amount, in satoshis, of the output being swept. + pub amount_satoshis: u64, +} +/// Token used to determine start of next page in paginated APIs. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct PageToken { + pub token: String, + pub index: i64, +} +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum Bolt11InvoiceDescription { + Direct(String), + Hash(String), +} +/// Configuration options for payment routing and pathfinding. +/// See for more details on each field. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct RouteParametersConfig { + /// The maximum total fees, in millisatoshi, that may accrue during route finding. + /// Defaults to 1% of the payment amount + 50 sats + pub max_total_routing_fee_msat: Option, + /// The maximum total CLTV delta we accept for the route. + /// Defaults to 1008. + pub max_total_cltv_expiry_delta: u32, + /// The maximum number of paths that may be used by (MPP) payments. + /// Defaults to 10. + pub max_path_count: u32, + /// Selects the maximum share of a channel's total capacity which will be + /// sent over a channel, as a power of 1/2. + /// Default value: 2 + pub max_channel_saturation_power_of_half: u32, +} +/// Routing fees for a channel as part of the network graph. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct GraphRoutingFees { + /// Flat routing fee in millisatoshis. + pub base_msat: u32, + /// Liquidity-based routing fee in millionths of a routed amount. + pub proportional_millionths: u32, +} +/// Details about one direction of a channel in the network graph, +/// as received within a `ChannelUpdate`. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct GraphChannelUpdate { + /// When the last update to the channel direction was issued. + /// Value is opaque, as set in the announcement. + pub last_update: u32, + /// Whether the channel can be currently used for payments (in this one direction). + pub enabled: bool, + /// The difference in CLTV values that you must have when routing through this channel. + pub cltv_expiry_delta: u32, + /// The minimum value, which must be relayed to the next hop via the channel. + pub htlc_minimum_msat: u64, + /// The maximum value which may be relayed to the next hop via the channel. + pub htlc_maximum_msat: u64, + /// Fees charged when the channel is used for routing. + pub fees: GraphRoutingFees, +} +/// Details about a channel in the network graph (both directions). +/// Received within a channel announcement. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct GraphChannel { + /// Source node of the first direction of the channel (hex-encoded public key). + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub node_one: [u8; 33], + /// Source node of the second direction of the channel (hex-encoded public key). + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub node_two: [u8; 33], + /// The channel capacity as seen on-chain, if chain lookup is available. + pub capacity_sats: Option, + /// Details about the first direction of a channel. + pub one_to_two: Option, + /// Details about the second direction of a channel. + pub two_to_one: Option, +} +/// Information received in the latest node_announcement from this node. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct GraphNodeAnnouncement { + /// When the last known update to the node state was issued. + /// Value is opaque, as set in the announcement. + pub last_update: u32, + /// Moniker assigned to the node. + /// May be invalid or malicious (eg control chars), should not be exposed to the user. + pub alias: String, + /// Color assigned to the node as a hex-encoded RGB string, e.g. "ff0000". + pub rgb: String, + /// List of addresses on which this node is reachable. + pub addresses: Vec, +} +/// Details of a known Lightning peer. +/// See more: +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct Peer { + /// The hex-encoded node ID of the peer. + #[schema(value_type = String)] + #[serde(with = "crate::serde_utils::hex_33")] + pub node_id: [u8; 33], + /// The network address of the peer. + pub address: String, + /// Indicates whether we'll try to reconnect to this peer after restarts. + pub is_persisted: bool, + /// Indicates whether we currently have an active connection with the peer. + pub is_connected: bool, +} +/// Details about a node in the network graph, known from the network announcement. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)] +pub struct GraphNode { + /// All valid channels a node has announced. + pub channels: Vec, + /// More information about a node from node_announcement. + /// Optional because we store a node entry after learning about it from + /// a channel announcement, but before receiving a node announcement. + pub announcement_info: Option, +} +/// Represents the direction of a payment. +#[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, ToSchema, +)] +#[serde(rename_all = "snake_case")] +pub enum PaymentDirection { + /// The payment is inbound. + Inbound, + /// The payment is outbound. + Outbound, +} +/// Represents the current status of a payment. +#[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, ToSchema, +)] +#[serde(rename_all = "snake_case")] +pub enum PaymentStatus { + /// The payment is still pending. + Pending, + /// The payment succeeded. + Succeeded, + /// The payment failed. + Failed, +} +/// Indicates whether the balance is derived from a cooperative close, a force-close (for holder or counterparty), +/// or whether it is for an HTLC. +#[derive( + Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, ToSchema, +)] +#[serde(rename_all = "snake_case")] +pub enum BalanceSource { + /// The channel was force closed by the holder. + HolderForceClosed, + /// The channel was force closed by the counterparty. + CounterpartyForceClosed, + /// The channel was cooperatively closed. + CoopClose, + /// This balance is the result of an HTLC. + Htlc, +} diff --git a/ldk-server-protos/Cargo.toml b/ldk-server-protos/Cargo.toml deleted file mode 100644 index c971d6f5..00000000 --- a/ldk-server-protos/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "ldk-server-protos" -version = "0.1.0" -edition = "2021" - -build = "build.rs" - -# We use a cfg instead of a feature for genproto to prevent it from being -# enabled with --all-features. Proto generation is a developer-only tool that -# requires external dependencies (protoc) and shouldn't be triggered accidentally. -# This lint configuration tells Cargo that genproto is an expected custom cfg. -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(genproto)'] } - -[features] -default = [] -serde = ["dep:serde", "dep:bytes"] - -[dependencies] -prost = { version = "0.11.6", default-features = false, features = ["std", "prost-derive"] } -serde = { version = "1.0", features = ["derive"], optional = true } -bytes = { version = "1", features = ["serde"], optional = true } - -[target.'cfg(genproto)'.build-dependencies] -prost-build = { version = "0.11.6", default-features = false } diff --git a/ldk-server-protos/build.rs b/ldk-server-protos/build.rs deleted file mode 100644 index 13e54d53..00000000 --- a/ldk-server-protos/build.rs +++ /dev/null @@ -1,95 +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. - -#[cfg(genproto)] -extern crate prost_build; - -#[cfg(genproto)] -use std::{env, fs, io::Write, path::Path}; - -#[cfg(genproto)] -const COPYRIGHT_HEADER: &str = - "// 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. - -"; - -/// To generate updated proto objects, run `RUSTFLAGS="--cfg genproto" cargo build` -fn main() { - #[cfg(genproto)] - generate_protos(); -} - -#[cfg(genproto)] -fn generate_protos() { - prost_build::Config::new() - .bytes(&["."]) - .type_attribute( - ".", - "#[cfg_attr(feature = \"serde\", derive(serde::Serialize, serde::Deserialize))]", - ) - .type_attribute(".", "#[cfg_attr(feature = \"serde\", serde(rename_all = \"snake_case\"))]") - .field_attribute( - "types.Bolt11.secret", - "#[cfg_attr(feature = \"serde\", serde(serialize_with = \"crate::serde_utils::serialize_opt_bytes_hex\"))]", - ) - .field_attribute( - "types.Bolt11Jit.secret", - "#[cfg_attr(feature = \"serde\", serde(serialize_with = \"crate::serde_utils::serialize_opt_bytes_hex\"))]", - ) - .field_attribute( - "types.Bolt12Offer.secret", - "#[cfg_attr(feature = \"serde\", serde(serialize_with = \"crate::serde_utils::serialize_opt_bytes_hex\"))]", - ) - .field_attribute( - "types.Bolt12Refund.secret", - "#[cfg_attr(feature = \"serde\", serde(serialize_with = \"crate::serde_utils::serialize_opt_bytes_hex\"))]", - ) - .field_attribute( - "types.Payment.direction", - "#[cfg_attr(feature = \"serde\", serde(serialize_with = \"crate::serde_utils::serialize_payment_direction\"))]", - ) - .field_attribute( - "types.Payment.status", - "#[cfg_attr(feature = \"serde\", serde(serialize_with = \"crate::serde_utils::serialize_payment_status\"))]", - ) - .field_attribute( - "types.ClaimableAwaitingConfirmations.source", - "#[cfg_attr(feature = \"serde\", serde(serialize_with = \"crate::serde_utils::serialize_balance_source\"))]", - ) - .field_attribute( - "api.UnifiedSendResponse.payment_result", - "#[cfg_attr(feature = \"serde\", serde(flatten))]", - ) - .compile_protos( - &[ - "src/proto/api.proto", - "src/proto/types.proto", - "src/proto/events.proto", - "src/proto/error.proto", - ], - &["src/proto/"], - ) - .expect("protobuf compilation failed"); - let out_dir = env::var("OUT_DIR").unwrap(); - println!("OUT_DIR: {}", &out_dir); - for file in &["api.rs", "types.rs", "events.rs", "error.rs"] { - let from_path = Path::new(&out_dir).join(file); - let content = fs::read(&from_path).unwrap(); - let mut dest = fs::File::create(Path::new("src").join(file)).unwrap(); - dest.write_all(COPYRIGHT_HEADER.as_bytes()).unwrap(); - dest.write_all(&content).unwrap(); - } -} diff --git a/ldk-server-protos/src/error.rs b/ldk-server-protos/src/error.rs deleted file mode 100644 index 41e73ee4..00000000 --- a/ldk-server-protos/src/error.rs +++ /dev/null @@ -1,79 +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. - -/// 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. - /// It is intended for a human audience only and should not be parsed to extract any information - /// programmatically. Client-side code may use it for logging only. - #[prost(string, tag = "1")] - pub message: ::prost::alloc::string::String, - /// The error code uniquely identifying an error condition. - /// It is meant to be read and understood programmatically by code that detects/handles errors by - /// type. - /// - /// **Caution**: If a new type of `error_code` is introduced in the `ErrorCode` enum, `error_code` field will be set to - /// `UnknownError`. - #[prost(enumeration = "ErrorCode", tag = "2")] - pub error_code: i32, -} -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum ErrorCode { - /// Will never be used as `error_code` by server. - /// - /// **Caution**: If a new type of `error_code` is introduced in the `ErrorCode` enum, `error_code` field will be set to - /// `UnknownError`. - UnknownError = 0, - /// Used in the following cases: - /// - The request was missing a required argument. - /// - The specified argument was invalid, incomplete or in the wrong format. - /// - The request body of api cannot be deserialized into corresponding protobuf object. - /// - The request does not follow api contract. - InvalidRequestError = 1, - /// Used when authentication fails or in case of an unauthorized request. - AuthError = 2, - /// Used to represent an error while doing a Lightning operation. - LightningError = 3, - /// Used when an internal server error occurred. The client is probably at no fault. - InternalServerError = 4, -} -impl ErrorCode { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - ErrorCode::UnknownError => "UNKNOWN_ERROR", - ErrorCode::InvalidRequestError => "INVALID_REQUEST_ERROR", - ErrorCode::AuthError => "AUTH_ERROR", - ErrorCode::LightningError => "LIGHTNING_ERROR", - ErrorCode::InternalServerError => "INTERNAL_SERVER_ERROR", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNKNOWN_ERROR" => Some(Self::UnknownError), - "INVALID_REQUEST_ERROR" => Some(Self::InvalidRequestError), - "AUTH_ERROR" => Some(Self::AuthError), - "LIGHTNING_ERROR" => Some(Self::LightningError), - "INTERNAL_SERVER_ERROR" => Some(Self::InternalServerError), - _ => None, - } - } -} diff --git a/ldk-server-protos/src/events.rs b/ldk-server-protos/src/events.rs deleted file mode 100644 index a41446aa..00000000 --- a/ldk-server-protos/src/events.rs +++ /dev/null @@ -1,87 +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. - -/// 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")] - pub event: ::core::option::Option, -} -/// Nested message and enum types in `EventEnvelope`. -pub mod event_envelope { - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] - #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Event { - #[prost(message, tag = "2")] - PaymentReceived(super::PaymentReceived), - #[prost(message, tag = "3")] - PaymentSuccessful(super::PaymentSuccessful), - #[prost(message, tag = "4")] - PaymentFailed(super::PaymentFailed), - #[prost(message, tag = "6")] - PaymentForwarded(super::PaymentForwarded), - #[prost(message, tag = "7")] - PaymentClaimable(super::PaymentClaimable), - } -} -/// 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. - #[prost(message, optional, tag = "1")] - pub payment: ::core::option::Option, -} -/// PaymentSuccessful indicates a sent payment was successful. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PaymentSuccessful { - /// The payment details for the payment in event. - #[prost(message, optional, tag = "1")] - pub payment: ::core::option::Option, -} -/// PaymentFailed indicates a sent payment has failed. -#[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. - #[prost(message, optional, tag = "1")] - pub payment: ::core::option::Option, -} -/// PaymentClaimable indicates a payment has arrived and is waiting to be manually claimed or failed. -/// 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. - #[prost(message, optional, tag = "1")] - pub payment: ::core::option::Option, -} -/// PaymentForwarded indicates a payment was forwarded through the node. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PaymentForwarded { - #[prost(message, optional, tag = "1")] - pub forwarded_payment: ::core::option::Option, -} diff --git a/ldk-server-protos/src/proto/api.proto b/ldk-server-protos/src/proto/api.proto deleted file mode 100644 index 3eb505d3..00000000 --- a/ldk-server-protos/src/proto/api.proto +++ /dev/null @@ -1,824 +0,0 @@ -syntax = "proto3"; -package api; - -import 'types.proto'; - -// Retrieve the latest node info like `node_id`, `current_best_block` etc. -// See more: -// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.node_id -// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.status -message GetNodeInfoRequest { -} - -// The response `content` for the `GetNodeInfo` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message GetNodeInfoResponse { - - // The hex-encoded `node-id` or public key for our own lightning node. - string node_id = 1; - - // The best block to which our Lightning wallet is currently synced. - // - // Should be always set, will never be `None`. - types.BestBlock current_best_block = 3; - - // The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our Lightning wallet to - // the chain tip. - // - // Will be `None` if the wallet hasn't been synced yet. - optional uint64 latest_lightning_wallet_sync_timestamp = 4; - - // The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our on-chain - // wallet to the chain tip. - // - // Will be `None` if the wallet hasn’t been synced since the node was initialized. - optional uint64 latest_onchain_wallet_sync_timestamp = 5; - - // The timestamp, in seconds since start of the UNIX epoch, when we last successfully update our fee rate cache. - // - // Will be `None` if the cache hasn’t been updated since the node was initialized. - optional uint64 latest_fee_rate_cache_update_timestamp = 6; - - // The timestamp, in seconds since start of the UNIX epoch, when the last rapid gossip sync (RGS) snapshot we - // successfully applied was generated. - // - // Will be `None` if RGS isn’t configured or the snapshot hasn’t been updated since the node was initialized. - optional uint64 latest_rgs_snapshot_timestamp = 7; - - // The timestamp, in seconds since start of the UNIX epoch, when we last broadcasted a node announcement. - // - // Will be `None` if we have no public channels or we haven’t broadcasted since the node was initialized. - optional uint64 latest_node_announcement_broadcast_timestamp = 8; - - // The addresses the node is currently listening on for incoming connections. - // - // Will be empty if the node is not listening on any addresses. - repeated string listening_addresses = 9; - - // The addresses the node announces to the network. - // - // Will be empty if no announcement addresses are configured. - repeated string announcement_addresses = 10; - - // The node alias, if configured. - // - // Will be `None` if no alias is configured. - optional string node_alias = 11; - - // The node URIs that can be used to connect to this node, in the format `node_id@address`. - // - // These are constructed from the announcement addresses and the node's public key. - // Will be empty if no announcement addresses are configured. - repeated string node_uris = 12; -} - -// Retrieve a new on-chain funding address. -// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.new_address -message OnchainReceiveRequest { -} - -// The response `content` for the `OnchainReceive` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`.. -message OnchainReceiveResponse { - - // A Bitcoin on-chain address. - string address = 1; -} - -// Send an on-chain payment to the given address. -message OnchainSendRequest { - - // The address to send coins to. - string address = 1; - - // The amount in satoshis to send. - // While sending the specified amount, we will respect any on-chain reserve we need to keep, - // i.e., won't allow to cut into `total_anchor_channels_reserve_sats`. - // See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.send_to_address - optional uint64 amount_sats = 2; - - // If set, the amount_sats field should be unset. - // It indicates that node will send full balance to the specified address. - // - // Please note that when send_all is used this operation will **not** retain any on-chain reserves, - // which might be potentially dangerous if you have open Anchor channels for which you can't trust - // the counterparty to spend the Anchor output after channel closure. - // See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.send_all_to_address - optional bool send_all = 3; - - // If `fee_rate_sat_per_vb` is set it will be used on the resulting transaction. Otherwise we'll retrieve - // a reasonable estimate from BitcoinD. - optional uint64 fee_rate_sat_per_vb = 4; -} - -// The response `content` for the `OnchainSend` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message OnchainSendResponse { - - // The transaction ID of the broadcasted transaction. - string txid = 1; -} - -// Return a BOLT11 payable invoice that can be used to request and receive a payment -// for the given amount, if specified. -// The inbound payment will be automatically claimed upon arrival. -// See more: -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.receive -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.receive_variable_amount -message Bolt11ReceiveRequest { - - // The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount invoice is returned. - optional uint64 amount_msat = 1; - - // An optional description to attach along with the invoice. - // Will be set in the description field of the encoded payment request. - types.Bolt11InvoiceDescription description = 2; - - // Invoice expiry time in seconds. - uint32 expiry_secs = 3; -} - -// The response `content` for the `Bolt11Receive` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message Bolt11ReceiveResponse { - - // An invoice for a payment within the Lightning Network. - // With the details of the invoice, the sender has all the data necessary to send a payment - // to the recipient. - string invoice = 1; - - // The hex-encoded 32-byte payment hash. - string payment_hash = 2; - - // The hex-encoded 32-byte payment secret. - string payment_secret = 3; -} - -// Return a BOLT11 payable invoice for a given payment hash. -// The inbound payment will NOT be automatically claimed upon arrival. -// Instead, the payment will need to be manually claimed by calling `Bolt11ClaimForHash` -// or manually failed by calling `Bolt11FailForHash`. -// See more: -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.receive_for_hash -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.receive_variable_amount_for_hash -message Bolt11ReceiveForHashRequest { - - // The amount in millisatoshi to receive. If unset, a "zero-amount" or variable-amount invoice is returned. - optional uint64 amount_msat = 1; - - // An optional description to attach along with the invoice. - // Will be set in the description field of the encoded payment request. - types.Bolt11InvoiceDescription description = 2; - - // Invoice expiry time in seconds. - uint32 expiry_secs = 3; - - // The hex-encoded 32-byte payment hash to use for the invoice. - string payment_hash = 4; -} - -// The response `content` for the `Bolt11ReceiveForHash` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message Bolt11ReceiveForHashResponse { - - // An invoice for a payment within the Lightning Network. - // With the details of the invoice, the sender has all the data necessary to send a payment - // to the recipient. - string invoice = 1; -} - -// Manually claim a payment for a given payment hash with the corresponding preimage. -// This should be used to claim payments created via `Bolt11ReceiveForHash`. -// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.claim_for_hash -message Bolt11ClaimForHashRequest { - - // The hex-encoded 32-byte payment hash. - // If provided, it will be used to verify that the preimage matches. - optional string payment_hash = 1; - - // The amount in millisatoshi that is claimable. - // If not provided, skips amount verification. - optional uint64 claimable_amount_msat = 2; - - // The hex-encoded 32-byte payment preimage. - string preimage = 3; -} - -// The response `content` for the `Bolt11ClaimForHash` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message Bolt11ClaimForHashResponse {} - -// Manually fail a payment for a given payment hash. -// This should be used to reject payments created via `Bolt11ReceiveForHash`. -// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.fail_for_hash -message Bolt11FailForHashRequest { - - // The hex-encoded 32-byte payment hash. - string payment_hash = 1; -} - -// The response `content` for the `Bolt11FailForHash` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message 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: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.receive_via_jit_channel -message Bolt11ReceiveViaJitChannelRequest { - - // The amount in millisatoshi to request. - uint64 amount_msat = 1; - - // An optional description to attach along with the invoice. - // Will be set in the description field of the encoded payment request. - types.Bolt11InvoiceDescription description = 2; - - // Invoice expiry time in seconds. - uint32 expiry_secs = 3; - - // Optional upper bound for the total fee an LSP may deduct when opening the JIT channel. - optional uint64 max_total_lsp_fee_limit_msat = 4; -} - -// The response `content` for the `Bolt11ReceiveViaJitChannel` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message Bolt11ReceiveViaJitChannelResponse { - - // An invoice for a payment within the Lightning Network. - string invoice = 1; -} - -// Return a variable-amount BOLT11 invoice that can be used to receive a payment via an LSPS2 -// just-in-time channel. -// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.receive_variable_amount_via_jit_channel -message Bolt11ReceiveVariableAmountViaJitChannelRequest { - - // An optional description to attach along with the invoice. - // Will be set in the description field of the encoded payment request. - types.Bolt11InvoiceDescription description = 1; - - // Invoice expiry time in seconds. - uint32 expiry_secs = 2; - - // Optional upper bound for the proportional fee, in parts-per-million millisatoshis, that an - // LSP may deduct when opening the JIT channel. - optional uint64 max_proportional_lsp_fee_limit_ppm_msat = 3; -} - -// The response `content` for the `Bolt11ReceiveVariableAmountViaJitChannel` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message Bolt11ReceiveVariableAmountViaJitChannelResponse { - - // An invoice for a payment within the Lightning Network. - string invoice = 1; -} - - -// Send a payment for a BOLT11 invoice. -// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt11Payment.html#method.send -message Bolt11SendRequest { - - // An invoice for a payment within the Lightning Network. - string invoice = 1; - - // Set this field when paying a so-called "zero-amount" invoice, i.e., an invoice that leaves the - // amount paid to be determined by the user. - // This operation will fail if the amount specified is less than the value required by the given invoice. - optional uint64 amount_msat = 2; - - // Configuration options for payment routing and pathfinding. - optional types.RouteParametersConfig route_parameters = 3; - -} - -// The response `content` for the `Bolt11Send` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message Bolt11SendResponse { - - // An identifier used to uniquely identify a payment in hex-encoded form. - string payment_id = 1; -} - -// Returns a BOLT12 offer for the given amount, if specified. -// -// See more: -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.receive -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.receive_variable_amount -message Bolt12ReceiveRequest { - - // An optional description to attach along with the offer. - // Will be set in the description field of the encoded offer. - string description = 1; - - // The amount in millisatoshi to send. If unset, a "zero-amount" or variable-amount offer is returned. - optional uint64 amount_msat = 2; - - // Offer expiry time in seconds. - optional uint32 expiry_secs = 3; - - // If set, it represents the number of items requested, can only be set for fixed-amount offers. - optional uint64 quantity = 4; -} - -// The response `content` for the `Bolt12Receive` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message Bolt12ReceiveResponse { - - // An offer for a payment within the Lightning Network. - // With the details of the offer, the sender has all the data necessary to send a payment - // to the recipient. - string offer = 1; - - // The hex-encoded offer id. - string offer_id = 2; -} - -// Send a payment for a BOLT12 offer. -// See more: -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.send -// - https://docs.rs/ldk-node/latest/ldk_node/payment/struct.Bolt12Payment.html#method.send_using_amount -message Bolt12SendRequest { - - // An offer for a payment within the Lightning Network. - string offer = 1; - - // Set this field when paying a so-called "zero-amount" offer, i.e., an offer that leaves the - // amount paid to be determined by the user. - // This operation will fail if the amount specified is less than the value required by the given offer. - optional uint64 amount_msat = 2; - - // If set, it represents the number of items requested. - optional uint64 quantity = 3; - - // If set, it will be seen by the recipient and reflected back in the invoice. - optional string payer_note = 4; - - // Configuration options for payment routing and pathfinding. - optional types.RouteParametersConfig route_parameters = 5; -} - -// The response `content` for the `Bolt12Send` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message Bolt12SendResponse { - - // An identifier used to uniquely identify a payment in hex-encoded form. - string payment_id = 1; -} - -// Send a spontaneous payment, also known as "keysend", to a node. -// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.SpontaneousPayment.html#method.send -message SpontaneousSendRequest { - // The amount in millisatoshis to send. - uint64 amount_msat = 1; - - // The hex-encoded public key of the node to send the payment to. - string node_id = 2; - - // Configuration options for payment routing and pathfinding. - optional types.RouteParametersConfig route_parameters = 3; -} - -// The response `content` for the `SpontaneousSend` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message SpontaneousSendResponse { - // An identifier used to uniquely identify a payment in hex-encoded form. - string payment_id = 1; -} - -// Creates a new outbound channel to the given remote node. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.connect_open_channel -message OpenChannelRequest { - - // The hex-encoded public key of the node to open a channel with. - string node_pubkey = 1; - - // An address which can be used to connect to a remote peer. - // It can be of type IPv4:port, IPv6:port, OnionV3:port or hostname:port - string address = 2; - - // The amount of satoshis the caller is willing to commit to the channel. - uint64 channel_amount_sats = 3; - - // The amount of satoshis to push to the remote side as part of the initial commitment state. - optional uint64 push_to_counterparty_msat = 4; - - // The channel configuration to be used for opening this channel. If unset, default ChannelConfig is used. - optional types.ChannelConfig channel_config = 5; - - // Whether the channel should be public. - bool announce_channel = 6; -} - -// The response `content` for the `OpenChannel` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message OpenChannelResponse { - - // The local channel id of the created channel that user can use to refer to channel. - string user_channel_id = 1; -} - -// Increases the channel balance by the given amount. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.splice_in -message SpliceInRequest { - - // The local `user_channel_id` of the channel. - string user_channel_id = 1; - - // The hex-encoded public key of the channel's counterparty node. - string counterparty_node_id = 2; - - // The amount of sats to splice into the channel. - uint64 splice_amount_sats = 3; -} - -// The response `content` for the `SpliceIn` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message SpliceInResponse {} - -// Decreases the channel balance by the given amount. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.splice_out -message SpliceOutRequest { - - // The local `user_channel_id` of this channel. - string user_channel_id = 1; - - // The hex-encoded public key of the channel's counterparty node. - string counterparty_node_id = 2; - - // A Bitcoin on-chain address to send the spliced-out funds. - // - // If not set, an address from the node's on-chain wallet will be used. - optional string address = 3; - - // The amount of sats to splice out of the channel. - uint64 splice_amount_sats = 4; -} - -// The response `content` for the `SpliceOut` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message SpliceOutResponse { - - // The Bitcoin on-chain address where the funds will be sent. - string address = 1; -} - -// Update the config for a previously opened channel. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.update_channel_config -message UpdateChannelConfigRequest { - - // The local `user_channel_id` of this channel. - string user_channel_id = 1; - - // The hex-encoded public key of the counterparty node to update channel config with. - string counterparty_node_id = 2; - - // The updated channel configuration settings for a channel. - types.ChannelConfig channel_config = 3; -} - -// The response `content` for the `UpdateChannelConfig` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message UpdateChannelConfigResponse { -} - -// Closes the channel specified by given request. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.close_channel -message CloseChannelRequest { - - // The local `user_channel_id` of this channel. - string user_channel_id = 1; - - // The hex-encoded public key of the node to close a channel with. - string counterparty_node_id = 2; -} - -// The response `content` for the `CloseChannel` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message CloseChannelResponse {} - -// Force closes the channel specified by given request. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.force_close_channel -message ForceCloseChannelRequest { - // The local `user_channel_id` of this channel. - string user_channel_id = 1; - // The hex-encoded public key of the node to close a channel with. - string counterparty_node_id = 2; - // The reason for force-closing. - optional string force_close_reason = 3; -} - -// The response `content` for the `ForceCloseChannel` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message ForceCloseChannelResponse {} - -// Returns a list of known channels. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_channels -message ListChannelsRequest {} - -// The response `content` for the `ListChannels` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message ListChannelsResponse { - - // List of channels. - repeated types.Channel channels = 1; -} - -// Returns payment details for a given payment_id. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.payment -message GetPaymentDetailsRequest { - // An identifier used to uniquely identify a payment in hex-encoded form. - string payment_id = 1; -} - -// The response `content` for the `GetPaymentDetails` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message GetPaymentDetailsResponse { - // Represents a payment. - // Will be `None` if payment doesn't exist. - types.Payment payment = 1; -} - -// Retrieves list of all payments. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_payments -message ListPaymentsRequest { - // `page_token` is a pagination token. - // - // To query for the first page, `page_token` must not be specified. - // - // For subsequent pages, use the value that was returned as `next_page_token` in the previous - // page's response. - optional types.PageToken page_token = 1; -} - -// The response `content` for the `ListPayments` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message ListPaymentsResponse { - // List of payments. - repeated types.Payment payments = 1; - - // `next_page_token` is a pagination token, used to retrieve the next page of results. - // Use this value to query for next-page of paginated operation, by specifying - // this value as the `page_token` in the next request. - // - // If `next_page_token` is `None`, then the "last page" of results has been processed and - // there is no more data to be retrieved. - // - // If `next_page_token` is not `None`, it does not necessarily mean that there is more data in the - // result set. The only way to know when you have reached the end of the result set is when - // `next_page_token` is `None`. - // - // **Caution**: Clients must not assume a specific number of records to be present in a page for - // paginated response. - optional types.PageToken next_page_token = 2; -} - -// Retrieves list of all forwarded payments. -// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.Event.html#variant.PaymentForwarded -message ListForwardedPaymentsRequest { - // `page_token` is a pagination token. - // - // To query for the first page, `page_token` must not be specified. - // - // For subsequent pages, use the value that was returned as `next_page_token` in the previous - // page's response. - optional types.PageToken page_token = 1; -} - -// The response `content` for the `ListForwardedPayments` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message ListForwardedPaymentsResponse { - // List of forwarded payments. - repeated types.ForwardedPayment forwarded_payments = 1; - - // `next_page_token` is a pagination token, used to retrieve the next page of results. - // Use this value to query for next-page of paginated operation, by specifying - // this value as the `page_token` in the next request. - // - // If `next_page_token` is `None`, then the "last page" of results has been processed and - // there is no more data to be retrieved. - // - // If `next_page_token` is not `None`, it does not necessarily mean that there is more data in the - // result set. The only way to know when you have reached the end of the result set is when - // `next_page_token` is `None`. - // - // **Caution**: Clients must not assume a specific number of records to be present in a page for - // paginated response. - optional types.PageToken next_page_token = 2; -} - -// Sign a message with the node's secret key. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.sign_message -message SignMessageRequest { - // The message to sign, as raw bytes. - bytes message = 1; -} - -// The response `content` for the `SignMessage` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message SignMessageResponse { - // The signature of the message, as a zbase32-encoded string. - string signature = 1; -} - -// Verify a signature against a message and public key. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.verify_signature -message VerifySignatureRequest { - // The message that was signed, as raw bytes. - bytes message = 1; - - // The signature to verify, as a zbase32-encoded string. - string signature = 2; - - // The hex-encoded public key of the signer. - string public_key = 3; -} - -// The response `content` for the `VerifySignature` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message VerifySignatureResponse { - // Whether the signature is valid. - bool valid = 1; -} - -// Export the pathfinding scores used by the router. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.export_pathfinding_scores -message 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`. -message ExportPathfindingScoresResponse { - // The serialized pathfinding scores data. - bytes scores = 1; -} - -// Retrieves an overview of all known balances. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_balances -message GetBalancesRequest {} - -// The response `content` for the `GetBalances` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message GetBalancesResponse { - // The total balance of our on-chain wallet. - uint64 total_onchain_balance_sats = 1; - - // The currently spendable balance of our on-chain wallet. - // - // This includes any sufficiently confirmed funds, minus `total_anchor_channels_reserve_sats`. - uint64 spendable_onchain_balance_sats = 2; - - // The share of our total balance that we retain as an emergency reserve to (hopefully) be - // able to spend the Anchor outputs when one of our channels is closed. - uint64 total_anchor_channels_reserve_sats = 3; - - // The total balance that we would be able to claim across all our Lightning channels. - // - // Note this excludes balances that we are unsure if we are able to claim (e.g., as we are - // waiting for a preimage or for a timeout to expire). These balances will however be included - // as `MaybePreimageClaimableHTLC` and `MaybeTimeoutClaimableHTLC` in `lightning_balances`. - uint64 total_lightning_balance_sats = 4; - - // A detailed list of all known Lightning balances that would be claimable on channel closure. - // - // Note that less than the listed amounts are spendable over lightning as further reserve - // restrictions apply. Please refer to `Channel::outbound_capacity_msat` and - // Channel::next_outbound_htlc_limit_msat as returned by `ListChannels` - // for a better approximation of the spendable amounts. - repeated types.LightningBalance lightning_balances = 5; - - // A detailed list of balances currently being swept from the Lightning to the on-chain - // wallet. - // - // These are balances resulting from channel closures that may have been encumbered by a - // delay, but are now being claimed and useable once sufficiently confirmed on-chain. - // - // Note that, depending on the sync status of the wallets, swept balances listed here might or - // might not already be accounted for in `total_onchain_balance_sats`. - repeated types.PendingSweepBalance pending_balances_from_channel_closures = 6; -} - -// Connect to a peer on the Lightning Network. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.connect -message ConnectPeerRequest { - // The hex-encoded public key of the node to connect to. - string node_pubkey = 1; - - // An address which can be used to connect to a remote peer. - // It can be of type IPv4:port, IPv6:port, OnionV3:port or hostname:port - string address = 2; - - // Whether to persist the peer connection, i.e., whether the peer will be re-connected on - // restart. - bool persist = 3; -} - -// The response `content` for the `ConnectPeer` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message ConnectPeerResponse {} - -// Disconnect from a peer and remove it from the peer store. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.disconnect -message DisconnectPeerRequest { - // The hex-encoded public key of the node to disconnect from. - string node_pubkey = 1; -} - -// The response `content` for the `DisconnectPeer` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message DisconnectPeerResponse {} - -// Returns a list of peers. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_peers -message 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`. -message ListPeersResponse { - - // List of peers. - repeated types.Peer peers = 1; -} - -// Returns a list of all known short channel IDs in the network graph. -// See more: https://docs.rs/ldk-node/latest/ldk_node/graph/struct.NetworkGraph.html#method.list_channels -message 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`. -message GraphListChannelsResponse { - // List of short channel IDs known to the network graph. - repeated uint64 short_channel_ids = 1; -} - -// Returns information on a channel with the given short channel ID from the network graph. -// See more: https://docs.rs/ldk-node/latest/ldk_node/graph/struct.NetworkGraph.html#method.channel -message GraphGetChannelRequest { - // The short channel ID to look up. - uint64 short_channel_id = 1; -} - -// The response `content` for the `GraphGetChannel` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message GraphGetChannelResponse { - // The channel information. - types.GraphChannel channel = 1; -} - -// Returns a list of all known node IDs in the network graph. -// See more: https://docs.rs/ldk-node/latest/ldk_node/graph/struct.NetworkGraph.html#method.list_nodes -message 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`. -message GraphListNodesResponse { - // List of hex-encoded node IDs known to the network graph. - repeated string node_ids = 1; -} - -// Send a payment given a BIP 21 URI or BIP 353 Human-Readable Name. -// -// This method parses the provided URI string and attempts to send the payment. If the URI -// has an offer and/or invoice, it will try to pay the offer first followed by the invoice. -// If they both fail, the on-chain payment will be paid. -// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.UnifiedPayment.html#method.send -message UnifiedSendRequest { - - // A BIP 21 URI or BIP 353 Human-Readable Name to pay. - string uri = 1; - - // The amount in millisatoshis to send. Required for "zero-amount" or variable-amount URIs. - optional uint64 amount_msat = 2; - - // Configuration options for payment routing and pathfinding. - optional types.RouteParametersConfig route_parameters = 3; -} - -// The response `content` for the `UnifiedSend` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message UnifiedSendResponse { - - oneof payment_result { - - // An on-chain payment was made. Contains the transaction ID. - string txid = 1; - - // A BOLT11 payment was made. Contains the payment ID in hex-encoded form. - string bolt11_payment_id = 2; - - // A BOLT12 payment was made. Contains the payment ID in hex-encoded form. - string bolt12_payment_id = 3; - } -} - -// Returns information on a node with the given ID from the network graph. -// See more: https://docs.rs/ldk-node/latest/ldk_node/graph/struct.NetworkGraph.html#method.node -message GraphGetNodeRequest { - // The hex-encoded node ID to look up. - string node_id = 1; -} - -// The response `content` for the `GraphGetNode` API, when HttpStatusCode is OK (200). -// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`. -message GraphGetNodeResponse { - // The node information. - types.GraphNode node = 1; -} diff --git a/ldk-server-protos/src/proto/error.proto b/ldk-server-protos/src/proto/error.proto deleted file mode 100644 index c5a75d7d..00000000 --- a/ldk-server-protos/src/proto/error.proto +++ /dev/null @@ -1,45 +0,0 @@ -syntax = "proto3"; -package error; - -// When HttpStatusCode is not ok (200), the response `content` contains a serialized `ErrorResponse` -// with the relevant ErrorCode and `message` -message ErrorResponse { - - // The error message containing a generic description of the error condition in English. - // It is intended for a human audience only and should not be parsed to extract any information - // programmatically. Client-side code may use it for logging only. - string message = 1; - - // The error code uniquely identifying an error condition. - // It is meant to be read and understood programmatically by code that detects/handles errors by - // type. - // - // **Caution**: If a new type of `error_code` is introduced in the `ErrorCode` enum, `error_code` field will be set to - // `UnknownError`. - ErrorCode error_code = 2; -} - -enum ErrorCode { - - // Will never be used as `error_code` by server. - // - // **Caution**: If a new type of `error_code` is introduced in the `ErrorCode` enum, `error_code` field will be set to - // `UnknownError`. - UNKNOWN_ERROR = 0; - - // Used in the following cases: - // - The request was missing a required argument. - // - The specified argument was invalid, incomplete or in the wrong format. - // - The request body of api cannot be deserialized into corresponding protobuf object. - // - The request does not follow api contract. - INVALID_REQUEST_ERROR = 1; - - // Used when authentication fails or in case of an unauthorized request. - AUTH_ERROR = 2; - - // Used to represent an error while doing a Lightning operation. - LIGHTNING_ERROR = 3; - - // Used when an internal server error occurred. The client is probably at no fault. - INTERNAL_SERVER_ERROR = 4; -} diff --git a/ldk-server-protos/src/proto/events.proto b/ldk-server-protos/src/proto/events.proto deleted file mode 100644 index 5c5ce2c3..00000000 --- a/ldk-server-protos/src/proto/events.proto +++ /dev/null @@ -1,44 +0,0 @@ -syntax = "proto3"; -import "types.proto"; -package events; - -// EventEnvelope wraps different event types in a single message to be used by EventPublisher. -message EventEnvelope { - oneof event { - PaymentReceived payment_received = 2; - PaymentSuccessful payment_successful = 3; - PaymentFailed payment_failed = 4; - PaymentForwarded payment_forwarded = 6; - PaymentClaimable payment_claimable = 7; - } -} - -// PaymentReceived indicates a payment has been received. -message PaymentReceived { - // The payment details for the payment in event. - types.Payment payment = 1; -} - -// PaymentSuccessful indicates a sent payment was successful. -message PaymentSuccessful { - // The payment details for the payment in event. - types.Payment payment = 1; -} - -// PaymentFailed indicates a sent payment has failed. -message PaymentFailed { - // The payment details for the payment in event. - types.Payment payment = 1; -} - -// PaymentClaimable indicates a payment has arrived and is waiting to be manually claimed or failed. -// This event is only emitted for payments created via `Bolt11ReceiveForHash`. -message PaymentClaimable { - // The payment details for the claimable payment. - types.Payment payment = 1; -} - -// PaymentForwarded indicates a payment was forwarded through the node. -message PaymentForwarded { - types.ForwardedPayment forwarded_payment = 1; -} diff --git a/ldk-server-protos/src/proto/types.proto b/ldk-server-protos/src/proto/types.proto deleted file mode 100644 index e48908ef..00000000 --- a/ldk-server-protos/src/proto/types.proto +++ /dev/null @@ -1,820 +0,0 @@ -syntax = "proto3"; -package types; - -// Represents a payment. -// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.PaymentDetails.html -message Payment { - // An identifier used to uniquely identify a payment in hex-encoded form. - string id = 1; - - // The kind of the payment. - PaymentKind kind = 2; - - // The amount transferred. - optional uint64 amount_msat = 3; - - // The fees that were paid for this payment. - // - // For Lightning payments, this will only be updated for outbound payments once they - // succeeded. - optional uint64 fee_paid_msat = 7; - - // The direction of the payment. - PaymentDirection direction = 4; - - // The status of the payment. - PaymentStatus status = 5; - - // The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. - uint64 latest_update_timestamp = 6; -} - -message PaymentKind { - oneof kind { - Onchain onchain = 1; - Bolt11 bolt11 = 2; - Bolt11Jit bolt11_jit = 3; - Bolt12Offer bolt12_offer = 4; - Bolt12Refund bolt12_refund = 5; - Spontaneous spontaneous = 6; - } -} - -// Represents an on-chain payment. -message Onchain { - // The transaction identifier of this payment. - string txid = 1; - - // The confirmation status of this payment. - ConfirmationStatus status = 2; -} - -message ConfirmationStatus { - oneof status { - Confirmed confirmed = 1; - Unconfirmed unconfirmed = 2; - } -} - -// The on-chain transaction is confirmed in the best chain. -message Confirmed { - // The hex representation of hash of the block in which the transaction was confirmed. - string block_hash = 1; - - // The height under which the block was confirmed. - uint32 height = 2; - - // The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. - uint64 timestamp = 3; -} - -// The on-chain transaction is unconfirmed. -message Unconfirmed {} - -// Represents a BOLT 11 payment. -message Bolt11 { - // The payment hash, i.e., the hash of the preimage. - string hash = 1; - - // The pre-image used by the payment. - optional string preimage = 2; - - // The secret used by the payment. - optional bytes secret = 3; -} - -// Represents a BOLT 11 payment intended to open an LSPS 2 just-in-time channel. -message Bolt11Jit { - // The payment hash, i.e., the hash of the preimage. - string hash = 1; - - // The pre-image used by the payment. - optional string preimage = 2; - - // The secret used by the payment. - optional bytes secret = 3; - - // Limits applying to how much fee we allow an LSP to deduct from the payment amount. - // - // Allowing them to deduct this fee from the first inbound payment will pay for the LSP’s channel opening fees. - // - // See [`LdkChannelConfig::accept_underpaying_htlcs`](https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.accept_underpaying_htlcs) - // for more information. - LSPFeeLimits lsp_fee_limits = 4; - - // The value, in thousands of a satoshi, that was deducted from this payment as an extra - // fee taken by our channel counterparty. - // - // Will only be `Some` once we received the payment. - optional uint64 counterparty_skimmed_fee_msat = 5; -} - -// Represents a BOLT 12 ‘offer’ payment, i.e., a payment for an Offer. -message Bolt12Offer { - // The payment hash, i.e., the hash of the preimage. - optional string hash = 1; - - // The pre-image used by the payment. - optional string preimage = 2; - - // The secret used by the payment. - optional bytes secret = 3; - - // The hex-encoded ID of the offer this payment is for. - string offer_id = 4; - - // The payer's note for the payment. - // Truncated to [PAYER_NOTE_LIMIT](https://docs.rs/lightning/latest/lightning/offers/invoice_request/constant.PAYER_NOTE_LIMIT.html). - // - // **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, - // all non-printable characters will be sanitized and replaced with safe characters. - optional string payer_note = 5; - - // The quantity of an item requested in the offer. - optional uint64 quantity = 6; -} - -// Represents a BOLT 12 ‘refund’ payment, i.e., a payment for a Refund. -message Bolt12Refund { - // The payment hash, i.e., the hash of the preimage. - optional string hash = 1; - - // The pre-image used by the payment. - optional string preimage = 2; - - // The secret used by the payment. - optional bytes secret = 3; - - // The payer's note for the payment. - // Truncated to [PAYER_NOTE_LIMIT](https://docs.rs/lightning/latest/lightning/offers/invoice_request/constant.PAYER_NOTE_LIMIT.html). - // - // **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, - // all non-printable characters will be sanitized and replaced with safe characters. - optional string payer_note = 5; - - // The quantity of an item requested in the offer. - optional uint64 quantity = 6; - -} - -// Represents a spontaneous (“keysend”) payment. -message Spontaneous { - // The payment hash, i.e., the hash of the preimage. - string hash = 1; - - // The pre-image used by the payment. - optional string preimage = 2; -} - -// Limits applying to how much fee we allow an LSP to deduct from the payment amount. -// See [`LdkChannelConfig::accept_underpaying_htlcs`] for more information. -// -// [`LdkChannelConfig::accept_underpaying_htlcs`]: lightning::util::config::ChannelConfig::accept_underpaying_htlcs -message LSPFeeLimits { - // The maximal total amount we allow any configured LSP withhold from us when forwarding the - // payment. - optional uint64 max_total_opening_fee_msat = 1; - - // The maximal proportional fee, in parts-per-million millisatoshi, we allow any configured - // LSP withhold from us when forwarding the payment. - optional uint64 max_proportional_opening_fee_ppm_msat = 2; -} - -// Represents the direction of a payment. -enum PaymentDirection { - // The payment is inbound. - INBOUND = 0; - - // The payment is outbound. - OUTBOUND = 1; -} - -// Represents the current status of a payment. -enum PaymentStatus { - // The payment is still pending. - PENDING = 0; - - // The payment succeeded. - SUCCEEDED = 1; - - // The payment failed. - FAILED = 2; -} - -// A forwarded payment through our node. -// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.Event.html#variant.PaymentForwarded -message ForwardedPayment{ - // The channel id of the incoming channel between the previous node and us. - string prev_channel_id = 1; - - // The channel id of the outgoing channel between the next node and us. - string next_channel_id = 2; - - // The `user_channel_id` of the incoming channel between the previous node and us. - string prev_user_channel_id = 3; - - // The node id of the previous node. - string prev_node_id = 9; - - // The node id of the next node. - string next_node_id = 10; - - // The `user_channel_id` of the outgoing channel between the next node and us. - // This will be `None` if the payment was settled via an on-chain transaction. - // See the caveat described for the `total_fee_earned_msat` field. - optional string next_user_channel_id = 4; - - // The total fee, in milli-satoshis, which was earned as a result of the payment. - // - // Note that if we force-closed the channel over which we forwarded an HTLC while the HTLC was pending, the amount the - // next hop claimed will have been rounded down to the nearest whole satoshi. Thus, the fee calculated here may be - // higher than expected as we still claimed the full value in millisatoshis from the source. - // In this case, `claim_from_onchain_tx` will be set. - // - // If the channel which sent us the payment has been force-closed, we will claim the funds via an on-chain transaction. - // In that case we do not yet know the on-chain transaction fees which we will spend and will instead set this to `None`. - optional uint64 total_fee_earned_msat = 5; - - // The share of the total fee, in milli-satoshis, which was withheld in addition to the forwarding fee. - // This will only be set if we forwarded an intercepted HTLC with less than the expected amount. This means our - // counterparty accepted to receive less than the invoice amount. - // - // The caveat described above the `total_fee_earned_msat` field applies here as well. - optional uint64 skimmed_fee_msat = 6; - - // If this is true, the forwarded HTLC was claimed by our counterparty via an on-chain transaction. - bool claim_from_onchain_tx = 7; - - // The final amount forwarded, in milli-satoshis, after the fee is deducted. - // - // The caveat described above the `total_fee_earned_msat` field applies here as well. - optional uint64 outbound_amount_forwarded_msat = 8; - -} - -message Channel { - // The channel ID (prior to funding transaction generation, this is a random 32-byte - // identifier, afterwards this is the transaction ID of the funding transaction XOR the - // funding transaction output). - // - // Note that this means this value is *not* persistent - it can change once during the - // lifetime of the channel. - string channel_id = 1; - - // The node ID of our the channel's remote counterparty. - string counterparty_node_id = 2; - - // The channel's funding transaction output, if we've negotiated the funding transaction with - // our counterparty already. - optional OutPoint funding_txo = 3; - - // The hex-encoded local `user_channel_id` of this channel. - string user_channel_id = 4; - - // The value, in satoshis, that must always be held as a reserve in the channel for us. This - // value ensures that if we broadcast a revoked state, our counterparty can punish us by - // claiming at least this value on chain. - // - // This value is not included in [`outbound_capacity_msat`] as it can never be spent. - // - // This value will be `None` for outbound channels until the counterparty accepts the channel. - optional uint64 unspendable_punishment_reserve = 5; - - // The value, in satoshis, of this channel as it appears in the funding output. - uint64 channel_value_sats = 6; - - // The currently negotiated fee rate denominated in satoshi per 1000 weight units, - // which is applied to commitment and HTLC transactions. - uint32 feerate_sat_per_1000_weight = 7; - - // The available outbound capacity for sending HTLCs to the remote peer. - // - // The amount does not include any pending HTLCs which are not yet resolved (and, thus, whose - // balance is not available for inclusion in new outbound HTLCs). This further does not include - // any pending outgoing HTLCs which are awaiting some other resolution to be sent. - uint64 outbound_capacity_msat = 8; - - // The available outbound capacity for sending HTLCs to the remote peer. - // - // The amount does not include any pending HTLCs which are not yet resolved - // (and, thus, whose balance is not available for inclusion in new inbound HTLCs). This further - // does not include any pending outgoing HTLCs which are awaiting some other resolution to be - // sent. - uint64 inbound_capacity_msat = 9; - - // The number of required confirmations on the funding transactions before the funding is - // considered "locked". The amount is selected by the channel fundee. - // - // The value will be `None` for outbound channels until the counterparty accepts the channel. - optional uint32 confirmations_required = 10; - - // The current number of confirmations on the funding transaction. - optional uint32 confirmations = 11; - - // Is `true` if the channel was initiated (and therefore funded) by us. - bool is_outbound = 12; - - // Is `true` if both parties have exchanged `channel_ready` messages, and the channel is - // not currently being shut down. Both parties exchange `channel_ready` messages upon - // independently verifying that the required confirmations count provided by - // `confirmations_required` has been reached. - bool is_channel_ready = 13; - - // Is `true` if the channel (a) `channel_ready` messages have been exchanged, (b) the - // peer is connected, and (c) the channel is not currently negotiating shutdown. - // - // This is a strict superset of `is_channel_ready`. - bool is_usable = 14; - - // Is `true` if this channel is (or will be) publicly-announced - bool is_announced = 15; - - // Set of configurable parameters set by self that affect channel operation. - ChannelConfig channel_config = 16; - - // The available outbound capacity for sending a single HTLC to the remote peer. This is - // similar to `outbound_capacity_msat` but it may be further restricted by - // the current state and per-HTLC limit(s). This is intended for use when routing, allowing us - // to use a limit as close as possible to the HTLC limit we can currently send. - uint64 next_outbound_htlc_limit_msat = 17; - - // The minimum value for sending a single HTLC to the remote peer. This is the equivalent of - // `next_outbound_htlc_limit_msat` but represents a lower-bound, rather than - // an upper-bound. This is intended for use when routing, allowing us to ensure we pick a - // route which is valid. - uint64 next_outbound_htlc_minimum_msat = 18; - - // The number of blocks (after our commitment transaction confirms) that we will need to wait - // until we can claim our funds after we force-close the channel. During this time our - // counterparty is allowed to punish us if we broadcasted a stale state. If our counterparty - // force-closes the channel and broadcasts a commitment transaction we do not have to wait any - // time to claim our non-HTLC-encumbered funds. - // - // This value will be `None` for outbound channels until the counterparty accepts the channel. - optional uint32 force_close_spend_delay = 19; - - // The smallest value HTLC (in msat) the remote peer will accept, for this channel. - // - // This field is only `None` before we have received either the `OpenChannel` or - // `AcceptChannel` message from the remote peer. - optional uint64 counterparty_outbound_htlc_minimum_msat = 20; - - // The largest value HTLC (in msat) the remote peer currently will accept, for this channel. - optional uint64 counterparty_outbound_htlc_maximum_msat = 21; - - // The value, in satoshis, that must always be held in the channel for our counterparty. This - // value ensures that if our counterparty broadcasts a revoked state, we can punish them by - // claiming at least this value on chain. - // - // This value is not included in `inbound_capacity_msat` as it can never be spent. - uint64 counterparty_unspendable_punishment_reserve = 22; - - // Base routing fee in millisatoshis. - optional uint32 counterparty_forwarding_info_fee_base_msat = 23; - - // Proportional fee, in millionths of a satoshi the channel will charge per transferred satoshi. - optional uint32 counterparty_forwarding_info_fee_proportional_millionths = 24; - - // The minimum difference in CLTV expiry between an ingoing HTLC and its outgoing counterpart, - // such that the outgoing HTLC is forwardable to this counterparty. - optional uint32 counterparty_forwarding_info_cltv_expiry_delta = 25; -} - -// ChannelConfig represents the configuration settings for a channel in a Lightning Network node. -// See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html -message ChannelConfig { - // Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound - // over the channel. - // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.forwarding_fee_proportional_millionths - optional uint32 forwarding_fee_proportional_millionths = 1; - - // Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, - // in excess of forwarding_fee_proportional_millionths. - // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.forwarding_fee_base_msat - optional uint32 forwarding_fee_base_msat = 2; - - // The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded - // over the channel this config applies to. - // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.cltv_expiry_delta - optional uint32 cltv_expiry_delta = 3; - - // The maximum additional fee we’re willing to pay to avoid waiting for the counterparty’s - // to_self_delay to reclaim funds. - // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.force_close_avoidance_max_fee_satoshis - optional uint64 force_close_avoidance_max_fee_satoshis = 4; - - // If set, allows this channel’s counterparty to skim an additional fee off this node’s - // inbound HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users. - // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.accept_underpaying_htlcs - optional bool accept_underpaying_htlcs = 5; - - // Limit our total exposure to potential loss to on-chain fees on close, including - // in-flight HTLCs which are burned to fees as they are too small to claim on-chain - // and fees on commitment transaction(s) broadcasted by our counterparty in excess of - // our own fee estimate. - // See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.max_dust_htlc_exposure - oneof max_dust_htlc_exposure { - - // This sets a fixed limit on the total dust exposure in millisatoshis. - // See more: https://docs.rs/lightning/latest/lightning/util/config/enum.MaxDustHTLCExposure.html#variant.FixedLimitMsat - uint64 fixed_limit_msat = 6; - - // This sets a multiplier on the ConfirmationTarget::OnChainSweep feerate (in sats/KW) to determine the maximum allowed dust exposure. - // See more: https://docs.rs/lightning/latest/lightning/util/config/enum.MaxDustHTLCExposure.html#variant.FeeRateMultiplier - uint64 fee_rate_multiplier = 7; - } -} - -// Represent a transaction outpoint. -message OutPoint { - // The referenced transaction's txid. - string txid = 1; - - // The index of the referenced output in its transaction's vout. - uint32 vout = 2; -} - -message BestBlock { - // The block’s hash - string block_hash = 1; - - // The height at which the block was confirmed. - uint32 height = 2; -} - -// Details about the status of a known Lightning balance. -message LightningBalance { - oneof balance_type { - ClaimableOnChannelClose claimable_on_channel_close = 1; - ClaimableAwaitingConfirmations claimable_awaiting_confirmations = 2; - ContentiousClaimable contentious_claimable = 3; - MaybeTimeoutClaimableHTLC maybe_timeout_claimable_htlc = 4; - MaybePreimageClaimableHTLC maybe_preimage_claimable_htlc = 5; - CounterpartyRevokedOutputClaimable counterparty_revoked_output_claimable = 6; - } -} - -// The channel is not yet closed (or the commitment or closing transaction has not yet appeared in a block). -// The given balance is claimable (less on-chain fees) if the channel is force-closed now. -// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.LightningBalance.html#variant.ClaimableOnChannelClose -message ClaimableOnChannelClose { - // The identifier of the channel this balance belongs to. - string channel_id = 1; - - // The identifier of our channel counterparty. - string counterparty_node_id = 2; - - // The amount available to claim, in satoshis, excluding the on-chain fees which will be required to do so. - uint64 amount_satoshis = 3; - - // The transaction fee we pay for the closing commitment transaction. - // This amount is not included in the `amount_satoshis` value. - // - // Note that if this channel is inbound (and thus our counterparty pays the commitment transaction fee) this value - // will be zero. - uint64 transaction_fee_satoshis = 4; - - // The amount of millisatoshis which has been burned to fees from HTLCs which are outbound from us and are related to - // a payment which was sent by us. This is the sum of the millisatoshis part of all HTLCs which are otherwise - // represented by `LightningBalance::MaybeTimeoutClaimableHTLC` with their - // `LightningBalance::MaybeTimeoutClaimableHTLC::outbound_payment` flag set, as well as any dust HTLCs which would - // otherwise be represented the same. - // - // This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. - uint64 outbound_payment_htlc_rounded_msat = 5; - - // The amount of millisatoshis which has been burned to fees from HTLCs which are outbound from us and are related to - // a forwarded HTLC. This is the sum of the millisatoshis part of all HTLCs which are otherwise represented by - // `LightningBalance::MaybeTimeoutClaimableHTLC` with their `LightningBalance::MaybeTimeoutClaimableHTLC::outbound_payment` - // flag not set, as well as any dust HTLCs which would otherwise be represented the same. - // - // This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. - uint64 outbound_forwarded_htlc_rounded_msat = 6; - - // The amount of millisatoshis which has been burned to fees from HTLCs which are inbound to us and for which we know - // the preimage. This is the sum of the millisatoshis part of all HTLCs which would be represented by - // `LightningBalance::ContentiousClaimable` on channel close, but whose current value is included in `amount_satoshis`, - // as well as any dust HTLCs which would otherwise be represented the same. - // - // This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. - uint64 inbound_claiming_htlc_rounded_msat = 7; - - // The amount of millisatoshis which has been burned to fees from HTLCs which are inbound to us and for which we do - // not know the preimage. This is the sum of the millisatoshis part of all HTLCs which would be represented by - // `LightningBalance::MaybePreimageClaimableHTLC` on channel close, as well as any dust HTLCs which would otherwise be - // represented the same. - // - // This amount (rounded up to a whole satoshi value) will not be included in the counterparty’s `amount_satoshis`. - uint64 inbound_htlc_rounded_msat = 8; -} - -// The channel has been closed, and the given balance is ours but awaiting confirmations until we consider it spendable. -// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.LightningBalance.html#variant.ClaimableAwaitingConfirmations -message ClaimableAwaitingConfirmations { - // The identifier of the channel this balance belongs to. - string channel_id = 1; - - // The identifier of our channel counterparty. - string counterparty_node_id = 2; - - // The amount available to claim, in satoshis, possibly excluding the on-chain fees which were spent in broadcasting - // the transaction. - uint64 amount_satoshis = 3; - - // The height at which we start tracking it as `SpendableOutput`. - uint32 confirmation_height = 4; - - // Whether this balance is a result of cooperative close, a force-close, or an HTLC. - BalanceSource source = 5; -} - -// Indicates whether the balance is derived from a cooperative close, a force-close (for holder or counterparty), -// or whether it is for an HTLC. -enum BalanceSource { - // The channel was force closed by the holder. - HOLDER_FORCE_CLOSED = 0; - - // The channel was force closed by the counterparty. - COUNTERPARTY_FORCE_CLOSED = 1; - - // The channel was cooperatively closed. - COOP_CLOSE = 2; - - // This balance is the result of an HTLC. - HTLC = 3; -} - -// The channel has been closed, and the given balance should be ours but awaiting spending transaction confirmation. -// If the spending transaction does not confirm in time, it is possible our counterparty can take the funds by -// broadcasting an HTLC timeout on-chain. -// -// Once the spending transaction confirms, before it has reached enough confirmations to be considered safe from chain -// reorganizations, the balance will instead be provided via `LightningBalance::ClaimableAwaitingConfirmations`. -// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.LightningBalance.html#variant.ContentiousClaimable -message ContentiousClaimable { - // The identifier of the channel this balance belongs to. - string channel_id = 1; - - // The identifier of our channel counterparty. - string counterparty_node_id = 2; - - // The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting - // the transaction. - uint64 amount_satoshis = 3; - - // The height at which the counterparty may be able to claim the balance if we have not done so. - uint32 timeout_height = 4; - - // The payment hash that locks this HTLC. - string payment_hash = 5; - - // The preimage that can be used to claim this HTLC. - string payment_preimage = 6; -} - -// HTLCs which we sent to our counterparty which are claimable after a timeout (less on-chain fees) if the counterparty -// does not know the preimage for the HTLCs. These are somewhat likely to be claimed by our counterparty before we do. -// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.LightningBalance.html#variant.MaybeTimeoutClaimableHTLC -message MaybeTimeoutClaimableHTLC { - // The identifier of the channel this balance belongs to. - string channel_id = 1; - - // The identifier of our channel counterparty. - string counterparty_node_id = 2; - - // The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting - // the transaction. - uint64 amount_satoshis = 3; - - // The height at which we will be able to claim the balance if our counterparty has not done so. - uint32 claimable_height = 4; - - // The payment hash whose preimage our counterparty needs to claim this HTLC. - string payment_hash = 5; - - // Indicates whether this HTLC represents a payment which was sent outbound from us. - bool outbound_payment = 6; -} - -// HTLCs which we received from our counterparty which are claimable with a preimage which we do not currently have. -// This will only be claimable if we receive the preimage from the node to which we forwarded this HTLC before the -// timeout. -// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.LightningBalance.html#variant.MaybePreimageClaimableHTLC -message MaybePreimageClaimableHTLC { - // The identifier of the channel this balance belongs to. - string channel_id = 1; - - // The identifier of our channel counterparty. - string counterparty_node_id = 2; - - // The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting - // the transaction. - uint64 amount_satoshis = 3; - - // The height at which our counterparty will be able to claim the balance if we have not yet received the preimage and - // claimed it ourselves. - uint32 expiry_height = 4; - - // The payment hash whose preimage we need to claim this HTLC. - string payment_hash = 5; -} -// The channel has been closed, and our counterparty broadcasted a revoked commitment transaction. -// -// Thus, we’re able to claim all outputs in the commitment transaction, one of which has the following amount. -// -// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.LightningBalance.html#variant.CounterpartyRevokedOutputClaimable -message CounterpartyRevokedOutputClaimable { - // The identifier of the channel this balance belongs to. - string channel_id = 1; - - // The identifier of our channel counterparty. - string counterparty_node_id = 2; - - // The amount, in satoshis, of the output which we can claim. - uint64 amount_satoshis = 3; -} - -// Details about the status of a known balance currently being swept to our on-chain wallet. -message PendingSweepBalance { - oneof balance_type { - PendingBroadcast pending_broadcast = 1; - BroadcastAwaitingConfirmation broadcast_awaiting_confirmation = 2; - AwaitingThresholdConfirmations awaiting_threshold_confirmations = 3; - } -} - -// The spendable output is about to be swept, but a spending transaction has yet to be generated and broadcast. -// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.PendingSweepBalance.html#variant.PendingBroadcast -message PendingBroadcast { - // The identifier of the channel this balance belongs to. - optional string channel_id = 1; - - // The amount, in satoshis, of the output being swept. - uint64 amount_satoshis = 2; -} - -// A spending transaction has been generated and broadcast and is awaiting confirmation on-chain. -// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.PendingSweepBalance.html#variant.BroadcastAwaitingConfirmation -message BroadcastAwaitingConfirmation { - // The identifier of the channel this balance belongs to. - optional string channel_id = 1; - - // The best height when we last broadcast a transaction spending the output being swept. - uint32 latest_broadcast_height = 2; - - // The identifier of the transaction spending the swept output we last broadcast. - string latest_spending_txid = 3; - - // The amount, in satoshis, of the output being swept. - uint64 amount_satoshis = 4; -} - -// A spending transaction has been confirmed on-chain and is awaiting threshold confirmations. -// -// It will be considered irrevocably confirmed after reaching `ANTI_REORG_DELAY`. -// See more: https://docs.rs/ldk-node/latest/ldk_node/enum.PendingSweepBalance.html#variant.AwaitingThresholdConfirmations -message AwaitingThresholdConfirmations { - // The identifier of the channel this balance belongs to. - optional string channel_id = 1; - - // The identifier of the confirmed transaction spending the swept output. - string latest_spending_txid = 2; - - // The hash of the block in which the spending transaction was confirmed. - string confirmation_hash = 3; - - // The height at which the spending transaction was confirmed. - uint32 confirmation_height = 4; - - // The amount, in satoshis, of the output being swept. - uint64 amount_satoshis = 5; -} - -// Token used to determine start of next page in paginated APIs. -message PageToken { - string token = 1; - int64 index = 2; -} - -message Bolt11InvoiceDescription { - oneof kind { - string direct = 1; - string hash = 2; - } -} - -// Configuration options for payment routing and pathfinding. -// See https://docs.rs/lightning/0.2.0/lightning/routing/router/struct.RouteParametersConfig.html for more details on each field. -message RouteParametersConfig { - // The maximum total fees, in millisatoshi, that may accrue during route finding. - // Defaults to 1% of the payment amount + 50 sats - optional uint64 max_total_routing_fee_msat = 1; - - // The maximum total CLTV delta we accept for the route. - // Defaults to 1008. - uint32 max_total_cltv_expiry_delta = 2; - - // The maximum number of paths that may be used by (MPP) payments. - // Defaults to 10. - uint32 max_path_count = 3; - - // Selects the maximum share of a channel's total capacity which will be - // sent over a channel, as a power of 1/2. - // Default value: 2 - uint32 max_channel_saturation_power_of_half = 4; -} - -// Routing fees for a channel as part of the network graph. -message GraphRoutingFees { - // Flat routing fee in millisatoshis. - uint32 base_msat = 1; - - // Liquidity-based routing fee in millionths of a routed amount. - uint32 proportional_millionths = 2; -} - -// Details about one direction of a channel in the network graph, -// as received within a `ChannelUpdate`. -message GraphChannelUpdate { - // When the last update to the channel direction was issued. - // Value is opaque, as set in the announcement. - uint32 last_update = 1; - - // Whether the channel can be currently used for payments (in this one direction). - bool enabled = 2; - - // The difference in CLTV values that you must have when routing through this channel. - uint32 cltv_expiry_delta = 3; - - // The minimum value, which must be relayed to the next hop via the channel. - uint64 htlc_minimum_msat = 4; - - // The maximum value which may be relayed to the next hop via the channel. - uint64 htlc_maximum_msat = 5; - - // Fees charged when the channel is used for routing. - GraphRoutingFees fees = 6; -} - -// Details about a channel in the network graph (both directions). -// Received within a channel announcement. -message GraphChannel { - // Source node of the first direction of the channel (hex-encoded public key). - string node_one = 1; - - // Source node of the second direction of the channel (hex-encoded public key). - string node_two = 2; - - // The channel capacity as seen on-chain, if chain lookup is available. - optional uint64 capacity_sats = 3; - - // Details about the first direction of a channel. - GraphChannelUpdate one_to_two = 4; - - // Details about the second direction of a channel. - GraphChannelUpdate two_to_one = 5; -} - -// Information received in the latest node_announcement from this node. -message GraphNodeAnnouncement { - // When the last known update to the node state was issued. - // Value is opaque, as set in the announcement. - uint32 last_update = 1; - - // Moniker assigned to the node. - // May be invalid or malicious (eg control chars), should not be exposed to the user. - string alias = 2; - - // Color assigned to the node as a hex-encoded RGB string, e.g. "ff0000". - string rgb = 3; - - // List of addresses on which this node is reachable. - repeated string addresses = 4; -} - -// Details of a known Lightning peer. -// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_peers -message Peer { - // The hex-encoded node ID of the peer. - string node_id = 1; - - // The network address of the peer. - string address = 2; - - // Indicates whether we'll try to reconnect to this peer after restarts. - bool is_persisted = 3; - - // Indicates whether we currently have an active connection with the peer. - bool is_connected = 4; -} - -// Details about a node in the network graph, known from the network announcement. -message GraphNode { - // All valid channels a node has announced. - repeated uint64 channels = 1; - - // More information about a node from node_announcement. - // Optional because we store a node entry after learning about it from - // a channel announcement, but before receiving a node announcement. - GraphNodeAnnouncement announcement_info = 2; -} diff --git a/ldk-server-protos/src/serde_utils.rs b/ldk-server-protos/src/serde_utils.rs deleted file mode 100644 index 5f10d137..00000000 --- a/ldk-server-protos/src/serde_utils.rs +++ /dev/null @@ -1,58 +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. - -//! Custom serde serializers for proto types. -//! -//! These are used via `#[serde(serialize_with = "...")]` attributes on generated -//! proto fields to produce human-readable output (hex strings for bytes, enum -//! names for integer enum fields). - -use std::fmt::Write; - -use serde::Serializer; - -/// Generates a serde serializer that converts an `i32` proto enum field to its -/// string name via `from_i32()` and `as_str_name()`. -macro_rules! stringify_enum_serializer { - ($fn_name:ident, $enum_type:ty) => { - pub fn $fn_name(value: &i32, serializer: S) -> Result - where - S: serde::Serializer, - { - let name = match <$enum_type>::from_i32(*value) { - Some(v) => v.as_str_name(), - None => "UNKNOWN", - }; - serializer.serialize_str(name) - } - }; -} - -stringify_enum_serializer!(serialize_payment_direction, crate::types::PaymentDirection); -stringify_enum_serializer!(serialize_payment_status, crate::types::PaymentStatus); -stringify_enum_serializer!(serialize_balance_source, crate::types::BalanceSource); - -/// Serializes `Option` as a hex string (or null). -pub fn serialize_opt_bytes_hex( - value: &Option, serializer: S, -) -> Result -where - S: Serializer, -{ - match value { - Some(bytes) => { - let hex = bytes.iter().fold(String::with_capacity(bytes.len() * 2), |mut acc, b| { - let _ = write!(acc, "{b:02x}"); - acc - }); - serializer.serialize_some(&hex) - }, - None => serializer.serialize_none(), - } -} diff --git a/ldk-server-protos/src/types.rs b/ldk-server-protos/src/types.rs deleted file mode 100644 index 280e34f4..00000000 --- a/ldk-server-protos/src/types.rs +++ /dev/null @@ -1,1143 +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. - -/// 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. - #[prost(string, tag = "1")] - pub id: ::prost::alloc::string::String, - /// The kind of the payment. - #[prost(message, optional, tag = "2")] - pub kind: ::core::option::Option, - /// The amount transferred. - #[prost(uint64, optional, tag = "3")] - pub amount_msat: ::core::option::Option, - /// The fees that were paid for this payment. - /// - /// For Lightning payments, this will only be updated for outbound payments once they - /// succeeded. - #[prost(uint64, optional, tag = "7")] - pub fee_paid_msat: ::core::option::Option, - /// The direction of the payment. - #[prost(enumeration = "PaymentDirection", tag = "4")] - #[cfg_attr( - feature = "serde", - serde(serialize_with = "crate::serde_utils::serialize_payment_direction") - )] - pub direction: i32, - /// The status of the payment. - #[prost(enumeration = "PaymentStatus", tag = "5")] - #[cfg_attr( - feature = "serde", - serde(serialize_with = "crate::serde_utils::serialize_payment_status") - )] - pub status: i32, - /// The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. - #[prost(uint64, tag = "6")] - pub latest_update_timestamp: u64, -} -#[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")] - pub kind: ::core::option::Option, -} -/// Nested message and enum types in `PaymentKind`. -pub mod payment_kind { - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] - #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Kind { - #[prost(message, tag = "1")] - Onchain(super::Onchain), - #[prost(message, tag = "2")] - Bolt11(super::Bolt11), - #[prost(message, tag = "3")] - Bolt11Jit(super::Bolt11Jit), - #[prost(message, tag = "4")] - Bolt12Offer(super::Bolt12Offer), - #[prost(message, tag = "5")] - Bolt12Refund(super::Bolt12Refund), - #[prost(message, tag = "6")] - Spontaneous(super::Spontaneous), - } -} -/// Represents an on-chain payment. -#[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. - #[prost(string, tag = "1")] - pub txid: ::prost::alloc::string::String, - /// The confirmation status of this payment. - #[prost(message, optional, tag = "2")] - pub status: ::core::option::Option, -} -#[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")] - pub status: ::core::option::Option, -} -/// Nested message and enum types in `ConfirmationStatus`. -pub mod confirmation_status { - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] - #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Status { - #[prost(message, tag = "1")] - Confirmed(super::Confirmed), - #[prost(message, tag = "2")] - Unconfirmed(super::Unconfirmed), - } -} -/// 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. - #[prost(string, tag = "1")] - pub block_hash: ::prost::alloc::string::String, - /// The height under which the block was confirmed. - #[prost(uint32, tag = "2")] - pub height: u32, - /// The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. - #[prost(uint64, tag = "3")] - pub timestamp: u64, -} -/// The on-chain transaction is unconfirmed. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Unconfirmed {} -/// Represents a BOLT 11 payment. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt11 { - /// The payment hash, i.e., the hash of the preimage. - #[prost(string, tag = "1")] - pub hash: ::prost::alloc::string::String, - /// The pre-image used by the payment. - #[prost(string, optional, tag = "2")] - pub preimage: ::core::option::Option<::prost::alloc::string::String>, - /// The secret used by the payment. - #[prost(bytes = "bytes", optional, tag = "3")] - #[cfg_attr( - feature = "serde", - serde(serialize_with = "crate::serde_utils::serialize_opt_bytes_hex") - )] - pub secret: ::core::option::Option<::prost::bytes::Bytes>, -} -/// Represents a BOLT 11 payment intended to open an LSPS 2 just-in-time channel. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt11Jit { - /// The payment hash, i.e., the hash of the preimage. - #[prost(string, tag = "1")] - pub hash: ::prost::alloc::string::String, - /// The pre-image used by the payment. - #[prost(string, optional, tag = "2")] - pub preimage: ::core::option::Option<::prost::alloc::string::String>, - /// The secret used by the payment. - #[prost(bytes = "bytes", optional, tag = "3")] - #[cfg_attr( - feature = "serde", - serde(serialize_with = "crate::serde_utils::serialize_opt_bytes_hex") - )] - pub secret: ::core::option::Option<::prost::bytes::Bytes>, - /// Limits applying to how much fee we allow an LSP to deduct from the payment amount. - /// - /// Allowing them to deduct this fee from the first inbound payment will pay for the LSP’s channel opening fees. - /// - /// See \[`LdkChannelConfig::accept_underpaying_htlcs`\]() - /// for more information. - #[prost(message, optional, tag = "4")] - pub lsp_fee_limits: ::core::option::Option, - /// The value, in thousands of a satoshi, that was deducted from this payment as an extra - /// fee taken by our channel counterparty. - /// - /// Will only be `Some` once we received the payment. - #[prost(uint64, optional, tag = "5")] - pub counterparty_skimmed_fee_msat: ::core::option::Option, -} -/// Represents a BOLT 12 ‘offer’ payment, i.e., a payment for an Offer. -#[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. - #[prost(string, optional, tag = "1")] - pub hash: ::core::option::Option<::prost::alloc::string::String>, - /// The pre-image used by the payment. - #[prost(string, optional, tag = "2")] - pub preimage: ::core::option::Option<::prost::alloc::string::String>, - /// The secret used by the payment. - #[prost(bytes = "bytes", optional, tag = "3")] - #[cfg_attr( - feature = "serde", - serde(serialize_with = "crate::serde_utils::serialize_opt_bytes_hex") - )] - pub secret: ::core::option::Option<::prost::bytes::Bytes>, - /// The hex-encoded ID of the offer this payment is for. - #[prost(string, tag = "4")] - pub offer_id: ::prost::alloc::string::String, - /// The payer's note for the payment. - /// Truncated to \[PAYER_NOTE_LIMIT\](). - /// - /// **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, - /// all non-printable characters will be sanitized and replaced with safe characters. - #[prost(string, optional, tag = "5")] - pub payer_note: ::core::option::Option<::prost::alloc::string::String>, - /// The quantity of an item requested in the offer. - #[prost(uint64, optional, tag = "6")] - pub quantity: ::core::option::Option, -} -/// Represents a BOLT 12 ‘refund’ payment, i.e., a payment for a Refund. -#[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. - #[prost(string, optional, tag = "1")] - pub hash: ::core::option::Option<::prost::alloc::string::String>, - /// The pre-image used by the payment. - #[prost(string, optional, tag = "2")] - pub preimage: ::core::option::Option<::prost::alloc::string::String>, - /// The secret used by the payment. - #[prost(bytes = "bytes", optional, tag = "3")] - #[cfg_attr( - feature = "serde", - serde(serialize_with = "crate::serde_utils::serialize_opt_bytes_hex") - )] - pub secret: ::core::option::Option<::prost::bytes::Bytes>, - /// The payer's note for the payment. - /// Truncated to \[PAYER_NOTE_LIMIT\](). - /// - /// **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, - /// all non-printable characters will be sanitized and replaced with safe characters. - #[prost(string, optional, tag = "5")] - pub payer_note: ::core::option::Option<::prost::alloc::string::String>, - /// The quantity of an item requested in the offer. - #[prost(uint64, optional, tag = "6")] - pub quantity: ::core::option::Option, -} -/// Represents a spontaneous (“keysend”) payment. -#[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. - #[prost(string, tag = "1")] - pub hash: ::prost::alloc::string::String, - /// The pre-image used by the payment. - #[prost(string, optional, tag = "2")] - pub preimage: ::core::option::Option<::prost::alloc::string::String>, -} -/// Limits applying to how much fee we allow an LSP to deduct from the payment amount. -/// See \[`LdkChannelConfig::accept_underpaying_htlcs`\] for more information. -/// -/// \[`LdkChannelConfig::accept_underpaying_htlcs`\]: lightning::util::config::ChannelConfig::accept_underpaying_htlcs -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct LspFeeLimits { - /// The maximal total amount we allow any configured LSP withhold from us when forwarding the - /// payment. - #[prost(uint64, optional, tag = "1")] - pub max_total_opening_fee_msat: ::core::option::Option, - /// The maximal proportional fee, in parts-per-million millisatoshi, we allow any configured - /// LSP withhold from us when forwarding the payment. - #[prost(uint64, optional, tag = "2")] - pub max_proportional_opening_fee_ppm_msat: ::core::option::Option, -} -/// A forwarded payment through our node. -/// See more: -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ForwardedPayment { - /// The channel id of the incoming channel between the previous node and us. - #[prost(string, tag = "1")] - pub prev_channel_id: ::prost::alloc::string::String, - /// The channel id of the outgoing channel between the next node and us. - #[prost(string, tag = "2")] - pub next_channel_id: ::prost::alloc::string::String, - /// The `user_channel_id` of the incoming channel between the previous node and us. - #[prost(string, tag = "3")] - pub prev_user_channel_id: ::prost::alloc::string::String, - /// The node id of the previous node. - #[prost(string, tag = "9")] - pub prev_node_id: ::prost::alloc::string::String, - /// The node id of the next node. - #[prost(string, tag = "10")] - pub next_node_id: ::prost::alloc::string::String, - /// The `user_channel_id` of the outgoing channel between the next node and us. - /// This will be `None` if the payment was settled via an on-chain transaction. - /// See the caveat described for the `total_fee_earned_msat` field. - #[prost(string, optional, tag = "4")] - pub next_user_channel_id: ::core::option::Option<::prost::alloc::string::String>, - /// The total fee, in milli-satoshis, which was earned as a result of the payment. - /// - /// Note that if we force-closed the channel over which we forwarded an HTLC while the HTLC was pending, the amount the - /// next hop claimed will have been rounded down to the nearest whole satoshi. Thus, the fee calculated here may be - /// higher than expected as we still claimed the full value in millisatoshis from the source. - /// In this case, `claim_from_onchain_tx` will be set. - /// - /// If the channel which sent us the payment has been force-closed, we will claim the funds via an on-chain transaction. - /// In that case we do not yet know the on-chain transaction fees which we will spend and will instead set this to `None`. - #[prost(uint64, optional, tag = "5")] - pub total_fee_earned_msat: ::core::option::Option, - /// The share of the total fee, in milli-satoshis, which was withheld in addition to the forwarding fee. - /// This will only be set if we forwarded an intercepted HTLC with less than the expected amount. This means our - /// counterparty accepted to receive less than the invoice amount. - /// - /// The caveat described above the `total_fee_earned_msat` field applies here as well. - #[prost(uint64, optional, tag = "6")] - pub skimmed_fee_msat: ::core::option::Option, - /// If this is true, the forwarded HTLC was claimed by our counterparty via an on-chain transaction. - #[prost(bool, tag = "7")] - pub claim_from_onchain_tx: bool, - /// The final amount forwarded, in milli-satoshis, after the fee is deducted. - /// - /// The caveat described above the `total_fee_earned_msat` field applies here as well. - #[prost(uint64, optional, tag = "8")] - pub outbound_amount_forwarded_msat: ::core::option::Option, -} -#[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 - /// identifier, afterwards this is the transaction ID of the funding transaction XOR the - /// funding transaction output). - /// - /// Note that this means this value is *not* persistent - it can change once during the - /// lifetime of the channel. - #[prost(string, tag = "1")] - pub channel_id: ::prost::alloc::string::String, - /// The node ID of our the channel's remote counterparty. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, - /// The channel's funding transaction output, if we've negotiated the funding transaction with - /// our counterparty already. - #[prost(message, optional, tag = "3")] - pub funding_txo: ::core::option::Option, - /// The hex-encoded local `user_channel_id` of this channel. - #[prost(string, tag = "4")] - pub user_channel_id: ::prost::alloc::string::String, - /// The value, in satoshis, that must always be held as a reserve in the channel for us. This - /// value ensures that if we broadcast a revoked state, our counterparty can punish us by - /// claiming at least this value on chain. - /// - /// This value is not included in \[`outbound_capacity_msat`\] as it can never be spent. - /// - /// This value will be `None` for outbound channels until the counterparty accepts the channel. - #[prost(uint64, optional, tag = "5")] - pub unspendable_punishment_reserve: ::core::option::Option, - /// The value, in satoshis, of this channel as it appears in the funding output. - #[prost(uint64, tag = "6")] - pub channel_value_sats: u64, - /// The currently negotiated fee rate denominated in satoshi per 1000 weight units, - /// which is applied to commitment and HTLC transactions. - #[prost(uint32, tag = "7")] - pub feerate_sat_per_1000_weight: u32, - /// The available outbound capacity for sending HTLCs to the remote peer. - /// - /// The amount does not include any pending HTLCs which are not yet resolved (and, thus, whose - /// balance is not available for inclusion in new outbound HTLCs). This further does not include - /// any pending outgoing HTLCs which are awaiting some other resolution to be sent. - #[prost(uint64, tag = "8")] - pub outbound_capacity_msat: u64, - /// The available outbound capacity for sending HTLCs to the remote peer. - /// - /// The amount does not include any pending HTLCs which are not yet resolved - /// (and, thus, whose balance is not available for inclusion in new inbound HTLCs). This further - /// does not include any pending outgoing HTLCs which are awaiting some other resolution to be - /// sent. - #[prost(uint64, tag = "9")] - pub inbound_capacity_msat: u64, - /// The number of required confirmations on the funding transactions before the funding is - /// considered "locked". The amount is selected by the channel fundee. - /// - /// The value will be `None` for outbound channels until the counterparty accepts the channel. - #[prost(uint32, optional, tag = "10")] - pub confirmations_required: ::core::option::Option, - /// The current number of confirmations on the funding transaction. - #[prost(uint32, optional, tag = "11")] - pub confirmations: ::core::option::Option, - /// Is `true` if the channel was initiated (and therefore funded) by us. - #[prost(bool, tag = "12")] - pub is_outbound: bool, - /// Is `true` if both parties have exchanged `channel_ready` messages, and the channel is - /// not currently being shut down. Both parties exchange `channel_ready` messages upon - /// independently verifying that the required confirmations count provided by - /// `confirmations_required` has been reached. - #[prost(bool, tag = "13")] - pub is_channel_ready: bool, - /// Is `true` if the channel (a) `channel_ready` messages have been exchanged, (b) the - /// peer is connected, and (c) the channel is not currently negotiating shutdown. - /// - /// This is a strict superset of `is_channel_ready`. - #[prost(bool, tag = "14")] - pub is_usable: bool, - /// Is `true` if this channel is (or will be) publicly-announced - #[prost(bool, tag = "15")] - pub is_announced: bool, - /// Set of configurable parameters set by self that affect channel operation. - #[prost(message, optional, tag = "16")] - pub channel_config: ::core::option::Option, - /// The available outbound capacity for sending a single HTLC to the remote peer. This is - /// similar to `outbound_capacity_msat` but it may be further restricted by - /// the current state and per-HTLC limit(s). This is intended for use when routing, allowing us - /// to use a limit as close as possible to the HTLC limit we can currently send. - #[prost(uint64, tag = "17")] - pub next_outbound_htlc_limit_msat: u64, - /// The minimum value for sending a single HTLC to the remote peer. This is the equivalent of - /// `next_outbound_htlc_limit_msat` but represents a lower-bound, rather than - /// an upper-bound. This is intended for use when routing, allowing us to ensure we pick a - /// route which is valid. - #[prost(uint64, tag = "18")] - pub next_outbound_htlc_minimum_msat: u64, - /// The number of blocks (after our commitment transaction confirms) that we will need to wait - /// until we can claim our funds after we force-close the channel. During this time our - /// counterparty is allowed to punish us if we broadcasted a stale state. If our counterparty - /// force-closes the channel and broadcasts a commitment transaction we do not have to wait any - /// time to claim our non-HTLC-encumbered funds. - /// - /// This value will be `None` for outbound channels until the counterparty accepts the channel. - #[prost(uint32, optional, tag = "19")] - pub force_close_spend_delay: ::core::option::Option, - /// The smallest value HTLC (in msat) the remote peer will accept, for this channel. - /// - /// This field is only `None` before we have received either the `OpenChannel` or - /// `AcceptChannel` message from the remote peer. - #[prost(uint64, optional, tag = "20")] - pub counterparty_outbound_htlc_minimum_msat: ::core::option::Option, - /// The largest value HTLC (in msat) the remote peer currently will accept, for this channel. - #[prost(uint64, optional, tag = "21")] - pub counterparty_outbound_htlc_maximum_msat: ::core::option::Option, - /// The value, in satoshis, that must always be held in the channel for our counterparty. This - /// value ensures that if our counterparty broadcasts a revoked state, we can punish them by - /// claiming at least this value on chain. - /// - /// This value is not included in `inbound_capacity_msat` as it can never be spent. - #[prost(uint64, tag = "22")] - pub counterparty_unspendable_punishment_reserve: u64, - /// Base routing fee in millisatoshis. - #[prost(uint32, optional, tag = "23")] - pub counterparty_forwarding_info_fee_base_msat: ::core::option::Option, - /// Proportional fee, in millionths of a satoshi the channel will charge per transferred satoshi. - #[prost(uint32, optional, tag = "24")] - pub counterparty_forwarding_info_fee_proportional_millionths: ::core::option::Option, - /// The minimum difference in CLTV expiry between an ingoing HTLC and its outgoing counterpart, - /// such that the outgoing HTLC is forwardable to this counterparty. - #[prost(uint32, optional, tag = "25")] - pub counterparty_forwarding_info_cltv_expiry_delta: ::core::option::Option, -} -/// ChannelConfig represents the configuration settings for a channel in a Lightning Network node. -/// See more: -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ChannelConfig { - /// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound - /// over the channel. - /// See more: - #[prost(uint32, optional, tag = "1")] - pub forwarding_fee_proportional_millionths: ::core::option::Option, - /// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, - /// in excess of forwarding_fee_proportional_millionths. - /// See more: - #[prost(uint32, optional, tag = "2")] - pub forwarding_fee_base_msat: ::core::option::Option, - /// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded - /// over the channel this config applies to. - /// See more: - #[prost(uint32, optional, tag = "3")] - pub cltv_expiry_delta: ::core::option::Option, - /// The maximum additional fee we’re willing to pay to avoid waiting for the counterparty’s - /// to_self_delay to reclaim funds. - /// See more: - #[prost(uint64, optional, tag = "4")] - pub force_close_avoidance_max_fee_satoshis: ::core::option::Option, - /// If set, allows this channel’s counterparty to skim an additional fee off this node’s - /// inbound HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users. - /// See more: - #[prost(bool, optional, tag = "5")] - pub accept_underpaying_htlcs: ::core::option::Option, - /// Limit our total exposure to potential loss to on-chain fees on close, including - /// in-flight HTLCs which are burned to fees as they are too small to claim on-chain - /// and fees on commitment transaction(s) broadcasted by our counterparty in excess of - /// our own fee estimate. - /// See more: - #[prost(oneof = "channel_config::MaxDustHtlcExposure", tags = "6, 7")] - pub max_dust_htlc_exposure: ::core::option::Option, -} -/// Nested message and enum types in `ChannelConfig`. -pub mod channel_config { - /// Limit our total exposure to potential loss to on-chain fees on close, including - /// in-flight HTLCs which are burned to fees as they are too small to claim on-chain - /// and fees on commitment transaction(s) broadcasted by our counterparty in excess of - /// our own fee estimate. - /// See more: - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] - #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum MaxDustHtlcExposure { - /// This sets a fixed limit on the total dust exposure in millisatoshis. - /// See more: - #[prost(uint64, tag = "6")] - FixedLimitMsat(u64), - /// This sets a multiplier on the ConfirmationTarget::OnChainSweep feerate (in sats/KW) to determine the maximum allowed dust exposure. - /// See more: - #[prost(uint64, tag = "7")] - FeeRateMultiplier(u64), - } -} -/// Represent a transaction outpoint. -#[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. - #[prost(string, tag = "1")] - pub txid: ::prost::alloc::string::String, - /// The index of the referenced output in its transaction's vout. - #[prost(uint32, tag = "2")] - pub vout: u32, -} -#[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 - #[prost(string, tag = "1")] - pub block_hash: ::prost::alloc::string::String, - /// The height at which the block was confirmed. - #[prost(uint32, tag = "2")] - pub height: u32, -} -/// 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")] - pub balance_type: ::core::option::Option, -} -/// Nested message and enum types in `LightningBalance`. -pub mod lightning_balance { - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] - #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum BalanceType { - #[prost(message, tag = "1")] - ClaimableOnChannelClose(super::ClaimableOnChannelClose), - #[prost(message, tag = "2")] - ClaimableAwaitingConfirmations(super::ClaimableAwaitingConfirmations), - #[prost(message, tag = "3")] - ContentiousClaimable(super::ContentiousClaimable), - #[prost(message, tag = "4")] - MaybeTimeoutClaimableHtlc(super::MaybeTimeoutClaimableHtlc), - #[prost(message, tag = "5")] - MaybePreimageClaimableHtlc(super::MaybePreimageClaimableHtlc), - #[prost(message, tag = "6")] - CounterpartyRevokedOutputClaimable(super::CounterpartyRevokedOutputClaimable), - } -} -/// The channel is not yet closed (or the commitment or closing transaction has not yet appeared in a block). -/// The given balance is claimable (less on-chain fees) if the channel is force-closed now. -/// See more: -#[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. - #[prost(string, tag = "1")] - pub channel_id: ::prost::alloc::string::String, - /// The identifier of our channel counterparty. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, - /// The amount available to claim, in satoshis, excluding the on-chain fees which will be required to do so. - #[prost(uint64, tag = "3")] - pub amount_satoshis: u64, - /// The transaction fee we pay for the closing commitment transaction. - /// This amount is not included in the `amount_satoshis` value. - /// - /// Note that if this channel is inbound (and thus our counterparty pays the commitment transaction fee) this value - /// will be zero. - #[prost(uint64, tag = "4")] - pub transaction_fee_satoshis: u64, - /// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound from us and are related to - /// a payment which was sent by us. This is the sum of the millisatoshis part of all HTLCs which are otherwise - /// represented by `LightningBalance::MaybeTimeoutClaimableHTLC` with their - /// `LightningBalance::MaybeTimeoutClaimableHTLC::outbound_payment` flag set, as well as any dust HTLCs which would - /// otherwise be represented the same. - /// - /// This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. - #[prost(uint64, tag = "5")] - pub outbound_payment_htlc_rounded_msat: u64, - /// The amount of millisatoshis which has been burned to fees from HTLCs which are outbound from us and are related to - /// a forwarded HTLC. This is the sum of the millisatoshis part of all HTLCs which are otherwise represented by - /// `LightningBalance::MaybeTimeoutClaimableHTLC` with their `LightningBalance::MaybeTimeoutClaimableHTLC::outbound_payment` - /// flag not set, as well as any dust HTLCs which would otherwise be represented the same. - /// - /// This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. - #[prost(uint64, tag = "6")] - pub outbound_forwarded_htlc_rounded_msat: u64, - /// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound to us and for which we know - /// the preimage. This is the sum of the millisatoshis part of all HTLCs which would be represented by - /// `LightningBalance::ContentiousClaimable` on channel close, but whose current value is included in `amount_satoshis`, - /// as well as any dust HTLCs which would otherwise be represented the same. - /// - /// This amount (rounded up to a whole satoshi value) will not be included in `amount_satoshis`. - #[prost(uint64, tag = "7")] - pub inbound_claiming_htlc_rounded_msat: u64, - /// The amount of millisatoshis which has been burned to fees from HTLCs which are inbound to us and for which we do - /// not know the preimage. This is the sum of the millisatoshis part of all HTLCs which would be represented by - /// `LightningBalance::MaybePreimageClaimableHTLC` on channel close, as well as any dust HTLCs which would otherwise be - /// represented the same. - /// - /// This amount (rounded up to a whole satoshi value) will not be included in the counterparty’s `amount_satoshis`. - #[prost(uint64, tag = "8")] - pub inbound_htlc_rounded_msat: u64, -} -/// The channel has been closed, and the given balance is ours but awaiting confirmations until we consider it spendable. -/// See more: -#[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. - #[prost(string, tag = "1")] - pub channel_id: ::prost::alloc::string::String, - /// The identifier of our channel counterparty. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, - /// The amount available to claim, in satoshis, possibly excluding the on-chain fees which were spent in broadcasting - /// the transaction. - #[prost(uint64, tag = "3")] - pub amount_satoshis: u64, - /// The height at which we start tracking it as `SpendableOutput`. - #[prost(uint32, tag = "4")] - pub confirmation_height: u32, - /// Whether this balance is a result of cooperative close, a force-close, or an HTLC. - #[prost(enumeration = "BalanceSource", tag = "5")] - #[cfg_attr( - feature = "serde", - serde(serialize_with = "crate::serde_utils::serialize_balance_source") - )] - pub source: i32, -} -/// The channel has been closed, and the given balance should be ours but awaiting spending transaction confirmation. -/// If the spending transaction does not confirm in time, it is possible our counterparty can take the funds by -/// broadcasting an HTLC timeout on-chain. -/// -/// Once the spending transaction confirms, before it has reached enough confirmations to be considered safe from chain -/// reorganizations, the balance will instead be provided via `LightningBalance::ClaimableAwaitingConfirmations`. -/// See more: -#[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. - #[prost(string, tag = "1")] - pub channel_id: ::prost::alloc::string::String, - /// The identifier of our channel counterparty. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, - /// The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting - /// the transaction. - #[prost(uint64, tag = "3")] - pub amount_satoshis: u64, - /// The height at which the counterparty may be able to claim the balance if we have not done so. - #[prost(uint32, tag = "4")] - pub timeout_height: u32, - /// The payment hash that locks this HTLC. - #[prost(string, tag = "5")] - pub payment_hash: ::prost::alloc::string::String, - /// The preimage that can be used to claim this HTLC. - #[prost(string, tag = "6")] - pub payment_preimage: ::prost::alloc::string::String, -} -/// HTLCs which we sent to our counterparty which are claimable after a timeout (less on-chain fees) if the counterparty -/// does not know the preimage for the HTLCs. These are somewhat likely to be claimed by our counterparty before we do. -/// See more: -#[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. - #[prost(string, tag = "1")] - pub channel_id: ::prost::alloc::string::String, - /// The identifier of our channel counterparty. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, - /// The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting - /// the transaction. - #[prost(uint64, tag = "3")] - pub amount_satoshis: u64, - /// The height at which we will be able to claim the balance if our counterparty has not done so. - #[prost(uint32, tag = "4")] - pub claimable_height: u32, - /// The payment hash whose preimage our counterparty needs to claim this HTLC. - #[prost(string, tag = "5")] - pub payment_hash: ::prost::alloc::string::String, - /// Indicates whether this HTLC represents a payment which was sent outbound from us. - #[prost(bool, tag = "6")] - pub outbound_payment: bool, -} -/// HTLCs which we received from our counterparty which are claimable with a preimage which we do not currently have. -/// This will only be claimable if we receive the preimage from the node to which we forwarded this HTLC before the -/// timeout. -/// See more: -#[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. - #[prost(string, tag = "1")] - pub channel_id: ::prost::alloc::string::String, - /// The identifier of our channel counterparty. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, - /// The amount available to claim, in satoshis, excluding the on-chain fees which were spent in broadcasting - /// the transaction. - #[prost(uint64, tag = "3")] - pub amount_satoshis: u64, - /// The height at which our counterparty will be able to claim the balance if we have not yet received the preimage and - /// claimed it ourselves. - #[prost(uint32, tag = "4")] - pub expiry_height: u32, - /// The payment hash whose preimage we need to claim this HTLC. - #[prost(string, tag = "5")] - pub payment_hash: ::prost::alloc::string::String, -} -/// The channel has been closed, and our counterparty broadcasted a revoked commitment transaction. -/// -/// Thus, we’re able to claim all outputs in the commitment transaction, one of which has the following amount. -/// -/// See more: -#[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. - #[prost(string, tag = "1")] - pub channel_id: ::prost::alloc::string::String, - /// The identifier of our channel counterparty. - #[prost(string, tag = "2")] - pub counterparty_node_id: ::prost::alloc::string::String, - /// The amount, in satoshis, of the output which we can claim. - #[prost(uint64, tag = "3")] - pub amount_satoshis: u64, -} -/// Details about the status of a known balance currently being swept to our on-chain wallet. -#[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")] - pub balance_type: ::core::option::Option, -} -/// Nested message and enum types in `PendingSweepBalance`. -pub mod pending_sweep_balance { - #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] - #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum BalanceType { - #[prost(message, tag = "1")] - PendingBroadcast(super::PendingBroadcast), - #[prost(message, tag = "2")] - BroadcastAwaitingConfirmation(super::BroadcastAwaitingConfirmation), - #[prost(message, tag = "3")] - AwaitingThresholdConfirmations(super::AwaitingThresholdConfirmations), - } -} -/// The spendable output is about to be swept, but a spending transaction has yet to be generated and broadcast. -/// See more: -#[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. - #[prost(string, optional, tag = "1")] - pub channel_id: ::core::option::Option<::prost::alloc::string::String>, - /// The amount, in satoshis, of the output being swept. - #[prost(uint64, tag = "2")] - pub amount_satoshis: u64, -} -/// A spending transaction has been generated and broadcast and is awaiting confirmation on-chain. -/// See more: -#[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. - #[prost(string, optional, tag = "1")] - pub channel_id: ::core::option::Option<::prost::alloc::string::String>, - /// The best height when we last broadcast a transaction spending the output being swept. - #[prost(uint32, tag = "2")] - pub latest_broadcast_height: u32, - /// The identifier of the transaction spending the swept output we last broadcast. - #[prost(string, tag = "3")] - pub latest_spending_txid: ::prost::alloc::string::String, - /// The amount, in satoshis, of the output being swept. - #[prost(uint64, tag = "4")] - pub amount_satoshis: u64, -} -/// A spending transaction has been confirmed on-chain and is awaiting threshold confirmations. -/// -/// It will be considered irrevocably confirmed after reaching `ANTI_REORG_DELAY`. -/// See more: -#[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. - #[prost(string, optional, tag = "1")] - pub channel_id: ::core::option::Option<::prost::alloc::string::String>, - /// The identifier of the confirmed transaction spending the swept output. - #[prost(string, tag = "2")] - pub latest_spending_txid: ::prost::alloc::string::String, - /// The hash of the block in which the spending transaction was confirmed. - #[prost(string, tag = "3")] - pub confirmation_hash: ::prost::alloc::string::String, - /// The height at which the spending transaction was confirmed. - #[prost(uint32, tag = "4")] - pub confirmation_height: u32, - /// The amount, in satoshis, of the output being swept. - #[prost(uint64, tag = "5")] - pub amount_satoshis: u64, -} -/// 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")] - pub token: ::prost::alloc::string::String, - #[prost(int64, tag = "2")] - pub index: i64, -} -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bolt11InvoiceDescription { - #[prost(oneof = "bolt11_invoice_description::Kind", tags = "1, 2")] - pub kind: ::core::option::Option, -} -/// Nested message and enum types in `Bolt11InvoiceDescription`. -pub mod bolt11_invoice_description { - #[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")] - Direct(::prost::alloc::string::String), - #[prost(string, tag = "2")] - Hash(::prost::alloc::string::String), - } -} -/// Configuration options for payment routing and pathfinding. -/// See for more details on each field. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RouteParametersConfig { - /// The maximum total fees, in millisatoshi, that may accrue during route finding. - /// Defaults to 1% of the payment amount + 50 sats - #[prost(uint64, optional, tag = "1")] - pub max_total_routing_fee_msat: ::core::option::Option, - /// The maximum total CLTV delta we accept for the route. - /// Defaults to 1008. - #[prost(uint32, tag = "2")] - pub max_total_cltv_expiry_delta: u32, - /// The maximum number of paths that may be used by (MPP) payments. - /// Defaults to 10. - #[prost(uint32, tag = "3")] - pub max_path_count: u32, - /// Selects the maximum share of a channel's total capacity which will be - /// sent over a channel, as a power of 1/2. - /// Default value: 2 - #[prost(uint32, tag = "4")] - pub max_channel_saturation_power_of_half: u32, -} -/// 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)] -pub struct GraphRoutingFees { - /// Flat routing fee in millisatoshis. - #[prost(uint32, tag = "1")] - pub base_msat: u32, - /// Liquidity-based routing fee in millionths of a routed amount. - #[prost(uint32, tag = "2")] - pub proportional_millionths: u32, -} -/// Details about one direction of a channel in the network graph, -/// 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)] -pub struct GraphChannelUpdate { - /// When the last update to the channel direction was issued. - /// Value is opaque, as set in the announcement. - #[prost(uint32, tag = "1")] - pub last_update: u32, - /// Whether the channel can be currently used for payments (in this one direction). - #[prost(bool, tag = "2")] - pub enabled: bool, - /// The difference in CLTV values that you must have when routing through this channel. - #[prost(uint32, tag = "3")] - pub cltv_expiry_delta: u32, - /// The minimum value, which must be relayed to the next hop via the channel. - #[prost(uint64, tag = "4")] - pub htlc_minimum_msat: u64, - /// The maximum value which may be relayed to the next hop via the channel. - #[prost(uint64, tag = "5")] - pub htlc_maximum_msat: u64, - /// Fees charged when the channel is used for routing. - #[prost(message, optional, tag = "6")] - pub fees: ::core::option::Option, -} -/// Details about a channel in the network graph (both directions). -/// 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). - #[prost(string, tag = "1")] - pub node_one: ::prost::alloc::string::String, - /// Source node of the second direction of the channel (hex-encoded public key). - #[prost(string, tag = "2")] - pub node_two: ::prost::alloc::string::String, - /// The channel capacity as seen on-chain, if chain lookup is available. - #[prost(uint64, optional, tag = "3")] - pub capacity_sats: ::core::option::Option, - /// Details about the first direction of a channel. - #[prost(message, optional, tag = "4")] - pub one_to_two: ::core::option::Option, - /// Details about the second direction of a channel. - #[prost(message, optional, tag = "5")] - pub two_to_one: ::core::option::Option, -} -/// 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. - /// Value is opaque, as set in the announcement. - #[prost(uint32, tag = "1")] - pub last_update: u32, - /// Moniker assigned to the node. - /// May be invalid or malicious (eg control chars), should not be exposed to the user. - #[prost(string, tag = "2")] - pub alias: ::prost::alloc::string::String, - /// Color assigned to the node as a hex-encoded RGB string, e.g. "ff0000". - #[prost(string, tag = "3")] - pub rgb: ::prost::alloc::string::String, - /// List of addresses on which this node is reachable. - #[prost(string, repeated, tag = "4")] - pub addresses: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -/// Details of a known Lightning peer. -/// 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. - #[prost(string, tag = "1")] - pub node_id: ::prost::alloc::string::String, - /// The network address of the peer. - #[prost(string, tag = "2")] - pub address: ::prost::alloc::string::String, - /// Indicates whether we'll try to reconnect to this peer after restarts. - #[prost(bool, tag = "3")] - pub is_persisted: bool, - /// Indicates whether we currently have an active connection with the peer. - #[prost(bool, tag = "4")] - pub is_connected: bool, -} -/// 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. - #[prost(uint64, repeated, tag = "1")] - pub channels: ::prost::alloc::vec::Vec, - /// More information about a node from node_announcement. - /// Optional because we store a node entry after learning about it from - /// a channel announcement, but before receiving a node announcement. - #[prost(message, optional, tag = "2")] - pub announcement_info: ::core::option::Option, -} -/// Represents the direction of a payment. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum PaymentDirection { - /// The payment is inbound. - Inbound = 0, - /// The payment is outbound. - Outbound = 1, -} -impl PaymentDirection { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - PaymentDirection::Inbound => "INBOUND", - PaymentDirection::Outbound => "OUTBOUND", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "INBOUND" => Some(Self::Inbound), - "OUTBOUND" => Some(Self::Outbound), - _ => None, - } - } -} -/// Represents the current status of a payment. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum PaymentStatus { - /// The payment is still pending. - Pending = 0, - /// The payment succeeded. - Succeeded = 1, - /// The payment failed. - Failed = 2, -} -impl PaymentStatus { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - PaymentStatus::Pending => "PENDING", - PaymentStatus::Succeeded => "SUCCEEDED", - PaymentStatus::Failed => "FAILED", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "PENDING" => Some(Self::Pending), - "SUCCEEDED" => Some(Self::Succeeded), - "FAILED" => Some(Self::Failed), - _ => None, - } - } -} -/// Indicates whether the balance is derived from a cooperative close, a force-close (for holder or counterparty), -/// or whether it is for an HTLC. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum BalanceSource { - /// The channel was force closed by the holder. - HolderForceClosed = 0, - /// The channel was force closed by the counterparty. - CounterpartyForceClosed = 1, - /// The channel was cooperatively closed. - CoopClose = 2, - /// This balance is the result of an HTLC. - Htlc = 3, -} -impl BalanceSource { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - BalanceSource::HolderForceClosed => "HOLDER_FORCE_CLOSED", - BalanceSource::CounterpartyForceClosed => "COUNTERPARTY_FORCE_CLOSED", - BalanceSource::CoopClose => "COOP_CLOSE", - BalanceSource::Htlc => "HTLC", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "HOLDER_FORCE_CLOSED" => Some(Self::HolderForceClosed), - "COUNTERPARTY_FORCE_CLOSED" => Some(Self::CounterpartyForceClosed), - "COOP_CLOSE" => Some(Self::CoopClose), - "HTLC" => Some(Self::Htlc), - _ => None, - } - } -} diff --git a/ldk-server/Cargo.toml b/ldk-server/Cargo.toml index 4156a649..f4e0b59d 100644 --- a/ldk-server/Cargo.toml +++ b/ldk-server/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] ldk-node = { git = "https://github.com/lightningdevkit/ldk-node", rev = "9e0a8124cbe2c00a06fc5c880113213d4b36d8aa" } serde = { version = "1.0.203", default-features = false, features = ["derive"] } +serde_json = "1.0" 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"] } @@ -13,30 +14,18 @@ tokio = { version = "1.38.0", default-features = false, features = ["time", "sig tokio-rustls = { version = "0.26", default-features = false, features = ["ring"] } 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" } -bytes = { version = "1.4.0", default-features = false } +ldk-server-json-models = { path = "../ldk-server-json-models" } +utoipa = { version = "5" } 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 d4345bc3..cf1cac37 100644 --- a/ldk-server/ldk-server-config.toml +++ b/ldk-server/ldk-server-config.toml @@ -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..a66247c9 100644 --- a/ldk-server/src/api/bolt11_claim_for_hash.rs +++ b/ldk-server/src/api/bolt11_claim_for_hash.rs @@ -7,33 +7,19 @@ // You may not use this file except in accordance with one or both of these // licenses. -use hex::FromHex; use ldk_node::bitcoin::hashes::{sha256, Hash}; use ldk_node::lightning_types::payment::{PaymentHash, PaymentPreimage}; -use ldk_server_protos::api::{Bolt11ClaimForHashRequest, Bolt11ClaimForHashResponse}; +use ldk_server_json_models::api::{Bolt11ClaimForHashRequest, Bolt11ClaimForHashResponse}; use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; pub(crate) fn handle_bolt11_claim_for_hash_request( context: Context, request: Bolt11ClaimForHashRequest, ) -> Result { - let preimage_bytes = <[u8; 32]>::from_hex(&request.preimage).map_err(|_| { - LdkServerError::new( - InvalidRequestError, - "Invalid preimage, must be a 32-byte hex string.".to_string(), - ) - })?; - let preimage = PaymentPreimage(preimage_bytes); + let preimage = PaymentPreimage(request.preimage); - let payment_hash = if let Some(hash_hex) = &request.payment_hash { - let hash_bytes = <[u8; 32]>::from_hex(hash_hex).map_err(|_| { - LdkServerError::new( - InvalidRequestError, - "Invalid payment_hash, must be a 32-byte hex string.".to_string(), - ) - })?; + let payment_hash = if let Some(hash_bytes) = request.payment_hash { PaymentHash(hash_bytes) } else { PaymentHash(sha256::Hash::hash(&preimage.0).to_byte_array()) diff --git a/ldk-server/src/api/bolt11_fail_for_hash.rs b/ldk-server/src/api/bolt11_fail_for_hash.rs index 9f349164..b269d919 100644 --- a/ldk-server/src/api/bolt11_fail_for_hash.rs +++ b/ldk-server/src/api/bolt11_fail_for_hash.rs @@ -7,24 +7,16 @@ // You may not use this file except in accordance with one or both of these // licenses. -use hex::FromHex; use ldk_node::lightning_types::payment::PaymentHash; -use ldk_server_protos::api::{Bolt11FailForHashRequest, Bolt11FailForHashResponse}; +use ldk_server_json_models::api::{Bolt11FailForHashRequest, Bolt11FailForHashResponse}; use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; pub(crate) fn handle_bolt11_fail_for_hash_request( context: Context, request: Bolt11FailForHashRequest, ) -> Result { - let hash_bytes = <[u8; 32]>::from_hex(&request.payment_hash).map_err(|_| { - LdkServerError::new( - InvalidRequestError, - "Invalid payment_hash, must be a 32-byte hex string.".to_string(), - ) - })?; - let payment_hash = PaymentHash(hash_bytes); + let payment_hash = PaymentHash(request.payment_hash); context.node.bolt11_payment().fail_for_hash(payment_hash)?; diff --git a/ldk-server/src/api/bolt11_receive.rs b/ldk-server/src/api/bolt11_receive.rs index 793a0928..d96cef6b 100644 --- a/ldk-server/src/api/bolt11_receive.rs +++ b/ldk-server/src/api/bolt11_receive.rs @@ -7,17 +7,16 @@ // You may not use this file except in accordance with one or both of these // licenses. -use hex::DisplayHex; -use ldk_server_protos::api::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; +use ldk_server_json_models::api::{Bolt11ReceiveRequest, Bolt11ReceiveResponse}; use crate::api::error::LdkServerError; use crate::service::Context; -use crate::util::proto_adapter::proto_to_bolt11_description; +use crate::util::adapter::bolt11_description_from_model; pub(crate) fn handle_bolt11_receive_request( context: Context, request: Bolt11ReceiveRequest, ) -> Result { - let description = proto_to_bolt11_description(request.description)?; + let description = bolt11_description_from_model(request.description)?; let invoice = match request.amount_msat { Some(amount_msat) => { context.node.bolt11_payment().receive(amount_msat, &description, request.expiry_secs)? @@ -28,8 +27,8 @@ pub(crate) fn handle_bolt11_receive_request( .receive_variable_amount(&description, request.expiry_secs)?, }; - let payment_hash = invoice.payment_hash().0.to_lower_hex_string(); - let payment_secret = invoice.payment_secret().0.to_lower_hex_string(); + let payment_hash = invoice.payment_hash().0; + let payment_secret = invoice.payment_secret().0; let response = Bolt11ReceiveResponse { invoice: invoice.to_string(), payment_hash, payment_secret }; Ok(response) diff --git a/ldk-server/src/api/bolt11_receive_for_hash.rs b/ldk-server/src/api/bolt11_receive_for_hash.rs index 8f687067..9207c07d 100644 --- a/ldk-server/src/api/bolt11_receive_for_hash.rs +++ b/ldk-server/src/api/bolt11_receive_for_hash.rs @@ -7,26 +7,18 @@ // You may not use this file except in accordance with one or both of these // licenses. -use hex::FromHex; use ldk_node::lightning_types::payment::PaymentHash; -use ldk_server_protos::api::{Bolt11ReceiveForHashRequest, Bolt11ReceiveForHashResponse}; +use ldk_server_json_models::api::{Bolt11ReceiveForHashRequest, Bolt11ReceiveForHashResponse}; use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; -use crate::util::proto_adapter::proto_to_bolt11_description; +use crate::util::adapter::bolt11_description_from_model; pub(crate) fn handle_bolt11_receive_for_hash_request( context: Context, request: Bolt11ReceiveForHashRequest, ) -> Result { - let description = proto_to_bolt11_description(request.description)?; - let hash_bytes = <[u8; 32]>::from_hex(&request.payment_hash).map_err(|_| { - LdkServerError::new( - InvalidRequestError, - "Invalid payment_hash, must be a 32-byte hex string.".to_string(), - ) - })?; - let payment_hash = PaymentHash(hash_bytes); + let description = bolt11_description_from_model(request.description)?; + let payment_hash = PaymentHash(request.payment_hash); let invoice = match request.amount_msat { Some(amount_msat) => context.node.bolt11_payment().receive_for_hash( 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..87c427e9 100644 --- a/ldk-server/src/api/bolt11_receive_via_jit_channel.rs +++ b/ldk-server/src/api/bolt11_receive_via_jit_channel.rs @@ -7,7 +7,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -use ldk_server_protos::api::{ +use ldk_server_json_models::api::{ Bolt11ReceiveVariableAmountViaJitChannelRequest, Bolt11ReceiveVariableAmountViaJitChannelResponse, Bolt11ReceiveViaJitChannelRequest, Bolt11ReceiveViaJitChannelResponse, @@ -15,12 +15,12 @@ use ldk_server_protos::api::{ use crate::api::error::LdkServerError; use crate::service::Context; -use crate::util::proto_adapter::proto_to_bolt11_description; +use crate::util::adapter::bolt11_description_from_model; pub(crate) fn handle_bolt11_receive_via_jit_channel_request( context: Context, request: Bolt11ReceiveViaJitChannelRequest, ) -> Result { - let description = proto_to_bolt11_description(request.description)?; + let description = bolt11_description_from_model(request.description)?; let invoice = context.node.bolt11_payment().receive_via_jit_channel( request.amount_msat, &description, @@ -34,7 +34,7 @@ pub(crate) fn handle_bolt11_receive_via_jit_channel_request( pub(crate) fn handle_bolt11_receive_variable_amount_via_jit_channel_request( context: Context, request: Bolt11ReceiveVariableAmountViaJitChannelRequest, ) -> Result { - let description = proto_to_bolt11_description(request.description)?; + let description = bolt11_description_from_model(request.description)?; let invoice = context.node.bolt11_payment().receive_variable_amount_via_jit_channel( &description, request.expiry_secs, diff --git a/ldk-server/src/api/bolt11_send.rs b/ldk-server/src/api/bolt11_send.rs index 1298896e..ce32362a 100644 --- a/ldk-server/src/api/bolt11_send.rs +++ b/ldk-server/src/api/bolt11_send.rs @@ -10,9 +10,9 @@ use std::str::FromStr; use ldk_node::lightning_invoice::Bolt11Invoice; -use ldk_server_protos::api::{Bolt11SendRequest, Bolt11SendResponse}; +use ldk_server_json_models::api::{Bolt11SendRequest, Bolt11SendResponse}; -use crate::api::build_route_parameters_config_from_proto; +use crate::api::build_route_parameters_config_from_model; use crate::api::error::LdkServerError; use crate::service::Context; @@ -22,7 +22,7 @@ pub(crate) fn handle_bolt11_send_request( let invoice = Bolt11Invoice::from_str(request.invoice.as_str()) .map_err(|_| ldk_node::NodeError::InvalidInvoice)?; - let route_parameters = build_route_parameters_config_from_proto(request.route_parameters)?; + let route_parameters = build_route_parameters_config_from_model(request.route_parameters)?; let payment_id = match request.amount_msat { None => context.node.bolt11_payment().send(&invoice, route_parameters), @@ -31,6 +31,6 @@ pub(crate) fn handle_bolt11_send_request( }, }?; - let response = Bolt11SendResponse { payment_id: payment_id.to_string() }; + let response = Bolt11SendResponse { payment_id: payment_id.0 }; Ok(response) } diff --git a/ldk-server/src/api/bolt12_receive.rs b/ldk-server/src/api/bolt12_receive.rs index 42f4b489..badb0fae 100644 --- a/ldk-server/src/api/bolt12_receive.rs +++ b/ldk-server/src/api/bolt12_receive.rs @@ -7,8 +7,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -use hex::DisplayHex; -use ldk_server_protos::api::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; +use ldk_server_json_models::api::{Bolt12ReceiveRequest, Bolt12ReceiveResponse}; use crate::api::error::LdkServerError; use crate::service::Context; @@ -29,7 +28,7 @@ pub(crate) fn handle_bolt12_receive_request( .receive_variable_amount(&request.description, request.expiry_secs)?, }; - let offer_id = offer.id().0.to_lower_hex_string(); + let offer_id = offer.id().0; let response = Bolt12ReceiveResponse { offer: offer.to_string(), offer_id }; Ok(response) } diff --git a/ldk-server/src/api/bolt12_send.rs b/ldk-server/src/api/bolt12_send.rs index 30df2dd8..4acdda06 100644 --- a/ldk-server/src/api/bolt12_send.rs +++ b/ldk-server/src/api/bolt12_send.rs @@ -10,9 +10,9 @@ use std::str::FromStr; use ldk_node::lightning::offers::offer::Offer; -use ldk_server_protos::api::{Bolt12SendRequest, Bolt12SendResponse}; +use ldk_server_json_models::api::{Bolt12SendRequest, Bolt12SendResponse}; -use crate::api::build_route_parameters_config_from_proto; +use crate::api::build_route_parameters_config_from_model; use crate::api::error::LdkServerError; use crate::service::Context; @@ -22,7 +22,7 @@ pub(crate) fn handle_bolt12_send_request( let offer = Offer::from_str(request.offer.as_str()).map_err(|_| ldk_node::NodeError::InvalidOffer)?; - let route_parameters = build_route_parameters_config_from_proto(request.route_parameters)?; + let route_parameters = build_route_parameters_config_from_model(request.route_parameters)?; let payment_id = match request.amount_msat { None => context.node.bolt12_payment().send( @@ -40,6 +40,6 @@ pub(crate) fn handle_bolt12_send_request( ), }?; - let response = Bolt12SendResponse { payment_id: payment_id.to_string() }; + let response = Bolt12SendResponse { payment_id: payment_id.0 }; Ok(response) } diff --git a/ldk-server/src/api/close_channel.rs b/ldk-server/src/api/close_channel.rs index 5ae4070b..51ce66ed 100644 --- a/ldk-server/src/api/close_channel.rs +++ b/ldk-server/src/api/close_channel.rs @@ -7,11 +7,9 @@ // You may not use this file except in accordance with one or both of these // licenses. -use std::str::FromStr; - use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::UserChannelId; -use ldk_server_protos::api::{ +use ldk_server_json_models::api::{ CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse, }; @@ -52,8 +50,8 @@ fn parse_user_channel_id(id: &str) -> Result { Ok(UserChannelId(parsed)) } -fn parse_counterparty_node_id(id: &str) -> Result { - PublicKey::from_str(id).map_err(|e| { +fn parse_counterparty_node_id(id: &[u8]) -> Result { + PublicKey::from_slice(id).map_err(|e| { LdkServerError::new( InvalidRequestError, format!("Invalid counterparty node ID, error: {}", e), diff --git a/ldk-server/src/api/connect_peer.rs b/ldk-server/src/api/connect_peer.rs index d3fac3a0..1039b67b 100644 --- a/ldk-server/src/api/connect_peer.rs +++ b/ldk-server/src/api/connect_peer.rs @@ -11,7 +11,7 @@ use std::str::FromStr; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::lightning::ln::msgs::SocketAddress; -use ldk_server_protos::api::{ConnectPeerRequest, ConnectPeerResponse}; +use ldk_server_json_models::api::{ConnectPeerRequest, ConnectPeerResponse}; use crate::api::error::LdkServerError; use crate::service::Context; @@ -19,7 +19,7 @@ use crate::service::Context; pub(crate) fn handle_connect_peer( context: Context, request: ConnectPeerRequest, ) -> Result { - let node_id = PublicKey::from_str(&request.node_pubkey) + let node_id = PublicKey::from_slice(&request.node_pubkey) .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; let address = SocketAddress::from_str(&request.address) .map_err(|_| ldk_node::NodeError::InvalidSocketAddress)?; diff --git a/ldk-server/src/api/disconnect_peer.rs b/ldk-server/src/api/disconnect_peer.rs index 76f2ecce..8903e978 100644 --- a/ldk-server/src/api/disconnect_peer.rs +++ b/ldk-server/src/api/disconnect_peer.rs @@ -7,10 +7,8 @@ // You may not use this file except in accordance with one or both of these // licenses. -use std::str::FromStr; - use ldk_node::bitcoin::secp256k1::PublicKey; -use ldk_server_protos::api::{DisconnectPeerRequest, DisconnectPeerResponse}; +use ldk_server_json_models::api::{DisconnectPeerRequest, DisconnectPeerResponse}; use crate::api::error::LdkServerError; use crate::service::Context; @@ -18,7 +16,7 @@ use crate::service::Context; pub(crate) fn handle_disconnect_peer( context: Context, request: DisconnectPeerRequest, ) -> Result { - let node_id = PublicKey::from_str(&request.node_pubkey) + let node_id = PublicKey::from_slice(&request.node_pubkey) .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; context.node.disconnect(node_id)?; diff --git a/ldk-server/src/api/error.rs b/ldk-server/src/api/error.rs index ad1c152f..b1b99999 100644 --- a/ldk-server/src/api/error.rs +++ b/ldk-server/src/api/error.rs @@ -41,16 +41,16 @@ impl fmt::Display for LdkServerError { #[derive(Clone, Debug, PartialEq, Eq)] #[allow(clippy::enum_variant_names)] pub(crate) enum LdkServerErrorCode { - /// Please refer to [`protos::error::ErrorCode::InvalidRequestError`]. + /// See [`ldk_server_json_models::error::ErrorCode::InvalidRequestError`]. InvalidRequestError, - /// Please refer to [`protos::error::ErrorCode::AuthError`]. + /// See [`ldk_server_json_models::error::ErrorCode::AuthError`]. AuthError, - /// Please refer to [`protos::error::ErrorCode::LightningError`]. + /// See [`ldk_server_json_models::error::ErrorCode::LightningError`]. LightningError, - /// Please refer to [`protos::error::ErrorCode::InternalServerError`]. + /// See [`ldk_server_json_models::error::ErrorCode::InternalServerError`]. InternalServerError, } diff --git a/ldk-server/src/api/export_pathfinding_scores.rs b/ldk-server/src/api/export_pathfinding_scores.rs index a6924a22..095ebf4d 100644 --- a/ldk-server/src/api/export_pathfinding_scores.rs +++ b/ldk-server/src/api/export_pathfinding_scores.rs @@ -7,7 +7,9 @@ // You may not use this file except in accordance with one or both of these // licenses. -use ldk_server_protos::api::{ExportPathfindingScoresRequest, ExportPathfindingScoresResponse}; +use ldk_server_json_models::api::{ + ExportPathfindingScoresRequest, ExportPathfindingScoresResponse, +}; use crate::api::error::LdkServerError; use crate::service::Context; @@ -17,6 +19,6 @@ pub(crate) fn handle_export_pathfinding_scores_request( ) -> Result { let scores = context.node.export_pathfinding_scores()?; - let response = ExportPathfindingScoresResponse { scores: scores.into() }; + let response = ExportPathfindingScoresResponse { scores }; Ok(response) } diff --git a/ldk-server/src/api/get_balances.rs b/ldk-server/src/api/get_balances.rs index 82ab69b7..90a7af27 100644 --- a/ldk-server/src/api/get_balances.rs +++ b/ldk-server/src/api/get_balances.rs @@ -7,11 +7,11 @@ // You may not use this file except in accordance with one or both of these // licenses. -use ldk_server_protos::api::{GetBalancesRequest, GetBalancesResponse}; +use ldk_server_json_models::api::{GetBalancesRequest, GetBalancesResponse}; use crate::api::error::LdkServerError; use crate::service::Context; -use crate::util::proto_adapter::{lightning_balance_to_proto, pending_sweep_balance_to_proto}; +use crate::util::adapter::{lightning_balance_to_model, pending_sweep_balance_to_model}; pub(crate) fn handle_get_balances_request( context: Context, _request: GetBalancesRequest, @@ -26,12 +26,12 @@ pub(crate) fn handle_get_balances_request( lightning_balances: balance_details .lightning_balances .into_iter() - .map(lightning_balance_to_proto) + .map(lightning_balance_to_model) .collect(), pending_balances_from_channel_closures: balance_details .pending_balances_from_channel_closures .into_iter() - .map(pending_sweep_balance_to_proto) + .map(pending_sweep_balance_to_model) .collect(), }; Ok(response) diff --git a/ldk-server/src/api/get_node_info.rs b/ldk-server/src/api/get_node_info.rs index c1b81279..f1943275 100644 --- a/ldk-server/src/api/get_node_info.rs +++ b/ldk-server/src/api/get_node_info.rs @@ -7,8 +7,9 @@ // You may not use this file except in accordance with one or both of these // licenses. -use ldk_server_protos::api::{GetNodeInfoRequest, GetNodeInfoResponse}; -use ldk_server_protos::types::BestBlock; +use ldk_node::bitcoin::hashes::Hash as _; +use ldk_server_json_models::api::{GetNodeInfoRequest, GetNodeInfoResponse}; +use ldk_server_json_models::types::BestBlock; use crate::api::error::LdkServerError; use crate::service::Context; @@ -19,7 +20,7 @@ pub(crate) fn handle_get_node_info_request( let node_status = context.node.status(); let best_block = BestBlock { - block_hash: node_status.current_best_block.block_hash.to_string(), + block_hash: node_status.current_best_block.block_hash.to_byte_array(), height: node_status.current_best_block.height, }; @@ -37,7 +38,7 @@ pub(crate) fn handle_get_node_info_request( let node_alias = context.node.node_alias().map(|alias| alias.to_string()); - let node_id = context.node.node_id().to_string(); + let node_id = context.node.node_id(); let node_uris = { let addrs = if announcement_addresses.is_empty() { @@ -48,8 +49,8 @@ pub(crate) fn handle_get_node_info_request( addrs.into_iter().map(|a| format!("{node_id}@{a}")).collect() }; let response = GetNodeInfoResponse { - node_id, - current_best_block: Some(best_block), + node_id: node_id.serialize(), + current_best_block: best_block, latest_lightning_wallet_sync_timestamp: node_status.latest_lightning_wallet_sync_timestamp, latest_onchain_wallet_sync_timestamp: node_status.latest_onchain_wallet_sync_timestamp, latest_fee_rate_cache_update_timestamp: node_status.latest_fee_rate_cache_update_timestamp, diff --git a/ldk-server/src/api/get_payment_details.rs b/ldk-server/src/api/get_payment_details.rs index 1d7b266a..140f4142 100644 --- a/ldk-server/src/api/get_payment_details.rs +++ b/ldk-server/src/api/get_payment_details.rs @@ -7,29 +7,19 @@ // You may not use this file except in accordance with one or both of these // licenses. -use hex::FromHex; use ldk_node::lightning::ln::channelmanager::PaymentId; -use ldk_server_protos::api::{GetPaymentDetailsRequest, GetPaymentDetailsResponse}; +use ldk_server_json_models::api::{GetPaymentDetailsRequest, GetPaymentDetailsResponse}; use crate::api::error::LdkServerError; -use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; -use crate::util::proto_adapter::payment_to_proto; +use crate::util::adapter::payment_to_model; pub(crate) fn handle_get_payment_details_request( context: Context, request: GetPaymentDetailsRequest, ) -> Result { - let payment_id_bytes = - <[u8; PaymentId::LENGTH]>::from_hex(&request.payment_id).map_err(|_| { - LdkServerError::new( - InvalidRequestError, - format!("Invalid payment_id, must be a {}-byte hex-string.", PaymentId::LENGTH), - ) - })?; + let payment_details = context.node.payment(&PaymentId(request.payment_id)); - let payment_details = context.node.payment(&PaymentId(payment_id_bytes)); - - let response = GetPaymentDetailsResponse { payment: payment_details.map(payment_to_proto) }; + let response = GetPaymentDetailsResponse { payment: payment_details.map(payment_to_model) }; Ok(response) } diff --git a/ldk-server/src/api/graph_get_channel.rs b/ldk-server/src/api/graph_get_channel.rs index 3e20a2a0..4b896f14 100644 --- a/ldk-server/src/api/graph_get_channel.rs +++ b/ldk-server/src/api/graph_get_channel.rs @@ -7,12 +7,12 @@ // You may not use this file except in accordance with one or both of these // licenses. -use ldk_server_protos::api::{GraphGetChannelRequest, GraphGetChannelResponse}; +use ldk_server_json_models::api::{GraphGetChannelRequest, GraphGetChannelResponse}; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; -use crate::util::proto_adapter::graph_channel_to_proto; +use crate::util::adapter::graph_channel_to_model; pub(crate) fn handle_graph_get_channel_request( context: Context, request: GraphGetChannelRequest, @@ -28,6 +28,6 @@ pub(crate) fn handle_graph_get_channel_request( ) })?; - let response = GraphGetChannelResponse { channel: Some(graph_channel_to_proto(channel_info)) }; + let response = GraphGetChannelResponse { channel: Some(graph_channel_to_model(channel_info)) }; Ok(response) } diff --git a/ldk-server/src/api/graph_get_node.rs b/ldk-server/src/api/graph_get_node.rs index 9ddb0eac..3b210ef5 100644 --- a/ldk-server/src/api/graph_get_node.rs +++ b/ldk-server/src/api/graph_get_node.rs @@ -8,30 +8,27 @@ // licenses. use ldk_node::lightning::routing::gossip::NodeId; -use ldk_server_protos::api::{GraphGetNodeRequest, GraphGetNodeResponse}; +use ldk_server_json_models::api::{GraphGetNodeRequest, GraphGetNodeResponse}; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; -use crate::util::proto_adapter::graph_node_to_proto; +use crate::util::adapter::graph_node_to_model; pub(crate) fn handle_graph_get_node_request( context: Context, request: GraphGetNodeRequest, ) -> Result { - let node_id: NodeId = request.node_id.parse().map_err(|_| { + let node_id = NodeId::from_slice(&request.node_id).map_err(|_| { LdkServerError::new( InvalidRequestError, - format!("Invalid node_id: {}. Expected a hex-encoded public key.", request.node_id), + "Invalid node_id: expected a valid 33-byte public key.".to_string(), ) })?; let node_info = context.node.network_graph().node(&node_id).ok_or_else(|| { - LdkServerError::new( - InvalidRequestError, - format!("Node with ID {} not found in the network graph.", request.node_id), - ) + LdkServerError::new(InvalidRequestError, "Node not found in the network graph.".to_string()) })?; - let response = GraphGetNodeResponse { node: Some(graph_node_to_proto(node_info)) }; + let response = GraphGetNodeResponse { node: Some(graph_node_to_model(node_info)) }; Ok(response) } diff --git a/ldk-server/src/api/graph_list_channels.rs b/ldk-server/src/api/graph_list_channels.rs index 60543292..2cee05cb 100644 --- a/ldk-server/src/api/graph_list_channels.rs +++ b/ldk-server/src/api/graph_list_channels.rs @@ -7,7 +7,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -use ldk_server_protos::api::{GraphListChannelsRequest, GraphListChannelsResponse}; +use ldk_server_json_models::api::{GraphListChannelsRequest, GraphListChannelsResponse}; use crate::api::error::LdkServerError; use crate::service::Context; diff --git a/ldk-server/src/api/graph_list_nodes.rs b/ldk-server/src/api/graph_list_nodes.rs index 64ccd295..8a3c0283 100644 --- a/ldk-server/src/api/graph_list_nodes.rs +++ b/ldk-server/src/api/graph_list_nodes.rs @@ -7,7 +7,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -use ldk_server_protos::api::{GraphListNodesRequest, GraphListNodesResponse}; +use ldk_server_json_models::api::{GraphListNodesRequest, GraphListNodesResponse}; use crate::api::error::LdkServerError; use crate::service::Context; diff --git a/ldk-server/src/api/list_channels.rs b/ldk-server/src/api/list_channels.rs index 84d1584b..f133c9bd 100644 --- a/ldk-server/src/api/list_channels.rs +++ b/ldk-server/src/api/list_channels.rs @@ -7,16 +7,16 @@ // You may not use this file except in accordance with one or both of these // licenses. -use ldk_server_protos::api::{ListChannelsRequest, ListChannelsResponse}; +use ldk_server_json_models::api::{ListChannelsRequest, ListChannelsResponse}; use crate::api::error::LdkServerError; use crate::service::Context; -use crate::util::proto_adapter::channel_to_proto; +use crate::util::adapter::channel_to_model; pub(crate) fn handle_list_channels_request( context: Context, _request: ListChannelsRequest, ) -> Result { - let channels = context.node.list_channels().into_iter().map(channel_to_proto).collect(); + let channels = context.node.list_channels().into_iter().map(channel_to_model).collect(); let response = ListChannelsResponse { channels }; Ok(response) diff --git a/ldk-server/src/api/list_forwarded_payments.rs b/ldk-server/src/api/list_forwarded_payments.rs index 78ce3dc4..6fb70f42 100644 --- a/ldk-server/src/api/list_forwarded_payments.rs +++ b/ldk-server/src/api/list_forwarded_payments.rs @@ -7,10 +7,8 @@ // You may not use this file except in accordance with one or both of these // licenses. -use bytes::Bytes; -use ldk_server_protos::api::{ListForwardedPaymentsRequest, ListForwardedPaymentsResponse}; -use ldk_server_protos::types::{ForwardedPayment, PageToken}; -use prost::Message; +use ldk_server_json_models::api::{ListForwardedPaymentsRequest, ListForwardedPaymentsResponse}; +use ldk_server_json_models::types::{ForwardedPayment, PageToken}; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InternalServerError; @@ -54,8 +52,8 @@ pub(crate) fn handle_list_forwarded_payments_request( format!("Failed to read forwarded payment data: {}", e), ) })?; - let forwarded_payment = ForwardedPayment::decode(Bytes::from(forwarded_payment_bytes)) - .map_err(|e| { + let forwarded_payment = + serde_json::from_slice::(&forwarded_payment_bytes).map_err(|e| { LdkServerError::new( InternalServerError, format!("Failed to decode forwarded payment: {}", e), diff --git a/ldk-server/src/api/list_payments.rs b/ldk-server/src/api/list_payments.rs index fbaf7c55..9cd645e5 100644 --- a/ldk-server/src/api/list_payments.rs +++ b/ldk-server/src/api/list_payments.rs @@ -7,10 +7,8 @@ // You may not use this file except in accordance with one or both of these // licenses. -use bytes::Bytes; -use ldk_server_protos::api::{ListPaymentsRequest, ListPaymentsResponse}; -use ldk_server_protos::types::{PageToken, Payment}; -use prost::Message; +use ldk_server_json_models::api::{ListPaymentsRequest, ListPaymentsResponse}; +use ldk_server_json_models::types::{PageToken, Payment}; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InternalServerError; @@ -49,7 +47,7 @@ pub(crate) fn handle_list_payments_request( format!("Failed to read payment data: {}", e), ) })?; - let payment = Payment::decode(Bytes::from(payment_bytes)).map_err(|e| { + let payment = serde_json::from_slice::(&payment_bytes).map_err(|e| { LdkServerError::new(InternalServerError, format!("Failed to decode payment: {}", e)) })?; payments.push(payment); diff --git a/ldk-server/src/api/list_peers.rs b/ldk-server/src/api/list_peers.rs index c75e119e..54203c5f 100644 --- a/ldk-server/src/api/list_peers.rs +++ b/ldk-server/src/api/list_peers.rs @@ -7,16 +7,16 @@ // You may not use this file except in accordance with one or both of these // licenses. -use ldk_server_protos::api::{ListPeersRequest, ListPeersResponse}; +use ldk_server_json_models::api::{ListPeersRequest, ListPeersResponse}; use crate::api::error::LdkServerError; use crate::service::Context; -use crate::util::proto_adapter::peer_to_proto; +use crate::util::adapter::peer_to_model; pub(crate) fn handle_list_peers_request( context: Context, _request: ListPeersRequest, ) -> Result { - let peers = context.node.list_peers().into_iter().map(peer_to_proto).collect(); + let peers = context.node.list_peers().into_iter().map(peer_to_model).collect(); let response = ListPeersResponse { peers }; Ok(response) diff --git a/ldk-server/src/api/mod.rs b/ldk-server/src/api/mod.rs index ab8d7d53..38712a1b 100644 --- a/ldk-server/src/api/mod.rs +++ b/ldk-server/src/api/mod.rs @@ -9,7 +9,7 @@ use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; use ldk_node::lightning::routing::router::RouteParametersConfig; -use ldk_server_protos::types::channel_config::MaxDustHtlcExposure; +use ldk_server_json_models::types::MaxDustHtlcExposure; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; @@ -48,10 +48,11 @@ pub(crate) mod unified_send; pub(crate) mod update_channel_config; pub(crate) mod verify_signature; -pub(crate) fn build_channel_config_from_proto( - default_config: ChannelConfig, proto_channel_config: ldk_server_protos::types::ChannelConfig, +pub(crate) fn build_channel_config_from_model( + default_config: ChannelConfig, + channel_config_model: ldk_server_json_models::types::ChannelConfig, ) -> Result { - let max_dust_htlc_exposure = proto_channel_config + let max_dust_htlc_exposure = channel_config_model .max_dust_htlc_exposure .map(|max_dust_htlc_exposure| match max_dust_htlc_exposure { MaxDustHtlcExposure::FixedLimitMsat(limit_msat) => { @@ -63,7 +64,7 @@ pub(crate) fn build_channel_config_from_proto( }) .unwrap_or(default_config.max_dust_htlc_exposure); - let cltv_expiry_delta = match proto_channel_config.cltv_expiry_delta { + let cltv_expiry_delta = match channel_config_model.cltv_expiry_delta { Some(c) => Some(u16::try_from(c).map_err(|_| { LdkServerError::new( InvalidRequestError, @@ -75,27 +76,27 @@ pub(crate) fn build_channel_config_from_proto( .unwrap_or(default_config.cltv_expiry_delta); Ok(ChannelConfig { - forwarding_fee_proportional_millionths: proto_channel_config + forwarding_fee_proportional_millionths: channel_config_model .forwarding_fee_proportional_millionths .unwrap_or(default_config.forwarding_fee_proportional_millionths), - forwarding_fee_base_msat: proto_channel_config + forwarding_fee_base_msat: channel_config_model .forwarding_fee_base_msat .unwrap_or(default_config.forwarding_fee_base_msat), cltv_expiry_delta, max_dust_htlc_exposure, - force_close_avoidance_max_fee_satoshis: proto_channel_config + force_close_avoidance_max_fee_satoshis: channel_config_model .force_close_avoidance_max_fee_satoshis .unwrap_or(default_config.force_close_avoidance_max_fee_satoshis), - accept_underpaying_htlcs: proto_channel_config + accept_underpaying_htlcs: channel_config_model .accept_underpaying_htlcs .unwrap_or(default_config.accept_underpaying_htlcs), }) } -pub(crate) fn build_route_parameters_config_from_proto( - proto_route_params: Option, +pub(crate) fn build_route_parameters_config_from_model( + route_params_model: Option, ) -> Result, LdkServerError> { - match proto_route_params { + match route_params_model { Some(params) => { let max_path_count = params.max_path_count.try_into().map_err(|_| { LdkServerError::new( diff --git a/ldk-server/src/api/onchain_receive.rs b/ldk-server/src/api/onchain_receive.rs index cad2837e..389cec84 100644 --- a/ldk-server/src/api/onchain_receive.rs +++ b/ldk-server/src/api/onchain_receive.rs @@ -7,7 +7,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -use ldk_server_protos::api::{OnchainReceiveRequest, OnchainReceiveResponse}; +use ldk_server_json_models::api::{OnchainReceiveRequest, OnchainReceiveResponse}; use crate::api::error::LdkServerError; use crate::service::Context; diff --git a/ldk-server/src/api/onchain_send.rs b/ldk-server/src/api/onchain_send.rs index 6eb1d63a..2b116b3a 100644 --- a/ldk-server/src/api/onchain_send.rs +++ b/ldk-server/src/api/onchain_send.rs @@ -9,8 +9,9 @@ use std::str::FromStr; +use ldk_node::bitcoin::hashes::Hash as _; use ldk_node::bitcoin::{Address, FeeRate}; -use ldk_server_protos::api::{OnchainSendRequest, OnchainSendResponse}; +use ldk_server_json_models::api::{OnchainSendRequest, OnchainSendResponse}; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; @@ -45,6 +46,6 @@ pub(crate) fn handle_onchain_send_request( )) }, }; - let response = OnchainSendResponse { txid: txid.to_string() }; + let response = OnchainSendResponse { txid: txid.to_byte_array() }; Ok(response) } diff --git a/ldk-server/src/api/open_channel.rs b/ldk-server/src/api/open_channel.rs index 6c470b71..a765ff6d 100644 --- a/ldk-server/src/api/open_channel.rs +++ b/ldk-server/src/api/open_channel.rs @@ -12,23 +12,23 @@ use std::str::FromStr; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::config::ChannelConfig; use ldk_node::lightning::ln::msgs::SocketAddress; -use ldk_server_protos::api::{OpenChannelRequest, OpenChannelResponse}; +use ldk_server_json_models::api::{OpenChannelRequest, OpenChannelResponse}; -use crate::api::build_channel_config_from_proto; +use crate::api::build_channel_config_from_model; use crate::api::error::LdkServerError; use crate::service::Context; pub(crate) fn handle_open_channel( context: Context, request: OpenChannelRequest, ) -> Result { - let node_id = PublicKey::from_str(&request.node_pubkey) + let node_id = PublicKey::from_slice(&request.node_pubkey) .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; let address = SocketAddress::from_str(&request.address) .map_err(|_| ldk_node::NodeError::InvalidSocketAddress)?; let channel_config = request .channel_config - .map(|proto_config| build_channel_config_from_proto(ChannelConfig::default(), proto_config)) + .map(|config_model| build_channel_config_from_model(ChannelConfig::default(), config_model)) .transpose()?; let user_channel_id = if request.announce_channel { diff --git a/ldk-server/src/api/sign_message.rs b/ldk-server/src/api/sign_message.rs index 8ef0e015..a4be8b18 100644 --- a/ldk-server/src/api/sign_message.rs +++ b/ldk-server/src/api/sign_message.rs @@ -7,7 +7,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -use ldk_server_protos::api::{SignMessageRequest, SignMessageResponse}; +use ldk_server_json_models::api::{SignMessageRequest, SignMessageResponse}; use crate::api::error::LdkServerError; use crate::service::Context; diff --git a/ldk-server/src/api/splice_channel.rs b/ldk-server/src/api/splice_channel.rs index 5d6edfec..1f6f2518 100644 --- a/ldk-server/src/api/splice_channel.rs +++ b/ldk-server/src/api/splice_channel.rs @@ -12,7 +12,7 @@ use std::str::FromStr; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::bitcoin::Address; use ldk_node::UserChannelId; -use ldk_server_protos::api::{ +use ldk_server_json_models::api::{ SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse, }; @@ -69,8 +69,8 @@ fn parse_user_channel_id(id: &str) -> Result { Ok(UserChannelId(parsed)) } -fn parse_counterparty_node_id(id: &str) -> Result { - PublicKey::from_str(id).map_err(|e| { +fn parse_counterparty_node_id(id: &[u8]) -> Result { + PublicKey::from_slice(id).map_err(|e| { LdkServerError::new( InvalidRequestError, format!("Invalid counterparty node ID, error: {}", e), diff --git a/ldk-server/src/api/spontaneous_send.rs b/ldk-server/src/api/spontaneous_send.rs index 77fe3b8a..b1058b96 100644 --- a/ldk-server/src/api/spontaneous_send.rs +++ b/ldk-server/src/api/spontaneous_send.rs @@ -7,12 +7,10 @@ // You may not use this file except in accordance with one or both of these // licenses. -use std::str::FromStr; - use ldk_node::bitcoin::secp256k1::PublicKey; -use ldk_server_protos::api::{SpontaneousSendRequest, SpontaneousSendResponse}; +use ldk_server_json_models::api::{SpontaneousSendRequest, SpontaneousSendResponse}; -use crate::api::build_route_parameters_config_from_proto; +use crate::api::build_route_parameters_config_from_model; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; use crate::service::Context; @@ -20,15 +18,15 @@ use crate::service::Context; pub(crate) fn handle_spontaneous_send_request( context: Context, request: SpontaneousSendRequest, ) -> Result { - let node_id = PublicKey::from_str(&request.node_id).map_err(|_| { + let node_id = PublicKey::from_slice(&request.node_id).map_err(|_| { LdkServerError::new(InvalidRequestError, "Invalid node_id provided.".to_string()) })?; - let route_parameters = build_route_parameters_config_from_proto(request.route_parameters)?; + let route_parameters = build_route_parameters_config_from_model(request.route_parameters)?; let payment_id = context.node.spontaneous_payment().send(request.amount_msat, node_id, route_parameters)?; - let response = SpontaneousSendResponse { payment_id: payment_id.to_string() }; + let response = SpontaneousSendResponse { payment_id: payment_id.0 }; Ok(response) } diff --git a/ldk-server/src/api/unified_send.rs b/ldk-server/src/api/unified_send.rs index 3f7807b4..21d09e13 100644 --- a/ldk-server/src/api/unified_send.rs +++ b/ldk-server/src/api/unified_send.rs @@ -8,18 +8,19 @@ // licenses. use ldk_node::payment::UnifiedPaymentResult; -use ldk_server_protos::api::unified_send_response::PaymentResult; -use ldk_server_protos::api::{UnifiedSendRequest, UnifiedSendResponse}; +use ldk_server_json_models::api::{ + UnifiedSendPaymentResult, UnifiedSendRequest, UnifiedSendResponse, +}; use tokio::runtime::Handle; -use crate::api::build_route_parameters_config_from_proto; +use crate::api::build_route_parameters_config_from_model; use crate::api::error::LdkServerError; use crate::service::Context; pub(crate) fn handle_unified_send_request( context: Context, request: UnifiedSendRequest, ) -> Result { - let route_parameters = build_route_parameters_config_from_proto(request.route_parameters)?; + let route_parameters = build_route_parameters_config_from_model(request.route_parameters)?; let result = tokio::task::block_in_place(|| { Handle::current().block_on(context.node.unified_payment().send( @@ -30,12 +31,12 @@ pub(crate) fn handle_unified_send_request( })?; let payment_result = match result { - UnifiedPaymentResult::Onchain { txid } => PaymentResult::Txid(txid.to_string()), + UnifiedPaymentResult::Onchain { txid } => UnifiedSendPaymentResult::Txid(txid.to_string()), UnifiedPaymentResult::Bolt11 { payment_id } => { - PaymentResult::Bolt11PaymentId(payment_id.to_string()) + UnifiedSendPaymentResult::Bolt11PaymentId(payment_id.to_string()) }, UnifiedPaymentResult::Bolt12 { payment_id } => { - PaymentResult::Bolt12PaymentId(payment_id.to_string()) + UnifiedSendPaymentResult::Bolt12PaymentId(payment_id.to_string()) }, }; diff --git a/ldk-server/src/api/update_channel_config.rs b/ldk-server/src/api/update_channel_config.rs index 780374c5..14f13a26 100644 --- a/ldk-server/src/api/update_channel_config.rs +++ b/ldk-server/src/api/update_channel_config.rs @@ -7,13 +7,11 @@ // You may not use this file except in accordance with one or both of these // licenses. -use std::str::FromStr; - use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::UserChannelId; -use ldk_server_protos::api::{UpdateChannelConfigRequest, UpdateChannelConfigResponse}; +use ldk_server_json_models::api::{UpdateChannelConfigRequest, UpdateChannelConfigResponse}; -use crate::api::build_channel_config_from_proto; +use crate::api::build_channel_config_from_model; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::{InvalidRequestError, LightningError}; use crate::service::Context; @@ -37,19 +35,20 @@ pub(crate) fn handle_update_channel_config_request( })? .config; - let updated_channel_config = build_channel_config_from_proto( + let updated_channel_config = build_channel_config_from_model( current_config, request.channel_config.ok_or_else(|| { LdkServerError::new(InvalidRequestError, "Channel config must be provided.") })?, )?; - let counterparty_node_id = PublicKey::from_str(&request.counterparty_node_id).map_err(|e| { - LdkServerError::new( - InvalidRequestError, - format!("Invalid counterparty node id, error {}", e), - ) - })?; + let counterparty_node_id = + PublicKey::from_slice(&request.counterparty_node_id).map_err(|e| { + LdkServerError::new( + InvalidRequestError, + format!("Invalid counterparty node id, error {}", e), + ) + })?; context .node diff --git a/ldk-server/src/api/verify_signature.rs b/ldk-server/src/api/verify_signature.rs index 9b7551ea..dcbbd4b6 100644 --- a/ldk-server/src/api/verify_signature.rs +++ b/ldk-server/src/api/verify_signature.rs @@ -7,10 +7,8 @@ // You may not use this file except in accordance with one or both of these // licenses. -use std::str::FromStr; - use ldk_node::bitcoin::secp256k1::PublicKey; -use ldk_server_protos::api::{VerifySignatureRequest, VerifySignatureResponse}; +use ldk_server_json_models::api::{VerifySignatureRequest, VerifySignatureResponse}; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; @@ -19,7 +17,7 @@ use crate::service::Context; pub(crate) fn handle_verify_signature_request( context: Context, request: VerifySignatureRequest, ) -> Result { - let public_key = PublicKey::from_str(&request.public_key).map_err(|_| { + let public_key = PublicKey::from_slice(&request.public_key).map_err(|_| { LdkServerError::new(InvalidRequestError, "Invalid public_key provided.".to_string()) })?; 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 index 4ec9a65a..993a8478 100644 --- a/ldk-server/src/io/events/mod.rs +++ b/ldk-server/src/io/events/mod.rs @@ -7,20 +7,17 @@ // You may not use this file except in accordance with one or both of these // licenses. -pub(crate) mod event_publisher; +pub(crate) mod sse; -#[cfg(feature = "events-rabbitmq")] -pub(crate) mod rabbitmq; - -use ldk_server_protos::events::event_envelope; +use ldk_server_json_models::events::Event; /// Event variant to event name mapping. -pub(crate) fn get_event_name(event: &event_envelope::Event) -> &'static str { +pub(crate) fn get_event_name(event: &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", + Event::PaymentReceived(_) => "PaymentReceived", + Event::PaymentSuccessful(_) => "PaymentSuccessful", + Event::PaymentFailed(_) => "PaymentFailed", + Event::PaymentForwarded(_) => "PaymentForwarded", + 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/events/sse.rs b/ldk-server/src/io/events/sse.rs new file mode 100644 index 00000000..b23ea248 --- /dev/null +++ b/ldk-server/src/io/events/sse.rs @@ -0,0 +1,76 @@ +// 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::task::{Context, Poll}; + +use hyper::body::{Bytes, Frame}; +use ldk_server_json_models::events::Event; +use log::warn; +use tokio::sync::{broadcast, mpsc}; + +use super::get_event_name; + +/// An HTTP body that streams Server-Sent Events from a broadcast channel. +/// +/// Uses an internal mpsc channel bridged from the broadcast receiver via a +/// spawned task, so that `poll_frame` can poll a `Receiver` directly. +pub(crate) struct SseBody { + receiver: mpsc::Receiver, +} + +impl SseBody { + pub(crate) fn new(broadcast_rx: broadcast::Receiver) -> Self { + let (tx, rx) = mpsc::channel(64); + tokio::spawn(bridge_broadcast_to_mpsc(broadcast_rx, tx)); + Self { receiver: rx } + } +} + +async fn bridge_broadcast_to_mpsc( + mut broadcast_rx: broadcast::Receiver, tx: mpsc::Sender, +) { + loop { + match broadcast_rx.recv().await { + Ok(event) => { + if tx.send(event).await.is_err() { + break; + } + }, + Err(broadcast::error::RecvError::Lagged(n)) => { + warn!("SSE subscriber lagged, skipped {n} events"); + }, + Err(broadcast::error::RecvError::Closed) => break, + } + } +} + +impl hyper::body::Body for SseBody { + type Data = Bytes; + type Error = std::convert::Infallible; + + fn poll_frame( + mut self: Pin<&mut Self>, cx: &mut Context<'_>, + ) -> Poll, Self::Error>>> { + match self.receiver.poll_recv(cx) { + Poll::Ready(Some(event)) => { + let encoded = format_sse_event(&event); + Poll::Ready(Some(Ok(Frame::data(Bytes::from(encoded))))) + }, + Poll::Ready(None) => Poll::Ready(None), + Poll::Pending => Poll::Pending, + } + } +} + +fn format_sse_event(event: &Event) -> String { + let event_name = get_event_name(event); + let data = serde_json::to_string(event).unwrap(); + format!("event: {event_name}\ndata: {data}\n\n") +} diff --git a/ldk-server/src/io/persist/mod.rs b/ldk-server/src/io/persist/mod.rs index 6c01795b..53f0c198 100644 --- a/ldk-server/src/io/persist/mod.rs +++ b/ldk-server/src/io/persist/mod.rs @@ -11,9 +11,9 @@ pub(crate) mod paginated_kv_store; pub(crate) mod sqlite_store; /// The forwarded payments will be persisted under this prefix. -pub(crate) const FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE: &str = "forwarded_payments"; -pub(crate) const FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE: &str = ""; +pub(crate) const FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE: &str = "ldk-server"; +pub(crate) const FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE: &str = "forwarded_payments"; /// The payments will be persisted under this prefix. -pub(crate) const PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE: &str = "payments"; -pub(crate) const PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE: &str = ""; +pub(crate) const PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE: &str = "ldk-server"; +pub(crate) const PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE: &str = "payments"; diff --git a/ldk-server/src/main.rs b/ldk-server/src/main.rs index 3de2a408..e4bae32c 100644 --- a/ldk-server/src/main.rs +++ b/ldk-server/src/main.rs @@ -9,6 +9,7 @@ mod api; mod io; +mod openapi; mod service; mod util; @@ -27,20 +28,17 @@ use ldk_node::config::Config; use ldk_node::entropy::NodeEntropy; use ldk_node::lightning::ln::channelmanager::PaymentId; use ldk_node::{Builder, Event, Node}; -use ldk_server_protos::events; -use ldk_server_protos::events::{event_envelope, EventEnvelope}; -use ldk_server_protos::types::Payment; +use ldk_server_json_models::events; +use ldk_server_json_models::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 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::io::persist::paginated_kv_store::PaginatedKVStore; + use crate::io::persist::sqlite_store::SqliteStore; use crate::io::persist::{ FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, @@ -48,9 +46,9 @@ use crate::io::persist::{ PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, }; use crate::service::NodeService; +use crate::util::adapter::{forwarded_payment_to_model, payment_to_model}; 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; @@ -222,18 +220,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::(256); info!("Starting up..."); match node.start() { @@ -322,43 +309,43 @@ fn main() { 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()), + |payment_ref| events::Event::PaymentReceived(events::PaymentReceived { + payment: payment_ref.clone(), }), &event_node, - Arc::clone(&event_publisher), - Arc::clone(&paginated_store)).await; + &event_sender, + Arc::clone(&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()), + |payment_ref| events::Event::PaymentSuccessful(events::PaymentSuccessful { + payment: payment_ref.clone(), }), &event_node, - Arc::clone(&event_publisher), - Arc::clone(&paginated_store)).await; + &event_sender, + Arc::clone(&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()), + |payment_ref| events::Event::PaymentFailed(events::PaymentFailed { + payment: payment_ref.clone(), }), &event_node, - Arc::clone(&event_publisher), - Arc::clone(&paginated_store)).await; + &event_sender, + Arc::clone(&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()), + |payment_ref| events::Event::PaymentClaimable(events::PaymentClaimable { + payment: payment_ref.clone(), }), &event_node, - Arc::clone(&event_publisher), - Arc::clone(&paginated_store)).await; + &event_sender, + Arc::clone(&paginated_store)); }, Event::PaymentForwarded { prev_channel_id, @@ -377,7 +364,7 @@ fn main() { 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( + let forwarded_payment = forwarded_payment_to_model( prev_channel_id, next_channel_id, prev_user_channel_id, @@ -398,22 +385,16 @@ fn main() { let forwarded_payment_creation_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs() as i64; - match event_publisher.publish(EventEnvelope { - event: Some(event_envelope::Event::PaymentForwarded(events::PaymentForwarded { - forwarded_payment: Some(forwarded_payment.clone()), - })), - }).await { - Ok(_) => {}, - Err(e) => { - error!("Failed to publish 'PaymentForwarded' event: {}", e); - continue; - } - }; + let _ = event_sender.send( + events::Event::PaymentForwarded(events::PaymentForwarded { + forwarded_payment: forwarded_payment.clone(), + }), + ); 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(), + &serde_json::to_vec(&forwarded_payment).unwrap(), ) { Ok(_) => { if let Err(e) = event_node.event_handled() { @@ -435,7 +416,7 @@ fn main() { 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 node_service = NodeService::new(Arc::clone(&node), Arc::clone(&paginated_store), api_key.clone(), event_sender.clone()); let acceptor = tls_acceptor.clone(); runtime.spawn(async move { match acceptor.accept(stream).await { @@ -474,23 +455,18 @@ fn main() { info!("Shutdown complete.."); } -async fn publish_event_and_upsert_payment( - payment_id: &PaymentId, payment_to_event: fn(&Payment) -> event_envelope::Event, - event_node: &Node, event_publisher: Arc, - paginated_store: Arc, +fn publish_event_and_upsert_payment( + payment_id: &PaymentId, payment_to_event: fn(&Payment) -> events::Event, 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 payment = payment_to_model(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; - }, - }; + if event_sender.send(event).is_err() { + debug!("No active subscribers for '{event_name}' event"); + } upsert_payment_details(event_node, Arc::clone(&paginated_store), &payment); } else { @@ -507,9 +483,9 @@ fn upsert_payment_details( match paginated_store.write( PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, - &payment.id, + &payment.id.to_lower_hex_string(), time, - &payment.encode_to_vec(), + &serde_json::to_vec(&payment).unwrap(), ) { Ok(_) => { if let Err(e) = event_node.event_handled() { diff --git a/ldk-server/src/openapi.rs b/ldk-server/src/openapi.rs new file mode 100644 index 00000000..006edf33 --- /dev/null +++ b/ldk-server/src/openapi.rs @@ -0,0 +1,580 @@ +// 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. + +#![allow(dead_code, unused_imports)] + +use ldk_server_json_models::api::*; +use ldk_server_json_models::error::{ErrorCode, ErrorResponse}; +use ldk_server_json_models::events::*; +use ldk_server_json_models::types::*; +use utoipa::openapi::security::{ApiKey, ApiKeyValue, SecurityScheme}; +use utoipa::{Modify, OpenApi}; + +#[derive(OpenApi)] +#[openapi( + info( + title = "LDK Server API", + version = "0.1.0", + description = "REST API for LDK Server, a Lightning Network node daemon built on LDK." + ), + paths( + get_node_info, + get_balances, + onchain_receive, + onchain_send, + bolt11_receive, + bolt11_receive_for_hash, + bolt11_claim_for_hash, + bolt11_fail_for_hash, + bolt11_receive_via_jit_channel, + bolt11_receive_variable_amount_via_jit_channel, + bolt11_send, + bolt12_receive, + bolt12_send, + spontaneous_send, + open_channel, + splice_in, + splice_out, + close_channel, + force_close_channel, + list_channels, + update_channel_config, + get_payment_details, + list_payments, + list_forwarded_payments, + list_peers, + connect_peer, + disconnect_peer, + sign_message, + verify_signature, + export_pathfinding_scores, + unified_send, + graph_list_channels, + graph_get_channel, + graph_list_nodes, + graph_get_node, + subscribe, + ), + components(schemas( + // API request/response types + GetNodeInfoRequest, GetNodeInfoResponse, + GetBalancesRequest, GetBalancesResponse, + OnchainReceiveRequest, OnchainReceiveResponse, + OnchainSendRequest, OnchainSendResponse, + Bolt11ReceiveRequest, Bolt11ReceiveResponse, + Bolt11ReceiveForHashRequest, Bolt11ReceiveForHashResponse, + Bolt11ClaimForHashRequest, Bolt11ClaimForHashResponse, + Bolt11FailForHashRequest, Bolt11FailForHashResponse, + Bolt11ReceiveViaJitChannelRequest, Bolt11ReceiveViaJitChannelResponse, + Bolt11ReceiveVariableAmountViaJitChannelRequest, Bolt11ReceiveVariableAmountViaJitChannelResponse, + Bolt11SendRequest, Bolt11SendResponse, + Bolt12ReceiveRequest, Bolt12ReceiveResponse, + Bolt12SendRequest, Bolt12SendResponse, + SpontaneousSendRequest, SpontaneousSendResponse, + OpenChannelRequest, OpenChannelResponse, + SpliceInRequest, SpliceInResponse, + SpliceOutRequest, SpliceOutResponse, + CloseChannelRequest, CloseChannelResponse, + ForceCloseChannelRequest, ForceCloseChannelResponse, + ListChannelsRequest, ListChannelsResponse, + UpdateChannelConfigRequest, UpdateChannelConfigResponse, + GetPaymentDetailsRequest, GetPaymentDetailsResponse, + ListPaymentsRequest, ListPaymentsResponse, + ListForwardedPaymentsRequest, ListForwardedPaymentsResponse, + ListPeersRequest, ListPeersResponse, + ConnectPeerRequest, ConnectPeerResponse, + DisconnectPeerRequest, DisconnectPeerResponse, + SignMessageRequest, SignMessageResponse, + VerifySignatureRequest, VerifySignatureResponse, + ExportPathfindingScoresRequest, ExportPathfindingScoresResponse, + UnifiedSendRequest, UnifiedSendResponse, UnifiedSendPaymentResult, + GraphListChannelsRequest, GraphListChannelsResponse, + GraphGetChannelRequest, GraphGetChannelResponse, + GraphListNodesRequest, GraphListNodesResponse, + GraphGetNodeRequest, GraphGetNodeResponse, + // Domain types + Payment, PaymentKind, PaymentDirection, PaymentStatus, + Onchain, ConfirmationStatus, Confirmed, Unconfirmed, + Bolt11, Bolt11Jit, Bolt12Offer, Bolt12Refund, Spontaneous, + LspFeeLimits, ForwardedPayment, + Channel, ChannelConfig, MaxDustHtlcExposure, OutPoint, BestBlock, + LightningBalance, ClaimableOnChannelClose, ClaimableAwaitingConfirmations, + ContentiousClaimable, MaybeTimeoutClaimableHtlc, MaybePreimageClaimableHtlc, + CounterpartyRevokedOutputClaimable, + PendingSweepBalance, PendingBroadcast, BroadcastAwaitingConfirmation, + AwaitingThresholdConfirmations, + PageToken, Bolt11InvoiceDescription, RouteParametersConfig, BalanceSource, + GraphRoutingFees, GraphChannelUpdate, GraphChannel, + GraphNodeAnnouncement, GraphNode, Peer, + // Event types + Event, PaymentReceived, PaymentSuccessful, PaymentFailed, + PaymentClaimable, PaymentForwarded, + // Error types + ErrorResponse, ErrorCode, + )), + modifiers(&HmacSecurityAddon), + tags( + (name = "Node", description = "Node information and balances"), + (name = "Onchain", description = "On-chain wallet operations"), + (name = "Bolt11", description = "BOLT11 Lightning invoice operations"), + (name = "Bolt12", description = "BOLT12 Lightning offer operations"), + (name = "Channels", description = "Channel management"), + (name = "Payments", description = "Payment queries"), + (name = "Peers", description = "Peer management"), + (name = "Send", description = "Sending payments"), + (name = "Graph", description = "Network graph queries"), + (name = "Crypto", description = "Message signing and verification"), + (name = "Events", description = "Server-Sent Events for payment notifications"), + ) +)] +pub(crate) struct ApiDoc; + +struct HmacSecurityAddon; + +impl Modify for HmacSecurityAddon { + fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) { + if let Some(components) = openapi.components.as_mut() { + components.add_security_scheme( + "hmac_auth", + SecurityScheme::ApiKey(ApiKey::Header(ApiKeyValue::new("X-Auth"))), + ); + } + } +} + +#[utoipa::path( + post, path = "/GetNodeInfo", + request_body = GetNodeInfoRequest, + responses( + (status = 200, body = GetNodeInfoResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Node" +)] +fn get_node_info() {} + +#[utoipa::path( + post, path = "/GetBalances", + request_body = GetBalancesRequest, + responses( + (status = 200, body = GetBalancesResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Node" +)] +fn get_balances() {} + +#[utoipa::path( + post, path = "/OnchainReceive", + request_body = OnchainReceiveRequest, + responses( + (status = 200, body = OnchainReceiveResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Onchain" +)] +fn onchain_receive() {} + +#[utoipa::path( + post, path = "/OnchainSend", + request_body = OnchainSendRequest, + responses( + (status = 200, body = OnchainSendResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Onchain" +)] +fn onchain_send() {} + +#[utoipa::path( + post, path = "/Bolt11Receive", + request_body = Bolt11ReceiveRequest, + responses( + (status = 200, body = Bolt11ReceiveResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Bolt11" +)] +fn bolt11_receive() {} + +#[utoipa::path( + post, path = "/Bolt11ReceiveForHash", + request_body = Bolt11ReceiveForHashRequest, + responses( + (status = 200, body = Bolt11ReceiveForHashResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Bolt11" +)] +fn bolt11_receive_for_hash() {} + +#[utoipa::path( + post, path = "/Bolt11ClaimForHash", + request_body = Bolt11ClaimForHashRequest, + responses( + (status = 200, body = Bolt11ClaimForHashResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Bolt11" +)] +fn bolt11_claim_for_hash() {} + +#[utoipa::path( + post, path = "/Bolt11FailForHash", + request_body = Bolt11FailForHashRequest, + responses( + (status = 200, body = Bolt11FailForHashResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Bolt11" +)] +fn bolt11_fail_for_hash() {} + +#[utoipa::path( + post, path = "/Bolt11ReceiveViaJitChannel", + request_body = Bolt11ReceiveViaJitChannelRequest, + responses( + (status = 200, body = Bolt11ReceiveViaJitChannelResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Bolt11" +)] +fn bolt11_receive_via_jit_channel() {} + +#[utoipa::path( + post, path = "/Bolt11ReceiveVariableAmountViaJitChannel", + request_body = Bolt11ReceiveVariableAmountViaJitChannelRequest, + responses( + (status = 200, body = Bolt11ReceiveVariableAmountViaJitChannelResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Bolt11" +)] +fn bolt11_receive_variable_amount_via_jit_channel() {} + +#[utoipa::path( + post, path = "/Bolt11Send", + request_body = Bolt11SendRequest, + responses( + (status = 200, body = Bolt11SendResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Bolt11" +)] +fn bolt11_send() {} + +#[utoipa::path( + post, path = "/Bolt12Receive", + request_body = Bolt12ReceiveRequest, + responses( + (status = 200, body = Bolt12ReceiveResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Bolt12" +)] +fn bolt12_receive() {} + +#[utoipa::path( + post, path = "/Bolt12Send", + request_body = Bolt12SendRequest, + responses( + (status = 200, body = Bolt12SendResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Bolt12" +)] +fn bolt12_send() {} + +#[utoipa::path( + post, path = "/SpontaneousSend", + request_body = SpontaneousSendRequest, + responses( + (status = 200, body = SpontaneousSendResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Send" +)] +fn spontaneous_send() {} + +#[utoipa::path( + post, path = "/OpenChannel", + request_body = OpenChannelRequest, + responses( + (status = 200, body = OpenChannelResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Channels" +)] +fn open_channel() {} + +#[utoipa::path( + post, path = "/SpliceIn", + request_body = SpliceInRequest, + responses( + (status = 200, body = SpliceInResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Channels" +)] +fn splice_in() {} + +#[utoipa::path( + post, path = "/SpliceOut", + request_body = SpliceOutRequest, + responses( + (status = 200, body = SpliceOutResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Channels" +)] +fn splice_out() {} + +#[utoipa::path( + post, path = "/CloseChannel", + request_body = CloseChannelRequest, + responses( + (status = 200, body = CloseChannelResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Channels" +)] +fn close_channel() {} + +#[utoipa::path( + post, path = "/ForceCloseChannel", + request_body = ForceCloseChannelRequest, + responses( + (status = 200, body = ForceCloseChannelResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Channels" +)] +fn force_close_channel() {} + +#[utoipa::path( + post, path = "/ListChannels", + request_body = ListChannelsRequest, + responses( + (status = 200, body = ListChannelsResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Channels" +)] +fn list_channels() {} + +#[utoipa::path( + post, path = "/UpdateChannelConfig", + request_body = UpdateChannelConfigRequest, + responses( + (status = 200, body = UpdateChannelConfigResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Channels" +)] +fn update_channel_config() {} + +#[utoipa::path( + post, path = "/GetPaymentDetails", + request_body = GetPaymentDetailsRequest, + responses( + (status = 200, body = GetPaymentDetailsResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Payments" +)] +fn get_payment_details() {} + +#[utoipa::path( + post, path = "/ListPayments", + request_body = ListPaymentsRequest, + responses( + (status = 200, body = ListPaymentsResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Payments" +)] +fn list_payments() {} + +#[utoipa::path( + post, path = "/ListForwardedPayments", + request_body = ListForwardedPaymentsRequest, + responses( + (status = 200, body = ListForwardedPaymentsResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Payments" +)] +fn list_forwarded_payments() {} + +#[utoipa::path( + post, path = "/ListPeers", + request_body = ListPeersRequest, + responses( + (status = 200, body = ListPeersResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Peers" +)] +fn list_peers() {} + +#[utoipa::path( + post, path = "/ConnectPeer", + request_body = ConnectPeerRequest, + responses( + (status = 200, body = ConnectPeerResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Peers" +)] +fn connect_peer() {} + +#[utoipa::path( + post, path = "/DisconnectPeer", + request_body = DisconnectPeerRequest, + responses( + (status = 200, body = DisconnectPeerResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Peers" +)] +fn disconnect_peer() {} + +#[utoipa::path( + post, path = "/SignMessage", + request_body = SignMessageRequest, + responses( + (status = 200, body = SignMessageResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Crypto" +)] +fn sign_message() {} + +#[utoipa::path( + post, path = "/VerifySignature", + request_body = VerifySignatureRequest, + responses( + (status = 200, body = VerifySignatureResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Crypto" +)] +fn verify_signature() {} + +#[utoipa::path( + post, path = "/ExportPathfindingScores", + request_body = ExportPathfindingScoresRequest, + responses( + (status = 200, body = ExportPathfindingScoresResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Node" +)] +fn export_pathfinding_scores() {} + +#[utoipa::path( + post, path = "/UnifiedSend", + request_body = UnifiedSendRequest, + responses( + (status = 200, body = UnifiedSendResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Send" +)] +fn unified_send() {} + +#[utoipa::path( + post, path = "/GraphListChannels", + request_body = GraphListChannelsRequest, + responses( + (status = 200, body = GraphListChannelsResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Graph" +)] +fn graph_list_channels() {} + +#[utoipa::path( + post, path = "/GraphGetChannel", + request_body = GraphGetChannelRequest, + responses( + (status = 200, body = GraphGetChannelResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Graph" +)] +fn graph_get_channel() {} + +#[utoipa::path( + post, path = "/GraphListNodes", + request_body = GraphListNodesRequest, + responses( + (status = 200, body = GraphListNodesResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Graph" +)] +fn graph_list_nodes() {} + +#[utoipa::path( + post, path = "/GraphGetNode", + request_body = GraphGetNodeRequest, + responses( + (status = 200, body = GraphGetNodeResponse), + (status = 400, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Graph" +)] +fn graph_get_node() {} + +#[utoipa::path( + post, path = "/Subscribe", + responses( + (status = 200, content_type = "text/event-stream", description = "Server-Sent Events stream of payment lifecycle events"), + (status = 401, body = ErrorResponse), + ), + security(("hmac_auth" = [])), + tag = "Events" +)] +fn subscribe() {} diff --git a/ldk-server/src/service.rs b/ldk-server/src/service.rs index 05004ae6..641fb927 100644 --- a/ldk-server/src/service.rs +++ b/ldk-server/src/service.rs @@ -18,7 +18,7 @@ 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::{ +use ldk_server_json_models::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, @@ -27,10 +27,13 @@ use ldk_server_protos::endpoints::{ 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, + SPLICE_OUT_PATH, SPONTANEOUS_SEND_PATH, SUBSCRIBE_PATH, UNIFIED_SEND_PATH, + UPDATE_CHANNEL_CONFIG_PATH, VERIFY_SIGNATURE_PATH, }; -use prost::Message; +use ldk_server_json_models::events::Event; +use serde::de::DeserializeOwned; +use serde::Serialize; +use tokio::sync::broadcast; 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; @@ -69,25 +72,28 @@ 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::events::sse::SseBody; use crate::io::persist::paginated_kv_store::PaginatedKVStore; -use crate::util::proto_adapter::to_error_response; +use crate::util::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 { +pub(crate) struct NodeService { node: Arc, paginated_kv_store: Arc, api_key: String, + event_sender: broadcast::Sender, } impl NodeService { pub(crate) fn new( node: Arc, paginated_kv_store: Arc, api_key: String, + event_sender: broadcast::Sender, ) -> Self { - Self { node, paginated_kv_store, api_key } + Self { node, paginated_kv_store, api_key, event_sender } } } @@ -165,24 +171,51 @@ pub(crate) struct Context { pub(crate) paginated_kv_store: Arc, } +type BoxBody = http_body_util::combinators::BoxBody; +type ServiceResponse = Response; + impl Service> for NodeService { - type Response = Response>; + type Response = ServiceResponse; type Error = hyper::Error; type Future = Pin> + Send>>; fn call(&self, req: Request) -> Self::Future { + // Handle CORS preflight + if req.method() == hyper::Method::OPTIONS { + return Box::pin(async { + Ok(with_cors_headers( + Response::builder().status(StatusCode::NO_CONTENT).body(empty_body()).unwrap(), + )) + }); + } + + let inner = self.call_inner(req); + Box::pin(async move { inner.await.map(with_cors_headers) }) + } +} + +impl NodeService { + fn call_inner( + &self, req: Request, + ) -> Pin> + Send>> { + if req.uri().path() == "/openapi.json" { + return Box::pin(async { + static OPENAPI_JSON: std::sync::LazyLock = std::sync::LazyLock::new(|| { + use utoipa::OpenApi; + crate::openapi::ApiDoc::openapi().to_json().unwrap() + }); + Ok(Response::builder() + .header("Content-Type", "application/json") + .body(Full::new(Bytes::from(OPENAPI_JSON.as_str())).boxed()) + .unwrap()) + }); + } + // 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()) - }); + return Box::pin(async move { Ok(error_to_response(e)) }); }, }; @@ -191,6 +224,7 @@ impl Service> for NodeService { paginated_kv_store: Arc::clone(&self.paginated_kv_store), }; let api_key = self.api_key.clone(); + let event_sender = self.event_sender.clone(); // Exclude '/' from path pattern matching. match &req.uri().path()[1..] { @@ -427,13 +461,25 @@ impl Service> for NodeService { api_key, handle_graph_get_node_request, )), + SUBSCRIBE_PATH => Box::pin(async move { + if let Err(e) = + validate_hmac_auth(auth_params.timestamp, &auth_params.hmac_hex, &[], &api_key) + { + return Ok(error_to_response(e)); + } + let sse_body = SseBody::new(event_sender.subscribe()); + Ok(Response::builder() + .header("Content-Type", "text/event-stream") + .header("Cache-Control", "no-cache") + .body(sse_body.boxed()) + .unwrap()) + }), 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. + .body(Full::new(Bytes::from(error)).boxed()) .unwrap()) }) }, @@ -441,66 +487,63 @@ impl Service> for NodeService { } } +fn error_to_response(e: LdkServerError) -> ServiceResponse { + let (error_response, status_code) = to_error_response(e); + Response::builder() + .status(status_code) + .header("Content-Type", "application/json") + .body(Full::new(Bytes::from(serde_json::to_vec(&error_response).unwrap())).boxed()) + .unwrap() +} + +fn empty_body() -> BoxBody { + Full::new(Bytes::new()).boxed() +} + +fn with_cors_headers(mut response: ServiceResponse) -> ServiceResponse { + let headers = response.headers_mut(); + headers.insert("Access-Control-Allow-Origin", "*".parse().unwrap()); + headers.insert("Access-Control-Allow-Methods", "GET, POST, OPTIONS".parse().unwrap()); + headers.insert("Access-Control-Allow-Headers", "Content-Type, X-Auth".parse().unwrap()); + response +} + async fn handle_request< - T: Message + Default, - R: Message, + T: DeserializeOwned, + R: Serialize, 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 +) -> Result { 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( + return Ok(error_to_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()); + return Ok(error_to_response(e)); } - match T::decode(bytes) { + let decode_bytes = if bytes.is_empty() { &b"{}"[..] } else { &bytes[..] }; + match serde_json::from_slice::(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. + .header("Content-Type", "application/json") + .body(Full::new(Bytes::from(serde_json::to_vec(&response).unwrap())).boxed()) .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(e) => Ok(error_to_response(e)), }, 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()) + Ok(error_to_response(LdkServerError::new(InvalidRequestError, "Malformed request."))) }, } } diff --git a/ldk-server/src/util/proto_adapter.rs b/ldk-server/src/util/adapter.rs similarity index 50% rename from ldk-server/src/util/proto_adapter.rs rename to ldk-server/src/util/adapter.rs index 77441dfd..e10d5c75 100644 --- a/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/src/util/adapter.rs @@ -7,10 +7,10 @@ // You may not use this file except in accordance with one or both of these // licenses. -use bytes::Bytes; use hex::prelude::*; use hyper::StatusCode; use ldk_node::bitcoin::hashes::sha256; +use ldk_node::bitcoin::hashes::Hash as _; use ldk_node::bitcoin::secp256k1::PublicKey; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; use ldk_node::lightning::chain::channelmonitor::BalanceSource; @@ -23,20 +23,9 @@ 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, - CounterpartyRevokedOutputClaimable, MaybePreimageClaimableHtlc, MaybeTimeoutClaimableHtlc, -}; -use ldk_server_protos::types::payment_kind::Kind::{ - Bolt11, Bolt11Jit, Bolt12Offer, Bolt12Refund, Onchain, Spontaneous, -}; -use ldk_server_protos::types::pending_sweep_balance::BalanceType::{ - AwaitingThresholdConfirmations, BroadcastAwaitingConfirmation, PendingBroadcast, -}; -use ldk_server_protos::types::{ - bolt11_invoice_description, Channel, ForwardedPayment, LspFeeLimits, OutPoint, Payment, Peer, +use ldk_server_json_models::error::{ErrorCode, ErrorResponse}; +use ldk_server_json_models::types::{ + Channel, ForwardedPayment, LspFeeLimits, OutPoint, Payment, Peer, }; use crate::api::error::LdkServerError; @@ -44,22 +33,22 @@ use crate::api::error::LdkServerErrorCode::{ AuthError, InternalServerError, InvalidRequestError, LightningError, }; -pub(crate) fn peer_to_proto(peer: PeerDetails) -> Peer { +pub(crate) fn peer_to_model(peer: PeerDetails) -> Peer { Peer { - node_id: peer.node_id.to_string(), + node_id: peer.node_id.serialize(), address: peer.address.to_string(), is_persisted: peer.is_persisted, is_connected: peer.is_connected, } } -pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { +pub(crate) fn channel_to_model(channel: ChannelDetails) -> Channel { Channel { - channel_id: channel.channel_id.0.to_lower_hex_string(), - counterparty_node_id: channel.counterparty_node_id.to_string(), + channel_id: channel.channel_id.0, + counterparty_node_id: channel.counterparty_node_id.serialize(), funding_txo: channel .funding_txo - .map(|o| OutPoint { txid: o.txid.to_string(), vout: o.vout }), + .map(|o| OutPoint { txid: o.txid.to_byte_array(), vout: o.vout }), user_channel_id: channel.user_channel_id.0.to_string(), unspendable_punishment_reserve: channel.unspendable_punishment_reserve, channel_value_sats: channel.channel_value_sats, @@ -72,7 +61,7 @@ pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { is_channel_ready: channel.is_channel_ready, is_usable: channel.is_usable, is_announced: channel.is_announced, - channel_config: Some(channel_config_to_proto(channel.config)), + channel_config: Some(channel_config_to_model(channel.config)), next_outbound_htlc_limit_msat: channel.next_outbound_htlc_limit_msat, next_outbound_htlc_minimum_msat: channel.next_outbound_htlc_minimum_msat, force_close_spend_delay: channel.force_close_spend_delay.map(|x| x as u32), @@ -90,10 +79,10 @@ pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { } } -pub(crate) fn channel_config_to_proto( +pub(crate) fn channel_config_to_model( channel_config: ChannelConfig, -) -> ldk_server_protos::types::ChannelConfig { - ldk_server_protos::types::ChannelConfig { +) -> ldk_server_json_models::types::ChannelConfig { + ldk_server_json_models::types::ChannelConfig { forwarding_fee_proportional_millionths: Some( channel_config.forwarding_fee_proportional_millionths, ), @@ -105,20 +94,16 @@ pub(crate) fn channel_config_to_proto( accept_underpaying_htlcs: Some(channel_config.accept_underpaying_htlcs), max_dust_htlc_exposure: match channel_config.max_dust_htlc_exposure { MaxDustHTLCExposure::FixedLimit { limit_msat } => { - Some(ldk_server_protos::types::channel_config::MaxDustHtlcExposure::FixedLimitMsat( - limit_msat, - )) + Some(ldk_server_json_models::types::MaxDustHtlcExposure::FixedLimitMsat(limit_msat)) }, MaxDustHTLCExposure::FeeRateMultiplier { multiplier } => Some( - ldk_server_protos::types::channel_config::MaxDustHtlcExposure::FeeRateMultiplier( - multiplier, - ), + ldk_server_json_models::types::MaxDustHtlcExposure::FeeRateMultiplier(multiplier), ), }, } } -pub(crate) fn payment_to_proto(payment: PaymentDetails) -> Payment { +pub(crate) fn payment_to_model(payment: PaymentDetails) -> Payment { let PaymentDetails { id, kind, @@ -130,41 +115,43 @@ pub(crate) fn payment_to_proto(payment: PaymentDetails) -> Payment { } = payment; Payment { - id: id.to_string(), - kind: Some(payment_kind_to_proto(kind)), + id: id.0, + kind: payment_kind_to_model(kind), amount_msat, fee_paid_msat, direction: match direction { - PaymentDirection::Inbound => ldk_server_protos::types::PaymentDirection::Inbound.into(), - PaymentDirection::Outbound => { - ldk_server_protos::types::PaymentDirection::Outbound.into() - }, + PaymentDirection::Inbound => ldk_server_json_models::types::PaymentDirection::Inbound, + PaymentDirection::Outbound => ldk_server_json_models::types::PaymentDirection::Outbound, }, status: match status { - PaymentStatus::Pending => ldk_server_protos::types::PaymentStatus::Pending.into(), - PaymentStatus::Succeeded => ldk_server_protos::types::PaymentStatus::Succeeded.into(), - PaymentStatus::Failed => ldk_server_protos::types::PaymentStatus::Failed.into(), + PaymentStatus::Pending => ldk_server_json_models::types::PaymentStatus::Pending, + PaymentStatus::Succeeded => ldk_server_json_models::types::PaymentStatus::Succeeded, + PaymentStatus::Failed => ldk_server_json_models::types::PaymentStatus::Failed, }, latest_update_timestamp, } } -pub(crate) fn payment_kind_to_proto( +pub(crate) fn payment_kind_to_model( payment_kind: PaymentKind, -) -> ldk_server_protos::types::PaymentKind { +) -> ldk_server_json_models::types::PaymentKind { match payment_kind { - PaymentKind::Onchain { txid, status } => ldk_server_protos::types::PaymentKind { - kind: Some(Onchain(ldk_server_protos::types::Onchain { - txid: txid.to_string(), - status: Some(confirmation_status_to_proto(status)), - })), + PaymentKind::Onchain { txid, status } => { + ldk_server_json_models::types::PaymentKind::Onchain( + ldk_server_json_models::types::Onchain { + txid: txid.to_byte_array(), + status: confirmation_status_to_model(status), + }, + ) }, - PaymentKind::Bolt11 { hash, preimage, secret } => ldk_server_protos::types::PaymentKind { - kind: Some(Bolt11(ldk_server_protos::types::Bolt11 { - hash: hash.to_string(), - preimage: preimage.map(|p| p.to_string()), - secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), - })), + PaymentKind::Bolt11 { hash, preimage, secret } => { + ldk_server_json_models::types::PaymentKind::Bolt11( + ldk_server_json_models::types::Bolt11 { + hash: hash.0, + preimage: preimage.map(|p| p.0), + secret: secret.map(|s| s.0), + }, + ) }, PaymentKind::Bolt11Jit { hash, @@ -172,73 +159,77 @@ pub(crate) fn payment_kind_to_proto( secret, lsp_fee_limits, counterparty_skimmed_fee_msat, - } => ldk_server_protos::types::PaymentKind { - kind: Some(Bolt11Jit(ldk_server_protos::types::Bolt11Jit { - hash: hash.to_string(), - preimage: preimage.map(|p| p.to_string()), - secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), + } => ldk_server_json_models::types::PaymentKind::Bolt11Jit( + ldk_server_json_models::types::Bolt11Jit { + hash: hash.0, + preimage: preimage.map(|p| p.0), + secret: secret.map(|s| s.0), lsp_fee_limits: Some(LspFeeLimits { max_total_opening_fee_msat: lsp_fee_limits.max_total_opening_fee_msat, max_proportional_opening_fee_ppm_msat: lsp_fee_limits .max_proportional_opening_fee_ppm_msat, }), counterparty_skimmed_fee_msat, - })), - }, + }, + ), PaymentKind::Bolt12Offer { hash, preimage, secret, offer_id, payer_note, quantity } => { - ldk_server_protos::types::PaymentKind { - kind: Some(Bolt12Offer(ldk_server_protos::types::Bolt12Offer { - hash: hash.map(|h| h.to_string()), - preimage: preimage.map(|p| p.to_string()), - secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), - offer_id: offer_id.0.to_lower_hex_string(), + ldk_server_json_models::types::PaymentKind::Bolt12Offer( + ldk_server_json_models::types::Bolt12Offer { + hash: hash.map(|h| h.0), + preimage: preimage.map(|p| p.0), + secret: secret.map(|s| s.0), + offer_id: offer_id.0, payer_note: payer_note.map(|s| s.to_string()), quantity, - })), - } + }, + ) }, PaymentKind::Bolt12Refund { hash, preimage, secret, payer_note, quantity } => { - ldk_server_protos::types::PaymentKind { - kind: Some(Bolt12Refund(ldk_server_protos::types::Bolt12Refund { - hash: hash.map(|h| h.to_string()), - preimage: preimage.map(|p| p.to_string()), - secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), + ldk_server_json_models::types::PaymentKind::Bolt12Refund( + ldk_server_json_models::types::Bolt12Refund { + hash: hash.map(|h| h.0), + preimage: preimage.map(|p| p.0), + secret: secret.map(|s| s.0), payer_note: payer_note.map(|s| s.to_string()), quantity, - })), - } + }, + ) }, - PaymentKind::Spontaneous { hash, preimage } => ldk_server_protos::types::PaymentKind { - kind: Some(Spontaneous(ldk_server_protos::types::Spontaneous { - hash: hash.to_string(), - preimage: preimage.map(|p| p.to_string()), - })), + PaymentKind::Spontaneous { hash, preimage } => { + ldk_server_json_models::types::PaymentKind::Spontaneous( + ldk_server_json_models::types::Spontaneous { + hash: hash.0, + preimage: preimage.map(|p| p.0), + }, + ) }, } } -pub(crate) fn confirmation_status_to_proto( +pub(crate) fn confirmation_status_to_model( confirmation_status: ConfirmationStatus, -) -> ldk_server_protos::types::ConfirmationStatus { +) -> ldk_server_json_models::types::ConfirmationStatus { match confirmation_status { ConfirmationStatus::Confirmed { block_hash, height, timestamp } => { - ldk_server_protos::types::ConfirmationStatus { - status: Some(Confirmed(ldk_server_protos::types::Confirmed { - block_hash: block_hash.to_string(), + ldk_server_json_models::types::ConfirmationStatus::Confirmed( + ldk_server_json_models::types::Confirmed { + block_hash: block_hash.to_byte_array(), height, timestamp, - })), - } + }, + ) }, - ConfirmationStatus::Unconfirmed => ldk_server_protos::types::ConfirmationStatus { - status: Some(Unconfirmed(ldk_server_protos::types::Unconfirmed {})), + ConfirmationStatus::Unconfirmed => { + ldk_server_json_models::types::ConfirmationStatus::Unconfirmed( + ldk_server_json_models::types::Unconfirmed {}, + ) }, } } -pub(crate) fn lightning_balance_to_proto( +pub(crate) fn lightning_balance_to_model( lightning_balance: LightningBalance, -) -> ldk_server_protos::types::LightningBalance { +) -> ldk_server_json_models::types::LightningBalance { match lightning_balance { LightningBalance::ClaimableOnChannelClose { channel_id, @@ -249,48 +240,44 @@ pub(crate) fn lightning_balance_to_proto( outbound_forwarded_htlc_rounded_msat, inbound_claiming_htlc_rounded_msat, inbound_htlc_rounded_msat, - } => ldk_server_protos::types::LightningBalance { - balance_type: Some(ClaimableOnChannelClose( - ldk_server_protos::types::ClaimableOnChannelClose { - channel_id: channel_id.0.to_lower_hex_string(), - counterparty_node_id: counterparty_node_id.to_string(), - amount_satoshis, - transaction_fee_satoshis, - outbound_payment_htlc_rounded_msat, - outbound_forwarded_htlc_rounded_msat, - inbound_claiming_htlc_rounded_msat, - inbound_htlc_rounded_msat, - }, - )), - }, + } => ldk_server_json_models::types::LightningBalance::ClaimableOnChannelClose( + ldk_server_json_models::types::ClaimableOnChannelClose { + channel_id: channel_id.0, + counterparty_node_id: counterparty_node_id.serialize(), + amount_satoshis, + transaction_fee_satoshis, + outbound_payment_htlc_rounded_msat, + outbound_forwarded_htlc_rounded_msat, + inbound_claiming_htlc_rounded_msat, + inbound_htlc_rounded_msat, + }, + ), LightningBalance::ClaimableAwaitingConfirmations { channel_id, counterparty_node_id, amount_satoshis, confirmation_height, source, - } => ldk_server_protos::types::LightningBalance { - balance_type: Some(ClaimableAwaitingConfirmations( - ldk_server_protos::types::ClaimableAwaitingConfirmations { - channel_id: channel_id.0.to_lower_hex_string(), - counterparty_node_id: counterparty_node_id.to_string(), - amount_satoshis, - confirmation_height, - source: match source { - BalanceSource::HolderForceClosed => { - ldk_server_protos::types::BalanceSource::HolderForceClosed.into() - }, - BalanceSource::CounterpartyForceClosed => { - ldk_server_protos::types::BalanceSource::CounterpartyForceClosed.into() - }, - BalanceSource::CoopClose => { - ldk_server_protos::types::BalanceSource::CoopClose.into() - }, - BalanceSource::Htlc => ldk_server_protos::types::BalanceSource::Htlc.into(), + } => ldk_server_json_models::types::LightningBalance::ClaimableAwaitingConfirmations( + ldk_server_json_models::types::ClaimableAwaitingConfirmations { + channel_id: channel_id.0, + counterparty_node_id: counterparty_node_id.serialize(), + amount_satoshis, + confirmation_height, + source: match source { + BalanceSource::HolderForceClosed => { + ldk_server_json_models::types::BalanceSource::HolderForceClosed + }, + BalanceSource::CounterpartyForceClosed => { + ldk_server_json_models::types::BalanceSource::CounterpartyForceClosed + }, + BalanceSource::CoopClose => { + ldk_server_json_models::types::BalanceSource::CoopClose }, + BalanceSource::Htlc => ldk_server_json_models::types::BalanceSource::Htlc, }, - )), - }, + }, + ), LightningBalance::ContentiousClaimable { channel_id, counterparty_node_id, @@ -298,18 +285,16 @@ pub(crate) fn lightning_balance_to_proto( timeout_height, payment_hash, payment_preimage, - } => ldk_server_protos::types::LightningBalance { - balance_type: Some(ContentiousClaimable( - ldk_server_protos::types::ContentiousClaimable { - channel_id: channel_id.0.to_lower_hex_string(), - counterparty_node_id: counterparty_node_id.to_string(), - amount_satoshis, - timeout_height, - payment_hash: payment_hash.to_string(), - payment_preimage: payment_preimage.to_string(), - }, - )), - }, + } => ldk_server_json_models::types::LightningBalance::ContentiousClaimable( + ldk_server_json_models::types::ContentiousClaimable { + channel_id: channel_id.0, + counterparty_node_id: counterparty_node_id.serialize(), + amount_satoshis, + timeout_height, + payment_hash: payment_hash.0, + payment_preimage: payment_preimage.0, + }, + ), LightningBalance::MaybeTimeoutClaimableHTLC { channel_id, counterparty_node_id, @@ -317,100 +302,90 @@ pub(crate) fn lightning_balance_to_proto( claimable_height, payment_hash, outbound_payment, - } => ldk_server_protos::types::LightningBalance { - balance_type: Some(MaybeTimeoutClaimableHtlc( - ldk_server_protos::types::MaybeTimeoutClaimableHtlc { - channel_id: channel_id.0.to_lower_hex_string(), - counterparty_node_id: counterparty_node_id.to_string(), - amount_satoshis, - claimable_height, - payment_hash: payment_hash.to_string(), - outbound_payment, - }, - )), - }, + } => ldk_server_json_models::types::LightningBalance::MaybeTimeoutClaimableHtlc( + ldk_server_json_models::types::MaybeTimeoutClaimableHtlc { + channel_id: channel_id.0, + counterparty_node_id: counterparty_node_id.serialize(), + amount_satoshis, + claimable_height, + payment_hash: payment_hash.0, + outbound_payment, + }, + ), LightningBalance::MaybePreimageClaimableHTLC { channel_id, counterparty_node_id, amount_satoshis, expiry_height, payment_hash, - } => ldk_server_protos::types::LightningBalance { - balance_type: Some(MaybePreimageClaimableHtlc( - ldk_server_protos::types::MaybePreimageClaimableHtlc { - channel_id: channel_id.0.to_lower_hex_string(), - counterparty_node_id: counterparty_node_id.to_string(), - amount_satoshis, - expiry_height, - payment_hash: payment_hash.to_string(), - }, - )), - }, + } => ldk_server_json_models::types::LightningBalance::MaybePreimageClaimableHtlc( + ldk_server_json_models::types::MaybePreimageClaimableHtlc { + channel_id: channel_id.0, + counterparty_node_id: counterparty_node_id.serialize(), + amount_satoshis, + expiry_height, + payment_hash: payment_hash.0, + }, + ), LightningBalance::CounterpartyRevokedOutputClaimable { channel_id, counterparty_node_id, amount_satoshis, - } => ldk_server_protos::types::LightningBalance { - balance_type: Some(CounterpartyRevokedOutputClaimable( - ldk_server_protos::types::CounterpartyRevokedOutputClaimable { - channel_id: channel_id.0.to_lower_hex_string(), - counterparty_node_id: counterparty_node_id.to_string(), - amount_satoshis, - }, - )), - }, + } => ldk_server_json_models::types::LightningBalance::CounterpartyRevokedOutputClaimable( + ldk_server_json_models::types::CounterpartyRevokedOutputClaimable { + channel_id: channel_id.0, + counterparty_node_id: counterparty_node_id.serialize(), + amount_satoshis, + }, + ), } } -pub(crate) fn pending_sweep_balance_to_proto( +pub(crate) fn pending_sweep_balance_to_model( pending_sweep_balance: PendingSweepBalance, -) -> ldk_server_protos::types::PendingSweepBalance { +) -> ldk_server_json_models::types::PendingSweepBalance { match pending_sweep_balance { PendingSweepBalance::PendingBroadcast { channel_id, amount_satoshis } => { - ldk_server_protos::types::PendingSweepBalance { - balance_type: Some(PendingBroadcast(ldk_server_protos::types::PendingBroadcast { - channel_id: channel_id.map(|c| c.0.to_lower_hex_string()), + ldk_server_json_models::types::PendingSweepBalance::PendingBroadcast( + ldk_server_json_models::types::PendingBroadcast { + channel_id: channel_id.map(|c| c.0), amount_satoshis, - })), - } + }, + ) }, PendingSweepBalance::BroadcastAwaitingConfirmation { channel_id, latest_broadcast_height, latest_spending_txid, amount_satoshis, - } => ldk_server_protos::types::PendingSweepBalance { - balance_type: Some(BroadcastAwaitingConfirmation( - ldk_server_protos::types::BroadcastAwaitingConfirmation { - channel_id: channel_id.map(|c| c.0.to_lower_hex_string()), - latest_broadcast_height, - latest_spending_txid: latest_spending_txid.to_string(), - amount_satoshis, - }, - )), - }, + } => ldk_server_json_models::types::PendingSweepBalance::BroadcastAwaitingConfirmation( + ldk_server_json_models::types::BroadcastAwaitingConfirmation { + channel_id: channel_id.map(|c| c.0), + latest_broadcast_height, + latest_spending_txid: latest_spending_txid.to_byte_array(), + amount_satoshis, + }, + ), PendingSweepBalance::AwaitingThresholdConfirmations { channel_id, latest_spending_txid, confirmation_hash, confirmation_height, amount_satoshis, - } => ldk_server_protos::types::PendingSweepBalance { - balance_type: Some(AwaitingThresholdConfirmations( - ldk_server_protos::types::AwaitingThresholdConfirmations { - channel_id: channel_id.map(|c| c.0.to_lower_hex_string()), - latest_spending_txid: latest_spending_txid.to_string(), - confirmation_hash: confirmation_hash.to_string(), - confirmation_height, - amount_satoshis, - }, - )), - }, + } => ldk_server_json_models::types::PendingSweepBalance::AwaitingThresholdConfirmations( + ldk_server_json_models::types::AwaitingThresholdConfirmations { + channel_id: channel_id.map(|c| c.0), + latest_spending_txid: latest_spending_txid.to_byte_array(), + confirmation_hash: confirmation_hash.to_byte_array(), + confirmation_height, + amount_satoshis, + }, + ), } } #[allow(clippy::too_many_arguments)] -pub(crate) fn forwarded_payment_to_proto( +pub(crate) fn forwarded_payment_to_model( prev_channel_id: ChannelId, next_channel_id: ChannelId, prev_user_channel_id: Option, next_user_channel_id: Option, prev_node_id: Option, next_node_id: Option, @@ -418,15 +393,15 @@ pub(crate) fn forwarded_payment_to_proto( outbound_amount_forwarded_msat: Option, ) -> ForwardedPayment { ForwardedPayment { - prev_channel_id: prev_channel_id.to_string(), - next_channel_id: next_channel_id.to_string(), + prev_channel_id: prev_channel_id.0, + next_channel_id: next_channel_id.0, prev_user_channel_id: prev_user_channel_id .expect("prev_user_channel_id expected for ldk-server >=0.1") .0 .to_string(), next_user_channel_id: next_user_channel_id.map(|u| u.0.to_string()), - prev_node_id: prev_node_id.expect("prev_node_id expected for ldk-server >=0.1").to_string(), - next_node_id: next_node_id.expect("next_node_id expected for ldk-node >=0.1").to_string(), + prev_node_id: prev_node_id.expect("prev_node_id expected for ldk-server >=0.1").serialize(), + next_node_id: next_node_id.expect("next_node_id expected for ldk-node >=0.1").serialize(), total_fee_earned_msat, skimmed_fee_msat, claim_from_onchain_tx, @@ -434,11 +409,11 @@ pub(crate) fn forwarded_payment_to_proto( } } -pub(crate) fn proto_to_bolt11_description( - description: Option, +pub(crate) fn bolt11_description_from_model( + description: Option, ) -> Result { - Ok(match description.and_then(|d| d.kind) { - Some(bolt11_invoice_description::Kind::Direct(s)) => { + Ok(match description { + Some(ldk_server_json_models::types::Bolt11InvoiceDescription::Direct(s)) => { Bolt11InvoiceDescription::Direct(Description::new(s).map_err(|e| { LdkServerError::new( InvalidRequestError, @@ -446,7 +421,7 @@ pub(crate) fn proto_to_bolt11_description( ) })?) }, - Some(bolt11_invoice_description::Kind::Hash(h)) => { + Some(ldk_server_json_models::types::Bolt11InvoiceDescription::Hash(h)) => { let hash_bytes = <[u8; 32]>::from_hex(&h).map_err(|_| { LdkServerError::new( InvalidRequestError, @@ -466,45 +441,45 @@ pub(crate) fn proto_to_bolt11_description( }) } -pub(crate) fn graph_routing_fees_to_proto( +pub(crate) fn graph_routing_fees_to_model( fees: RoutingFees, -) -> ldk_server_protos::types::GraphRoutingFees { - ldk_server_protos::types::GraphRoutingFees { +) -> ldk_server_json_models::types::GraphRoutingFees { + ldk_server_json_models::types::GraphRoutingFees { base_msat: fees.base_msat, proportional_millionths: fees.proportional_millionths, } } -pub(crate) fn graph_channel_update_to_proto( +pub(crate) fn graph_channel_update_to_model( update: ChannelUpdateInfo, -) -> ldk_server_protos::types::GraphChannelUpdate { - ldk_server_protos::types::GraphChannelUpdate { +) -> ldk_server_json_models::types::GraphChannelUpdate { + ldk_server_json_models::types::GraphChannelUpdate { last_update: update.last_update, enabled: update.enabled, cltv_expiry_delta: update.cltv_expiry_delta as u32, htlc_minimum_msat: update.htlc_minimum_msat, htlc_maximum_msat: update.htlc_maximum_msat, - fees: Some(graph_routing_fees_to_proto(update.fees)), + fees: graph_routing_fees_to_model(update.fees), } } -pub(crate) fn graph_channel_to_proto( +pub(crate) fn graph_channel_to_model( channel: ChannelInfo, -) -> ldk_server_protos::types::GraphChannel { - ldk_server_protos::types::GraphChannel { - node_one: channel.node_one.to_string(), - node_two: channel.node_two.to_string(), +) -> ldk_server_json_models::types::GraphChannel { + ldk_server_json_models::types::GraphChannel { + node_one: channel.node_one.as_slice().try_into().expect("NodeId should be 33 bytes"), + node_two: channel.node_two.as_slice().try_into().expect("NodeId should be 33 bytes"), capacity_sats: channel.capacity_sats, - one_to_two: channel.one_to_two.map(graph_channel_update_to_proto), - two_to_one: channel.two_to_one.map(graph_channel_update_to_proto), + one_to_two: channel.one_to_two.map(graph_channel_update_to_model), + two_to_one: channel.two_to_one.map(graph_channel_update_to_model), } } -pub(crate) fn graph_node_announcement_to_proto( +pub(crate) fn graph_node_announcement_to_model( announcement: NodeAnnouncementInfo, -) -> ldk_server_protos::types::GraphNodeAnnouncement { +) -> ldk_server_json_models::types::GraphNodeAnnouncement { let rgb = announcement.rgb(); - ldk_server_protos::types::GraphNodeAnnouncement { + ldk_server_json_models::types::GraphNodeAnnouncement { last_update: announcement.last_update(), alias: announcement.alias().to_string(), rgb: format!("{:02x}{:02x}{:02x}", rgb[0], rgb[1], rgb[2]), @@ -512,10 +487,10 @@ pub(crate) fn graph_node_announcement_to_proto( } } -pub(crate) fn graph_node_to_proto(node: NodeInfo) -> ldk_server_protos::types::GraphNode { - ldk_server_protos::types::GraphNode { +pub(crate) fn graph_node_to_model(node: NodeInfo) -> ldk_server_json_models::types::GraphNode { + ldk_server_json_models::types::GraphNode { channels: node.channels, - announcement_info: node.announcement_info.map(graph_node_announcement_to_proto), + announcement_info: node.announcement_info.map(graph_node_announcement_to_model), } } @@ -525,7 +500,7 @@ pub(crate) fn to_error_response(ldk_error: LdkServerError) -> (ErrorResponse, St AuthError => ErrorCode::AuthError, LightningError => ErrorCode::LightningError, InternalServerError => ErrorCode::InternalServerError, - } as i32; + }; let status = match ldk_error.error_code { InvalidRequestError => StatusCode::BAD_REQUEST, diff --git a/ldk-server/src/util/config.rs b/ldk-server/src/util/config.rs index c950987c..18aa841c 100644 --- a/ldk-server/src/util/config.rs +++ b/ldk-server/src/util/config.rs @@ -48,10 +48,6 @@ pub struct Config { 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, @@ -97,8 +93,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, @@ -146,11 +140,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); } @@ -313,30 +302,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() @@ -372,8 +337,6 @@ impl ConfigBuilder { 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, @@ -391,7 +354,6 @@ pub struct TomlConfig { bitcoind: Option, electrum: Option, esplora: Option, - rabbitmq: Option, liquidity: Option, log: Option, tls: Option, @@ -441,12 +403,6 @@ struct LogConfig { file: Option, } -#[derive(Deserialize, Serialize)] -struct RabbitmqConfig { - connection_string: String, - exchange_name: String, -} - #[derive(Deserialize, Serialize)] struct TomlTlsConfig { cert_path: Option, @@ -711,9 +667,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" @@ -786,13 +739,6 @@ 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()]), @@ -812,8 +758,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", @@ -847,8 +791,6 @@ mod tests { 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()); @@ -882,9 +824,7 @@ 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" @@ -939,9 +879,7 @@ 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" @@ -1003,9 +941,7 @@ 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" @@ -1048,9 +984,7 @@ mod tests { 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 @@ -1098,14 +1032,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")); @@ -1123,7 +1049,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(); @@ -1154,8 +1079,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, @@ -1170,15 +1093,12 @@ mod tests { 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 +1129,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(); @@ -1248,8 +1161,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", @@ -1282,24 +1193,12 @@ mod tests { 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() { diff --git a/ldk-server/src/util/mod.rs b/ldk-server/src/util/mod.rs index 5d74de43..52162b0a 100644 --- a/ldk-server/src/util/mod.rs +++ b/ldk-server/src/util/mod.rs @@ -7,8 +7,8 @@ // You may not use this file except in accordance with one or both of these // licenses. +pub(crate) mod adapter; pub(crate) mod config; pub(crate) mod logger; -pub(crate) mod proto_adapter; pub(crate) mod systemd; pub(crate) mod tls;