Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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