From 82b277ecb9fd3c0d959b7c7e1579b5cab19100e0 Mon Sep 17 00:00:00 2001 From: anon Date: Wed, 25 Feb 2026 00:16:01 +0100 Subject: [PATCH] Add DisconnectPeer API endpoint --- ldk-server-cli/src/main.rs | 24 ++++++++++++++++------- ldk-server-client/src/client.rs | 28 ++++++++++++++++++--------- ldk-server-protos/src/api.rs | 18 +++++++++++++++++ ldk-server-protos/src/endpoints.rs | 1 + ldk-server-protos/src/proto/api.proto | 11 +++++++++++ ldk-server/src/api/disconnect_peer.rs | 27 ++++++++++++++++++++++++++ ldk-server/src/api/mod.rs | 1 + ldk-server/src/service.rs | 6 +++++- 8 files changed, 99 insertions(+), 17 deletions(-) create mode 100644 ldk-server/src/api/disconnect_peer.rs diff --git a/ldk-server-cli/src/main.rs b/ldk-server-cli/src/main.rs index 8da497af..48d24ef4 100644 --- a/ldk-server-cli/src/main.rs +++ b/ldk-server-cli/src/main.rs @@ -24,13 +24,13 @@ use ldk_server_client::ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse, Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, CloseChannelRequest, CloseChannelResponse, ConnectPeerRequest, ConnectPeerResponse, - ExportPathfindingScoresRequest, ForceCloseChannelRequest, ForceCloseChannelResponse, - GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse, - GetPaymentDetailsRequest, GetPaymentDetailsResponse, ListChannelsRequest, ListChannelsResponse, - ListForwardedPaymentsRequest, ListPaymentsRequest, OnchainReceiveRequest, - OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, - OpenChannelResponse, SignMessageRequest, SignMessageResponse, SpliceInRequest, - SpliceInResponse, SpliceOutRequest, SpliceOutResponse, SpontaneousSendRequest, + DisconnectPeerRequest, DisconnectPeerResponse, ExportPathfindingScoresRequest, + ForceCloseChannelRequest, ForceCloseChannelResponse, GetBalancesRequest, GetBalancesResponse, + GetNodeInfoRequest, GetNodeInfoResponse, GetPaymentDetailsRequest, GetPaymentDetailsResponse, + ListChannelsRequest, ListChannelsResponse, ListForwardedPaymentsRequest, ListPaymentsRequest, + OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, + OpenChannelRequest, OpenChannelResponse, SignMessageRequest, SignMessageResponse, + SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse, SpontaneousSendRequest, SpontaneousSendResponse, UpdateChannelConfigRequest, UpdateChannelConfigResponse, VerifySignatureRequest, VerifySignatureResponse, }; @@ -373,6 +373,11 @@ enum Commands { )] persist: bool, }, + #[command(about = "Disconnect from a peer and remove it from the peer store")] + DisconnectPeer { + #[arg(help = "The hex-encoded public key of the node to disconnect from")] + node_pubkey: String, + }, #[command(about = "Sign a message with the node's secret key")] SignMessage { #[arg(help = "The message to sign")] @@ -769,6 +774,11 @@ async fn main() { client.connect_peer(ConnectPeerRequest { node_pubkey, address, persist }).await, ); }, + Commands::DisconnectPeer { node_pubkey } => { + handle_response_result::<_, DisconnectPeerResponse>( + client.disconnect_peer(DisconnectPeerRequest { node_pubkey }).await, + ); + }, Commands::SignMessage { message } => { handle_response_result::<_, SignMessageResponse>( client diff --git a/ldk-server-client/src/client.rs b/ldk-server-client/src/client.rs index a4d19206..f810467e 100644 --- a/ldk-server-client/src/client.rs +++ b/ldk-server-client/src/client.rs @@ -15,19 +15,20 @@ use ldk_server_protos::api::{ Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse, Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse, CloseChannelRequest, CloseChannelResponse, ConnectPeerRequest, ConnectPeerResponse, - ExportPathfindingScoresRequest, ExportPathfindingScoresResponse, ForceCloseChannelRequest, - ForceCloseChannelResponse, GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, - GetNodeInfoResponse, GetPaymentDetailsRequest, GetPaymentDetailsResponse, ListChannelsRequest, - ListChannelsResponse, ListForwardedPaymentsRequest, ListForwardedPaymentsResponse, - ListPaymentsRequest, ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse, - OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, OpenChannelResponse, - SignMessageRequest, SignMessageResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest, - SpliceOutResponse, SpontaneousSendRequest, SpontaneousSendResponse, UpdateChannelConfigRequest, + DisconnectPeerRequest, DisconnectPeerResponse, ExportPathfindingScoresRequest, + ExportPathfindingScoresResponse, ForceCloseChannelRequest, ForceCloseChannelResponse, + GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse, + GetPaymentDetailsRequest, GetPaymentDetailsResponse, ListChannelsRequest, ListChannelsResponse, + ListForwardedPaymentsRequest, ListForwardedPaymentsResponse, ListPaymentsRequest, + ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, + OnchainSendResponse, OpenChannelRequest, OpenChannelResponse, SignMessageRequest, + SignMessageResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse, + SpontaneousSendRequest, SpontaneousSendResponse, UpdateChannelConfigRequest, UpdateChannelConfigResponse, VerifySignatureRequest, VerifySignatureResponse, }; use ldk_server_protos::endpoints::{ BOLT11_RECEIVE_PATH, BOLT11_SEND_PATH, BOLT12_RECEIVE_PATH, BOLT12_SEND_PATH, - CLOSE_CHANNEL_PATH, CONNECT_PEER_PATH, EXPORT_PATHFINDING_SCORES_PATH, + CLOSE_CHANNEL_PATH, CONNECT_PEER_PATH, DISCONNECT_PEER_PATH, EXPORT_PATHFINDING_SCORES_PATH, FORCE_CLOSE_CHANNEL_PATH, GET_BALANCES_PATH, GET_NODE_INFO_PATH, GET_PAYMENT_DETAILS_PATH, LIST_CHANNELS_PATH, LIST_FORWARDED_PAYMENTS_PATH, LIST_PAYMENTS_PATH, ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SIGN_MESSAGE_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH, @@ -264,6 +265,15 @@ impl LdkServerClient { self.post_request(&request, &url).await } + /// Disconnect from a peer and remove it from the peer store. + /// For API contract/usage, refer to docs for [`DisconnectPeerRequest`] and [`DisconnectPeerResponse`]. + pub async fn disconnect_peer( + &self, request: DisconnectPeerRequest, + ) -> Result { + let url = format!("https://{}/{DISCONNECT_PEER_PATH}", self.base_url); + self.post_request(&request, &url).await + } + /// Send a spontaneous payment (keysend) to a node. /// For API contract/usage, refer to docs for [`SpontaneousSendRequest`] and [`SpontaneousSendResponse`]. pub async fn spontaneous_send( diff --git a/ldk-server-protos/src/api.rs b/ldk-server-protos/src/api.rs index b5b83bdf..9bfb1321 100644 --- a/ldk-server-protos/src/api.rs +++ b/ldk-server-protos/src/api.rs @@ -737,3 +737,21 @@ pub struct ConnectPeerRequest { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ConnectPeerResponse {} +/// Disconnect from a peer and remove it from the peer store. +/// See more: +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DisconnectPeerRequest { + /// The hex-encoded public key of the node to disconnect from. + #[prost(string, tag = "1")] + pub node_pubkey: ::prost::alloc::string::String, +} +/// 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)] +pub struct DisconnectPeerResponse {} diff --git a/ldk-server-protos/src/endpoints.rs b/ldk-server-protos/src/endpoints.rs index 52cd4a50..6833b501 100644 --- a/ldk-server-protos/src/endpoints.rs +++ b/ldk-server-protos/src/endpoints.rs @@ -26,6 +26,7 @@ pub const LIST_FORWARDED_PAYMENTS_PATH: &str = "ListForwardedPayments"; pub const UPDATE_CHANNEL_CONFIG_PATH: &str = "UpdateChannelConfig"; pub const GET_PAYMENT_DETAILS_PATH: &str = "GetPaymentDetails"; pub const CONNECT_PEER_PATH: &str = "ConnectPeer"; +pub const DISCONNECT_PEER_PATH: &str = "DisconnectPeer"; pub const SPONTANEOUS_SEND_PATH: &str = "SpontaneousSend"; pub const SIGN_MESSAGE_PATH: &str = "SignMessage"; pub const VERIFY_SIGNATURE_PATH: &str = "VerifySignature"; diff --git a/ldk-server-protos/src/proto/api.proto b/ldk-server-protos/src/proto/api.proto index f4549d0a..c982342a 100644 --- a/ldk-server-protos/src/proto/api.proto +++ b/ldk-server-protos/src/proto/api.proto @@ -579,3 +579,14 @@ message ConnectPeerRequest { // 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 {} diff --git a/ldk-server/src/api/disconnect_peer.rs b/ldk-server/src/api/disconnect_peer.rs new file mode 100644 index 00000000..76f2ecce --- /dev/null +++ b/ldk-server/src/api/disconnect_peer.rs @@ -0,0 +1,27 @@ +// 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::str::FromStr; + +use ldk_node::bitcoin::secp256k1::PublicKey; +use ldk_server_protos::api::{DisconnectPeerRequest, DisconnectPeerResponse}; + +use crate::api::error::LdkServerError; +use crate::service::Context; + +pub(crate) fn handle_disconnect_peer( + context: Context, request: DisconnectPeerRequest, +) -> Result { + let node_id = PublicKey::from_str(&request.node_pubkey) + .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; + + context.node.disconnect(node_id)?; + + Ok(DisconnectPeerResponse {}) +} diff --git a/ldk-server/src/api/mod.rs b/ldk-server/src/api/mod.rs index 98a2c14d..1bba0574 100644 --- a/ldk-server/src/api/mod.rs +++ b/ldk-server/src/api/mod.rs @@ -20,6 +20,7 @@ pub(crate) mod bolt12_receive; pub(crate) mod bolt12_send; pub(crate) mod close_channel; pub(crate) mod connect_peer; +pub(crate) mod disconnect_peer; pub(crate) mod error; pub(crate) mod export_pathfinding_scores; pub(crate) mod get_balances; diff --git a/ldk-server/src/service.rs b/ldk-server/src/service.rs index 3a188767..cdf48278 100644 --- a/ldk-server/src/service.rs +++ b/ldk-server/src/service.rs @@ -20,7 +20,7 @@ use ldk_node::bitcoin::hashes::{sha256, Hash, HashEngine}; use ldk_node::Node; use ldk_server_protos::endpoints::{ BOLT11_RECEIVE_PATH, BOLT11_SEND_PATH, BOLT12_RECEIVE_PATH, BOLT12_SEND_PATH, - CLOSE_CHANNEL_PATH, CONNECT_PEER_PATH, EXPORT_PATHFINDING_SCORES_PATH, + CLOSE_CHANNEL_PATH, CONNECT_PEER_PATH, DISCONNECT_PEER_PATH, EXPORT_PATHFINDING_SCORES_PATH, FORCE_CLOSE_CHANNEL_PATH, GET_BALANCES_PATH, GET_NODE_INFO_PATH, GET_PAYMENT_DETAILS_PATH, LIST_CHANNELS_PATH, LIST_FORWARDED_PAYMENTS_PATH, LIST_PAYMENTS_PATH, ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SIGN_MESSAGE_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH, @@ -34,6 +34,7 @@ use crate::api::bolt12_receive::handle_bolt12_receive_request; use crate::api::bolt12_send::handle_bolt12_send_request; use crate::api::close_channel::{handle_close_channel_request, handle_force_close_channel_request}; use crate::api::connect_peer::handle_connect_peer; +use crate::api::disconnect_peer::handle_disconnect_peer; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::{AuthError, InvalidRequestError}; use crate::api::export_pathfinding_scores::handle_export_pathfinding_scores_request; @@ -301,6 +302,9 @@ impl Service> for NodeService { CONNECT_PEER_PATH => { Box::pin(handle_request(context, req, auth_params, api_key, handle_connect_peer)) }, + DISCONNECT_PEER_PATH => { + Box::pin(handle_request(context, req, auth_params, api_key, handle_disconnect_peer)) + }, SPONTANEOUS_SEND_PATH => Box::pin(handle_request( context, req,