Skip to content

Commit

Permalink
Merge pull request #13 from G8XSU/s2-apis
Browse files Browse the repository at this point in the history
Implement ListChannels and GetNodeInfo Api.
  • Loading branch information
G8XSU authored Oct 18, 2024
2 parents 2c881d9 + 6d8810d commit be53832
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 40 deletions.
87 changes: 72 additions & 15 deletions protos/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,50 @@
/// 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>
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetNodeInfoRequest {}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetNodeInfoResponse {
/// The hex-encoded `node-id` or public key for our own lightning node.
#[prost(string, tag = "1")]
pub node_id: ::prost::alloc::string::String,
/// The best block to which our Lightning wallet is currently synced.
///
/// Should be always set, will never be `None`.
#[prost(message, optional, tag = "3")]
pub current_best_block: ::core::option::Option<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 since the node was initialized.
#[prost(uint64, optional, tag = "4")]
pub latest_wallet_sync_timestamp: ::core::option::Option<u64>,
/// 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<u64>,
/// 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<u64>,
/// 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<u64>,
/// 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<u64>,
}
/// Retrieve a new on-chain funding address.
/// See more: <https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.new_address>
#[allow(clippy::derive_partial_eq_without_eq)]
Expand Down Expand Up @@ -184,28 +231,28 @@ pub struct 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>
#[prost(uint32, tag = "1")]
pub forwarding_fee_proportional_millionths: u32,
#[prost(uint32, optional, tag = "1")]
pub forwarding_fee_proportional_millionths: ::core::option::Option<u32>,
/// 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>
#[prost(uint32, tag = "2")]
pub forwarding_fee_base_msat: u32,
#[prost(uint32, optional, tag = "2")]
pub forwarding_fee_base_msat: ::core::option::Option<u32>,
/// 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>
#[prost(uint32, tag = "3")]
pub cltv_expiry_delta: u32,
#[prost(uint32, optional, tag = "3")]
pub cltv_expiry_delta: ::core::option::Option<u32>,
/// The maximum additional fee we’re willing to pay to avoid waiting for the counterparty’s
/// to_self_delay to reclaim funds.
/// See more: <https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.force_close_avoidance_max_fee_satoshis>
#[prost(uint64, tag = "4")]
pub force_close_avoidance_max_fee_satoshis: u64,
#[prost(uint64, optional, tag = "4")]
pub force_close_avoidance_max_fee_satoshis: ::core::option::Option<u64>,
/// If set, allows this channel’s counterparty to skim an additional fee off this node’s
/// inbound HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users.
/// See more: <https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.accept_underpaying_htlcs>
#[prost(bool, tag = "5")]
pub accept_underpaying_htlcs: bool,
#[prost(bool, optional, tag = "5")]
pub accept_underpaying_htlcs: ::core::option::Option<bool>,
/// Limit our total exposure to potential loss to on-chain fees on close, including
/// in-flight HTLCs which are burned to fees as they are too small to claim on-chain
/// and fees on commitment transaction(s) broadcasted by our counterparty in excess of
Expand Down Expand Up @@ -284,9 +331,9 @@ pub struct Channel {
/// our counterparty already.
#[prost(message, optional, tag = "3")]
pub funding_txo: ::core::option::Option<OutPoint>,
/// The local `user_channel_id` of this channel.
#[prost(bytes = "bytes", tag = "4")]
pub user_channel_id: ::prost::bytes::Bytes,
/// The hex-encoded local `user_channel_id` of this channel.
#[prost(string, tag = "4")]
pub user_channel_id: ::prost::alloc::string::String,
/// The value, in satoshis, that must always be held as a reserve in the channel for us. This
/// value ensures that if we broadcast a revoked state, our counterparty can punish us by
/// claiming at least this value on chain.
Expand Down Expand Up @@ -383,8 +430,8 @@ pub struct Channel {
/// claiming at least this value on chain.
///
/// This value is not included in `inbound_capacity_msat` as it can never be spent.
#[prost(uint64, optional, tag = "22")]
pub counterparty_unspendable_punishment_reserve: ::core::option::Option<u64>,
#[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<u32>,
Expand All @@ -407,3 +454,13 @@ pub struct OutPoint {
#[prost(uint32, tag = "2")]
pub vout: u32,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct BestBlock {
/// The block’s hash
#[prost(string, tag = "1")]
pub block_hash: ::prost::alloc::string::String,
/// The height at which the block was confirmed.
#[prost(uint32, tag = "2")]
pub height: u32,
}
74 changes: 65 additions & 9 deletions protos/src/proto/ldk_node_server.proto
Original file line number Diff line number Diff line change
@@ -1,6 +1,52 @@
syntax = "proto3";
package ldk_node_server;

// Retrieve the latest node info like `node_id`, `current_best_block` etc.
// See more:
// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.node_id
// - https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.status
message GetNodeInfoRequest {
}

message GetNodeInfoResponse {

// The hex-encoded `node-id` or public key for our own lightning node.
string node_id = 1;

// The best block to which our Lightning wallet is currently synced.
//
// Should be always set, will never be `None`.
BestBlock current_best_block = 3;

// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our Lightning wallet
// to the chain tip.
//
// Will be `None` if the wallet hasn’t been synced since the node was initialized.
optional uint64 latest_wallet_sync_timestamp = 4;

// The timestamp, in seconds since start of the UNIX epoch, when we last successfully synced our on-chain
// wallet to the chain tip.
//
// Will be `None` if the wallet hasn’t been synced since the node was initialized.
optional uint64 latest_onchain_wallet_sync_timestamp = 5;

// The timestamp, in seconds since start of the UNIX epoch, when we last successfully update our fee rate cache.
//
// Will be `None` if the cache hasn’t been updated since the node was initialized.
optional uint64 latest_fee_rate_cache_update_timestamp = 6;

// The timestamp, in seconds since start of the UNIX epoch, when the last rapid gossip sync (RGS) snapshot we
// successfully applied was generated.
//
// Will be `None` if RGS isn’t configured or the snapshot hasn’t been updated since the node was initialized.
optional uint64 latest_rgs_snapshot_timestamp = 7;

// The timestamp, in seconds since start of the UNIX epoch, when we last broadcasted a node announcement.
//
// Will be `None` if we have no public channels or we haven’t broadcasted since the node was initialized.
optional uint64 latest_node_announcement_broadcast_timestamp = 8;
}

// Retrieve a new on-chain funding address.
// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.new_address
message OnchainReceiveRequest {
Expand Down Expand Up @@ -174,27 +220,27 @@ message ChannelConfig {
// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
// over the channel.
// See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.forwarding_fee_proportional_millionths
uint32 forwarding_fee_proportional_millionths = 1;
optional uint32 forwarding_fee_proportional_millionths = 1;

// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel,
// in excess of forwarding_fee_proportional_millionths.
// See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.forwarding_fee_base_msat
uint32 forwarding_fee_base_msat = 2;
optional uint32 forwarding_fee_base_msat = 2;

// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded
// over the channel this config applies to.
// See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.cltv_expiry_delta
uint32 cltv_expiry_delta = 3;
optional uint32 cltv_expiry_delta = 3;

// The maximum additional fee we’re willing to pay to avoid waiting for the counterparty’s
// to_self_delay to reclaim funds.
// See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.force_close_avoidance_max_fee_satoshis
uint64 force_close_avoidance_max_fee_satoshis = 4;
optional uint64 force_close_avoidance_max_fee_satoshis = 4;

// If set, allows this channel’s counterparty to skim an additional fee off this node’s
// inbound HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users.
// See more: https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.accept_underpaying_htlcs
bool accept_underpaying_htlcs = 5;
optional bool accept_underpaying_htlcs = 5;

// Limit our total exposure to potential loss to on-chain fees on close, including
// in-flight HTLCs which are burned to fees as they are too small to claim on-chain
Expand Down Expand Up @@ -259,8 +305,8 @@ message Channel {
// our counterparty already.
optional OutPoint funding_txo = 3;

// The local `user_channel_id` of this channel.
bytes user_channel_id = 4;
// The hex-encoded local `user_channel_id` of this channel.
string user_channel_id = 4;

// The value, in satoshis, that must always be held as a reserve in the channel for us. This
// value ensures that if we broadcast a revoked state, our counterparty can punish us by
Expand Down Expand Up @@ -358,7 +404,7 @@ message Channel {
// claiming at least this value on chain.
//
// This value is not included in `inbound_capacity_msat` as it can never be spent.
optional uint64 counterparty_unspendable_punishment_reserve = 22;
uint64 counterparty_unspendable_punishment_reserve = 22;

// Base routing fee in millisatoshis.
optional uint32 counterparty_forwarding_info_fee_base_msat = 23;
Expand All @@ -378,4 +424,14 @@ message OutPoint {

// 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;

}
1 change: 1 addition & 0 deletions server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ tokio = { version = "1.38.0", default-features = false, features = ["time", "sig
prost = { version = "0.11.6", default-features = false, features = ["std"] }
protos = { path = "../protos" }
bytes = "1.4.0"
hex = { package = "hex-conservative", version = "0.2.1", default-features = false }
28 changes: 28 additions & 0 deletions server/src/api/get_node_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use ldk_node::Node;
use protos::{BestBlock, GetNodeInfoRequest, GetNodeInfoResponse};
use std::sync::Arc;

pub(crate) const GET_NODE_INFO: &str = "GetNodeInfo";

pub(crate) fn handle_get_node_info_request(
node: Arc<Node>, _request: GetNodeInfoRequest,
) -> Result<GetNodeInfoResponse, ldk_node::NodeError> {
let node_status = node.status();

let best_block = BestBlock {
block_hash: node_status.current_best_block.block_hash.to_string(),
height: node_status.current_best_block.height,
};

let response = GetNodeInfoResponse {
node_id: node.node_id().to_string(),
current_best_block: Some(best_block),
latest_wallet_sync_timestamp: node_status.latest_wallet_sync_timestamp,
latest_onchain_wallet_sync_timestamp: node_status.latest_onchain_wallet_sync_timestamp,
latest_fee_rate_cache_update_timestamp: node_status.latest_fee_rate_cache_update_timestamp,
latest_rgs_snapshot_timestamp: node_status.latest_rgs_snapshot_timestamp,
latest_node_announcement_broadcast_timestamp: node_status
.latest_node_announcement_broadcast_timestamp,
};
Ok(response)
}
15 changes: 15 additions & 0 deletions server/src/api/list_channels.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use crate::util::proto_adapter::channel_to_proto;
use ldk_node::Node;
use protos::{ListChannelsRequest, ListChannelsResponse};
use std::sync::Arc;

pub(crate) const LIST_CHANNELS_PATH: &str = "ListChannels";

pub(crate) fn handle_list_channels_request(
node: Arc<Node>, _request: ListChannelsRequest,
) -> Result<ListChannelsResponse, ldk_node::NodeError> {
let channels = node.list_channels().into_iter().map(|c| channel_to_proto(c)).collect();

let response = ListChannelsResponse { channels };
Ok(response)
}
2 changes: 2 additions & 0 deletions server/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ pub(crate) mod bolt11_send;
pub(crate) mod bolt12_receive;
pub(crate) mod bolt12_send;
pub(crate) mod close_channel;
pub(crate) mod get_node_info;
pub(crate) mod list_channels;
pub(crate) mod onchain_receive;
pub(crate) mod onchain_send;
pub(crate) mod open_channel;
1 change: 1 addition & 0 deletions server/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod api;
mod service;
mod util;

use crate::service::NodeService;

Expand Down
28 changes: 12 additions & 16 deletions server/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,16 @@ use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;

use crate::api::bolt11_receive::handle_bolt11_receive_request;
use crate::api::bolt11_receive::BOLT11_RECEIVE_PATH;
use crate::api::bolt11_send::handle_bolt11_send_request;
use crate::api::bolt11_send::BOLT11_SEND_PATH;
use crate::api::bolt12_receive::handle_bolt12_receive_request;
use crate::api::bolt12_receive::BOLT12_RECEIVE_PATH;
use crate::api::bolt12_send::handle_bolt12_send_request;
use crate::api::bolt12_send::BOLT12_SEND_PATH;
use crate::api::close_channel::handle_close_channel_request;
use crate::api::close_channel::CLOSE_CHANNEL_PATH;
use crate::api::onchain_receive::handle_onchain_receive_request;
use crate::api::onchain_receive::ONCHAIN_RECEIVE_PATH;
use crate::api::onchain_send::handle_onchain_send_request;
use crate::api::onchain_send::ONCHAIN_SEND_PATH;
use crate::api::open_channel::handle_open_channel;
use crate::api::open_channel::OPEN_CHANNEL_PATH;
use crate::api::bolt11_receive::{handle_bolt11_receive_request, BOLT11_RECEIVE_PATH};
use crate::api::bolt11_send::{handle_bolt11_send_request, BOLT11_SEND_PATH};
use crate::api::bolt12_receive::{handle_bolt12_receive_request, BOLT12_RECEIVE_PATH};
use crate::api::bolt12_send::{handle_bolt12_send_request, BOLT12_SEND_PATH};
use crate::api::close_channel::{handle_close_channel_request, CLOSE_CHANNEL_PATH};
use crate::api::get_node_info::{handle_get_node_info_request, GET_NODE_INFO};
use crate::api::list_channels::{handle_list_channels_request, LIST_CHANNELS_PATH};
use crate::api::onchain_receive::{handle_onchain_receive_request, ONCHAIN_RECEIVE_PATH};
use crate::api::onchain_send::{handle_onchain_send_request, ONCHAIN_SEND_PATH};
use crate::api::open_channel::{handle_open_channel, OPEN_CHANNEL_PATH};

#[derive(Clone)]
pub struct NodeService {
Expand All @@ -48,6 +42,7 @@ impl Service<Request<Incoming>> for NodeService {
let node = Arc::clone(&self.node);
// Exclude '/' from path pattern matching.
match &req.uri().path()[1..] {
GET_NODE_INFO => Box::pin(handle_request(node, req, handle_get_node_info_request)),
ONCHAIN_RECEIVE_PATH => {
Box::pin(handle_request(node, req, handle_onchain_receive_request))
},
Expand All @@ -62,6 +57,7 @@ impl Service<Request<Incoming>> for NodeService {
BOLT12_SEND_PATH => Box::pin(handle_request(node, req, handle_bolt12_send_request)),
OPEN_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_open_channel)),
CLOSE_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_close_channel_request)),
LIST_CHANNELS_PATH => Box::pin(handle_request(node, req, handle_list_channels_request)),
path => {
let error = format!("Unknown request: {}", path).into_bytes();
Box::pin(async {
Expand Down
1 change: 1 addition & 0 deletions server/src/util/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub(crate) mod proto_adapter;
Loading

0 comments on commit be53832

Please sign in to comment.