Skip to content

Commit 9702286

Browse files
authored
Merge pull request #65 from moisesPompilio/issue-55
Add `close-channel` command to the CLI
2 parents 0e18aa7 + fd52396 commit 9702286

File tree

7 files changed

+136
-46
lines changed

7 files changed

+136
-46
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ cargo build
4646

4747
### Running
4848
```
49-
cargo run --bin ldk-server ./ldk-server/ldk-server.config
49+
cargo run --bin ldk-server ./ldk-server/ldk-server-config.toml
5050
```
5151

5252
Interact with the node using CLI:

ldk-server-cli/src/main.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use ldk_server_client::error::LdkServerErrorCode::{
66
};
77
use ldk_server_client::ldk_server_protos::api::{
88
Bolt11ReceiveRequest, Bolt11SendRequest, Bolt12ReceiveRequest, Bolt12SendRequest,
9-
GetBalancesRequest, GetNodeInfoRequest, ListChannelsRequest, ListPaymentsRequest,
10-
OnchainReceiveRequest, OnchainSendRequest, OpenChannelRequest,
9+
CloseChannelRequest, ForceCloseChannelRequest, GetBalancesRequest, GetNodeInfoRequest,
10+
ListChannelsRequest, ListPaymentsRequest, OnchainReceiveRequest, OnchainSendRequest,
11+
OpenChannelRequest,
1112
};
1213
use ldk_server_client::ldk_server_protos::types::{
1314
bolt11_invoice_description, Bolt11InvoiceDescription, PageToken, Payment,
@@ -75,6 +76,20 @@ enum Commands {
7576
#[arg(short, long)]
7677
payer_note: Option<String>,
7778
},
79+
CloseChannel {
80+
#[arg(short, long)]
81+
user_channel_id: String,
82+
#[arg(short, long)]
83+
counterparty_node_id: String,
84+
},
85+
ForceCloseChannel {
86+
#[arg(short, long)]
87+
user_channel_id: String,
88+
#[arg(short, long)]
89+
counterparty_node_id: String,
90+
#[arg(long)]
91+
force_close_reason: Option<String>,
92+
},
7893
OpenChannel {
7994
#[arg(short, long)]
8095
node_pubkey: String,
@@ -170,6 +185,28 @@ async fn main() {
170185
.await,
171186
);
172187
},
188+
Commands::CloseChannel { user_channel_id, counterparty_node_id } => {
189+
handle_response_result(
190+
client
191+
.close_channel(CloseChannelRequest { user_channel_id, counterparty_node_id })
192+
.await,
193+
);
194+
},
195+
Commands::ForceCloseChannel {
196+
user_channel_id,
197+
counterparty_node_id,
198+
force_close_reason,
199+
} => {
200+
handle_response_result(
201+
client
202+
.force_close_channel(ForceCloseChannelRequest {
203+
user_channel_id,
204+
counterparty_node_id,
205+
force_close_reason,
206+
})
207+
.await,
208+
);
209+
},
173210
Commands::OpenChannel {
174211
node_pubkey,
175212
address,

ldk-server-client/src/client.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ use crate::error::LdkServerErrorCode::{
77
use ldk_server_protos::api::{
88
Bolt11ReceiveRequest, Bolt11ReceiveResponse, Bolt11SendRequest, Bolt11SendResponse,
99
Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse,
10-
CloseChannelRequest, CloseChannelResponse, GetBalancesRequest, GetBalancesResponse,
11-
GetNodeInfoRequest, GetNodeInfoResponse, ListChannelsRequest, ListChannelsResponse,
12-
ListPaymentsRequest, ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse,
13-
OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, OpenChannelResponse,
10+
CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse,
11+
GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse,
12+
ListChannelsRequest, ListChannelsResponse, ListPaymentsRequest, ListPaymentsResponse,
13+
OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse,
14+
OpenChannelRequest, OpenChannelResponse,
1415
};
1516
use ldk_server_protos::error::{ErrorCode, ErrorResponse};
1617
use reqwest::header::CONTENT_TYPE;
@@ -28,6 +29,7 @@ const BOLT12_RECEIVE_PATH: &str = "Bolt12Receive";
2829
const BOLT12_SEND_PATH: &str = "Bolt12Send";
2930
const OPEN_CHANNEL_PATH: &str = "OpenChannel";
3031
const CLOSE_CHANNEL_PATH: &str = "CloseChannel";
32+
const FORCE_CLOSE_CHANNEL_PATH: &str = "ForceCloseChannel";
3133
const LIST_CHANNELS_PATH: &str = "ListChannels";
3234
const LIST_PAYMENTS_PATH: &str = "ListPayments";
3335

@@ -134,6 +136,15 @@ impl LdkServerClient {
134136
self.post_request(&request, &url).await
135137
}
136138

139+
/// Force closes the channel specified by given request.
140+
/// For API contract/usage, refer to docs for [`ForceCloseChannelRequest`] and [`ForceCloseChannelResponse`].
141+
pub async fn force_close_channel(
142+
&self, request: ForceCloseChannelRequest,
143+
) -> Result<ForceCloseChannelResponse, LdkServerError> {
144+
let url = format!("http://{}/{FORCE_CLOSE_CHANNEL_PATH}", self.base_url);
145+
self.post_request(&request, &url).await
146+
}
147+
137148
/// Retrieves list of known channels.
138149
/// For API contract/usage, refer to docs for [`ListChannelsRequest`] and [`ListChannelsResponse`].
139150
pub async fn list_channels(

ldk-server-protos/src/api.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,7 @@ pub struct UpdateChannelConfigRequest {
270270
#[derive(Clone, PartialEq, ::prost::Message)]
271271
pub struct UpdateChannelConfigResponse {}
272272
/// Closes the channel specified by given request.
273-
/// See more:
274-
/// - <https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.close_channel>
275-
/// - <https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.force_close_channel>
273+
/// See more: <https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.close_channel>
276274
#[allow(clippy::derive_partial_eq_without_eq)]
277275
#[derive(Clone, PartialEq, ::prost::Message)]
278276
pub struct CloseChannelRequest {
@@ -282,18 +280,32 @@ pub struct CloseChannelRequest {
282280
/// The hex-encoded public key of the node to close a channel with.
283281
#[prost(string, tag = "2")]
284282
pub counterparty_node_id: ::prost::alloc::string::String,
285-
/// Whether to force close the specified channel.
286-
#[prost(bool, optional, tag = "3")]
287-
pub force_close: ::core::option::Option<bool>,
288-
/// The reason for force-closing, can only be set while force closing a channel.
289-
#[prost(string, optional, tag = "4")]
290-
pub force_close_reason: ::core::option::Option<::prost::alloc::string::String>,
291283
}
292284
/// The response `content` for the `CloseChannel` API, when HttpStatusCode is OK (200).
293285
/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`.
294286
#[allow(clippy::derive_partial_eq_without_eq)]
295287
#[derive(Clone, PartialEq, ::prost::Message)]
296288
pub struct CloseChannelResponse {}
289+
/// Force closes the channel specified by given request.
290+
/// See more: <https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.force_close_channel>
291+
#[allow(clippy::derive_partial_eq_without_eq)]
292+
#[derive(Clone, PartialEq, ::prost::Message)]
293+
pub struct ForceCloseChannelRequest {
294+
/// The local `user_channel_id` of this channel.
295+
#[prost(string, tag = "1")]
296+
pub user_channel_id: ::prost::alloc::string::String,
297+
/// The hex-encoded public key of the node to close a channel with.
298+
#[prost(string, tag = "2")]
299+
pub counterparty_node_id: ::prost::alloc::string::String,
300+
/// The reason for force-closing.
301+
#[prost(string, optional, tag = "3")]
302+
pub force_close_reason: ::core::option::Option<::prost::alloc::string::String>,
303+
}
304+
/// The response `content` for the `ForceCloseChannel` API, when HttpStatusCode is OK (200).
305+
/// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`.
306+
#[allow(clippy::derive_partial_eq_without_eq)]
307+
#[derive(Clone, PartialEq, ::prost::Message)]
308+
pub struct ForceCloseChannelResponse {}
297309
/// Returns a list of known channels.
298310
/// See more: <https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_channels>
299311
#[allow(clippy::derive_partial_eq_without_eq)]

ldk-server-protos/src/proto/api.proto

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -261,30 +261,35 @@ message UpdateChannelConfigResponse {
261261
}
262262

263263
// Closes the channel specified by given request.
264-
// See more:
265-
// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.close_channel
266-
// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.force_close_channel
264+
// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.close_channel
267265
message CloseChannelRequest {
268266

269267
// The local `user_channel_id` of this channel.
270268
string user_channel_id = 1;
271269

272270
// The hex-encoded public key of the node to close a channel with.
273271
string counterparty_node_id = 2;
274-
275-
// Whether to force close the specified channel.
276-
optional bool force_close = 3;
277-
278-
// The reason for force-closing, can only be set while force closing a channel.
279-
optional string force_close_reason = 4;
280272
}
281273

282274
// The response `content` for the `CloseChannel` API, when HttpStatusCode is OK (200).
283275
// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`.
284-
message CloseChannelResponse {
276+
message CloseChannelResponse {}
285277

278+
// Force closes the channel specified by given request.
279+
// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.force_close_channel
280+
message ForceCloseChannelRequest {
281+
// The local `user_channel_id` of this channel.
282+
string user_channel_id = 1;
283+
// The hex-encoded public key of the node to close a channel with.
284+
string counterparty_node_id = 2;
285+
// The reason for force-closing.
286+
optional string force_close_reason = 3;
286287
}
287288

289+
// The response `content` for the `ForceCloseChannel` API, when HttpStatusCode is OK (200).
290+
// When HttpStatusCode is not OK (non-200), the response `content` contains a serialized `ErrorResponse`.
291+
message ForceCloseChannelResponse {}
292+
288293
// Returns a list of known channels.
289294
// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_channels
290295
message ListChannelsRequest {}

ldk-server/src/api/close_channel.rs

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,53 @@ use crate::api::error::LdkServerErrorCode::InvalidRequestError;
33
use crate::service::Context;
44
use ldk_node::bitcoin::secp256k1::PublicKey;
55
use ldk_node::UserChannelId;
6-
use ldk_server_protos::api::{CloseChannelRequest, CloseChannelResponse};
6+
use ldk_server_protos::api::{
7+
CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse,
8+
};
79
use std::str::FromStr;
810

911
pub(crate) const CLOSE_CHANNEL_PATH: &str = "CloseChannel";
1012

1113
pub(crate) fn handle_close_channel_request(
1214
context: Context, request: CloseChannelRequest,
1315
) -> Result<CloseChannelResponse, LdkServerError> {
14-
let user_channel_id =
15-
UserChannelId((&request.user_channel_id).parse::<u128>().map_err(|_| {
16-
LdkServerError::new(InvalidRequestError, "Invalid UserChannelId.".to_string())
17-
})?);
18-
let counterparty_node_id = PublicKey::from_str(&request.counterparty_node_id).map_err(|e| {
16+
let user_channel_id = parse_user_channel_id(&request.user_channel_id)?;
17+
let counterparty_node_id = parse_counterparty_node_id(&request.counterparty_node_id)?;
18+
19+
context.node.close_channel(&user_channel_id, counterparty_node_id)?;
20+
21+
Ok(CloseChannelResponse {})
22+
}
23+
24+
pub(crate) const FORCE_CLOSE_CHANNEL_PATH: &str = "ForceCloseChannel";
25+
26+
pub(crate) fn handle_force_close_channel_request(
27+
context: Context, request: ForceCloseChannelRequest,
28+
) -> Result<ForceCloseChannelResponse, LdkServerError> {
29+
let user_channel_id = parse_user_channel_id(&request.user_channel_id)?;
30+
let counterparty_node_id = parse_counterparty_node_id(&request.counterparty_node_id)?;
31+
32+
context.node.force_close_channel(
33+
&user_channel_id,
34+
counterparty_node_id,
35+
request.force_close_reason,
36+
)?;
37+
38+
Ok(ForceCloseChannelResponse {})
39+
}
40+
41+
fn parse_user_channel_id(id: &str) -> Result<UserChannelId, LdkServerError> {
42+
let parsed = id.parse::<u128>().map_err(|_| {
43+
LdkServerError::new(InvalidRequestError, "Invalid UserChannelId.".to_string())
44+
})?;
45+
Ok(UserChannelId(parsed))
46+
}
47+
48+
fn parse_counterparty_node_id(id: &str) -> Result<PublicKey, LdkServerError> {
49+
PublicKey::from_str(id).map_err(|e| {
1950
LdkServerError::new(
2051
InvalidRequestError,
2152
format!("Invalid counterparty node ID, error: {}", e),
2253
)
23-
})?;
24-
25-
match request.force_close {
26-
Some(true) => context.node.force_close_channel(
27-
&user_channel_id,
28-
counterparty_node_id,
29-
request.force_close_reason,
30-
)?,
31-
_ => context.node.close_channel(&user_channel_id, counterparty_node_id)?,
32-
};
33-
34-
let response = CloseChannelResponse {};
35-
Ok(response)
54+
})
3655
}

ldk-server/src/service.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ use crate::api::bolt11_receive::{handle_bolt11_receive_request, BOLT11_RECEIVE_P
1111
use crate::api::bolt11_send::{handle_bolt11_send_request, BOLT11_SEND_PATH};
1212
use crate::api::bolt12_receive::{handle_bolt12_receive_request, BOLT12_RECEIVE_PATH};
1313
use crate::api::bolt12_send::{handle_bolt12_send_request, BOLT12_SEND_PATH};
14-
use crate::api::close_channel::{handle_close_channel_request, CLOSE_CHANNEL_PATH};
14+
use crate::api::close_channel::{
15+
handle_close_channel_request, handle_force_close_channel_request, CLOSE_CHANNEL_PATH,
16+
FORCE_CLOSE_CHANNEL_PATH,
17+
};
1518
use crate::api::error::LdkServerError;
1619
use crate::api::error::LdkServerErrorCode::InvalidRequestError;
1720
use crate::api::get_balances::{handle_get_balances_request, GET_BALANCES};
@@ -85,6 +88,9 @@ impl Service<Request<Incoming>> for NodeService {
8588
CLOSE_CHANNEL_PATH => {
8689
Box::pin(handle_request(context, req, handle_close_channel_request))
8790
},
91+
FORCE_CLOSE_CHANNEL_PATH => {
92+
Box::pin(handle_request(context, req, handle_force_close_channel_request))
93+
},
8894
LIST_CHANNELS_PATH => {
8995
Box::pin(handle_request(context, req, handle_list_channels_request))
9096
},

0 commit comments

Comments
 (0)