Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose NetworkGraph accessors #293

Merged
merged 2 commits into from
Jun 12, 2024
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
45 changes: 45 additions & 0 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ interface Node {
sequence<PaymentDetails> list_payments();
sequence<PeerDetails> list_peers();
sequence<ChannelDetails> list_channels();
NetworkGraph network_graph();
[Throws=NodeError]
string sign_message([ByRef]sequence<u8> msg);
boolean verify_signature([ByRef]sequence<u8> msg, [ByRef]string sig, [ByRef]PublicKey pkey);
Expand Down Expand Up @@ -167,6 +168,7 @@ enum NodeError {
"InvalidPublicKey",
"InvalidSecretKey",
"InvalidOfferId",
"InvalidNodeId",
"InvalidPaymentId",
"InvalidPaymentHash",
"InvalidPaymentPreimage",
Expand Down Expand Up @@ -387,6 +389,46 @@ enum LogLevel {
"Error",
};

interface NetworkGraph {
sequence<u64> list_channels();
ChannelInfo? channel(u64 short_channel_id);
sequence<NodeId> list_nodes();
NodeInfo? node([ByRef]NodeId node_id);
};

dictionary ChannelInfo {
NodeId node_one;
ChannelUpdateInfo? one_to_two;
NodeId node_two;
ChannelUpdateInfo? two_to_one;
u64? capacity_sats;
};

dictionary ChannelUpdateInfo {
u32 last_update;
boolean enabled;
u16 cltv_expiry_delta;
u64 htlc_minimum_msat;
u64 htlc_maximum_msat;
RoutingFees fees;
};

dictionary RoutingFees {
u32 base_msat;
u32 proportional_millionths;
};

dictionary NodeInfo {
sequence<u64> channels;
NodeAnnouncementInfo? announcement_info;
};

dictionary NodeAnnouncementInfo {
u32 last_update;
string alias;
sequence<SocketAddress> addresses;
};

[Custom]
typedef string Txid;

Expand All @@ -399,6 +441,9 @@ typedef string SocketAddress;
[Custom]
typedef string PublicKey;

[Custom]
typedef string NodeId;

[Custom]
typedef string Address;

Expand Down
4 changes: 2 additions & 2 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::payment::store::PaymentStore;
use crate::peer_store::PeerStore;
use crate::tx_broadcaster::TransactionBroadcaster;
use crate::types::{
ChainMonitor, ChannelManager, DynStore, GossipSync, KeysManager, MessageRouter, NetworkGraph,
ChainMonitor, ChannelManager, DynStore, GossipSync, Graph, KeysManager, MessageRouter,
OnionMessenger, PeerManager,
};
use crate::wallet::Wallet;
Expand Down Expand Up @@ -633,7 +633,7 @@ fn build_with_store_internal(
Ok(graph) => Arc::new(graph),
Err(e) => {
if e.kind() == std::io::ErrorKind::NotFound {
Arc::new(NetworkGraph::new(config.network.into(), Arc::clone(&logger)))
Arc::new(Graph::new(config.network.into(), Arc::clone(&logger)))
} else {
return Err(BuildError::ReadFailed);
}
Expand Down
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ pub enum Error {
InvalidSecretKey,
/// The given offer id is invalid.
InvalidOfferId,
/// The given node id is invalid.
InvalidNodeId,
/// The given payment id is invalid.
InvalidPaymentId,
/// The given payment hash is invalid.
Expand Down Expand Up @@ -120,6 +122,7 @@ impl fmt::Display for Error {
Self::InvalidPublicKey => write!(f, "The given public key is invalid."),
Self::InvalidSecretKey => write!(f, "The given secret key is invalid."),
Self::InvalidOfferId => write!(f, "The given offer id is invalid."),
Self::InvalidNodeId => write!(f, "The given node id is invalid."),
Self::InvalidPaymentId => write!(f, "The given payment id is invalid."),
Self::InvalidPaymentHash => write!(f, "The given payment hash is invalid."),
Self::InvalidPaymentPreimage => write!(f, "The given payment preimage is invalid."),
Expand Down
6 changes: 3 additions & 3 deletions src/event.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::types::{DynStore, Sweeper, Wallet};

use crate::{
hex_utils, BumpTransactionEventHandler, ChannelManager, Config, Error, NetworkGraph, PeerInfo,
hex_utils, BumpTransactionEventHandler, ChannelManager, Config, Error, Graph, PeerInfo,
PeerStore, UserChannelId,
};

Expand Down Expand Up @@ -323,7 +323,7 @@ where
channel_manager: Arc<ChannelManager>,
connection_manager: Arc<ConnectionManager<L>>,
output_sweeper: Arc<Sweeper>,
network_graph: Arc<NetworkGraph>,
network_graph: Arc<Graph>,
payment_store: Arc<PaymentStore<L>>,
peer_store: Arc<PeerStore<L>>,
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>,
Expand All @@ -339,7 +339,7 @@ where
event_queue: Arc<EventQueue<L>>, wallet: Arc<Wallet>,
bump_tx_event_handler: Arc<BumpTransactionEventHandler>,
channel_manager: Arc<ChannelManager>, connection_manager: Arc<ConnectionManager<L>>,
output_sweeper: Arc<Sweeper>, network_graph: Arc<NetworkGraph>,
output_sweeper: Arc<Sweeper>, network_graph: Arc<Graph>,
payment_store: Arc<PaymentStore<L>>, peer_store: Arc<PeerStore<L>>,
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>, logger: L, config: Arc<Config>,
) -> Self {
Expand Down
6 changes: 3 additions & 3 deletions src/gossip.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::logger::{log_trace, FilesystemLogger, Logger};
use crate::types::{GossipSync, NetworkGraph, P2PGossipSync, RapidGossipSync};
use crate::types::{GossipSync, Graph, P2PGossipSync, RapidGossipSync};
use crate::Error;

use lightning::routing::utxo::UtxoLookup;
Expand All @@ -20,7 +20,7 @@ pub(crate) enum GossipSource {
}

impl GossipSource {
pub fn new_p2p(network_graph: Arc<NetworkGraph>, logger: Arc<FilesystemLogger>) -> Self {
pub fn new_p2p(network_graph: Arc<Graph>, logger: Arc<FilesystemLogger>) -> Self {
let gossip_sync = Arc::new(P2PGossipSync::new(
network_graph,
None::<Arc<dyn UtxoLookup + Send + Sync>>,
Expand All @@ -30,7 +30,7 @@ impl GossipSource {
}

pub fn new_rgs(
server_url: String, latest_sync_timestamp: u32, network_graph: Arc<NetworkGraph>,
server_url: String, latest_sync_timestamp: u32, network_graph: Arc<Graph>,
logger: Arc<FilesystemLogger>,
) -> Self {
let gossip_sync = Arc::new(RapidGossipSync::new(network_graph, Arc::clone(&logger)));
Expand Down
166 changes: 166 additions & 0 deletions src/graph.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
//! Objects for querying the network graph.

use crate::types::Graph;

use lightning::routing::gossip::NodeId;

#[cfg(feature = "uniffi")]
use lightning::ln::msgs::SocketAddress;
#[cfg(feature = "uniffi")]
use lightning::routing::gossip::RoutingFees;

#[cfg(not(feature = "uniffi"))]
use lightning::routing::gossip::{ChannelInfo, NodeInfo};

use std::sync::Arc;

/// Represents the network as nodes and channels between them.
pub struct NetworkGraph {
inner: Arc<Graph>,
}

impl NetworkGraph {
pub(crate) fn new(inner: Arc<Graph>) -> Self {
Self { inner }
}

/// Returns the list of channels in the graph
pub fn list_channels(&self) -> Vec<u64> {
self.inner.read_only().channels().unordered_keys().map(|c| *c).collect()
}

/// Returns information on a channel with the given id.
pub fn channel(&self, short_channel_id: u64) -> Option<ChannelInfo> {
self.inner.read_only().channels().get(&short_channel_id).cloned().map(|c| c.into())
}

/// Returns the list of nodes in the graph
pub fn list_nodes(&self) -> Vec<NodeId> {
self.inner.read_only().nodes().unordered_keys().map(|n| *n).collect()
}

/// Returns information on a node with the given id.
pub fn node(&self, node_id: &NodeId) -> Option<NodeInfo> {
self.inner.read_only().nodes().get(node_id).cloned().map(|n| n.into())
}
}

/// Details about a channel (both directions).
///
/// Received within a channel announcement.
///
/// This is a simplified version of LDK's `ChannelInfo` for bindings.
#[cfg(feature = "uniffi")]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ChannelInfo {
/// Source node of the first direction of a channel
pub node_one: NodeId,
/// Details about the first direction of a channel
pub one_to_two: Option<ChannelUpdateInfo>,
/// Source node of the second direction of a channel
pub node_two: NodeId,
/// Details about the second direction of a channel
pub two_to_one: Option<ChannelUpdateInfo>,
/// The channel capacity as seen on-chain, if chain lookup is available.
pub capacity_sats: Option<u64>,
}

#[cfg(feature = "uniffi")]
impl From<lightning::routing::gossip::ChannelInfo> for ChannelInfo {
fn from(value: lightning::routing::gossip::ChannelInfo) -> Self {
Self {
node_one: value.node_one,
one_to_two: value.one_to_two.map(|u| u.into()),
node_two: value.node_two,
two_to_one: value.two_to_one.map(|u| u.into()),
capacity_sats: value.capacity_sats,
}
}
}

/// Details about one direction of a channel as received within a `ChannelUpdate`.
///
/// This is a simplified version of LDK's `ChannelUpdateInfo` for bindings.
#[cfg(feature = "uniffi")]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ChannelUpdateInfo {
/// 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: u16,
/// 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: RoutingFees,
}

#[cfg(feature = "uniffi")]
impl From<lightning::routing::gossip::ChannelUpdateInfo> for ChannelUpdateInfo {
fn from(value: lightning::routing::gossip::ChannelUpdateInfo) -> Self {
Self {
last_update: value.last_update,
enabled: value.enabled,
cltv_expiry_delta: value.cltv_expiry_delta,
htlc_minimum_msat: value.htlc_minimum_msat,
htlc_maximum_msat: value.htlc_maximum_msat,
fees: value.fees,
}
}
}

/// Details about a node in the network, known from the network announcement.
///
/// This is a simplified version of LDK's `NodeInfo` for bindings.
#[cfg(feature = "uniffi")]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NodeInfo {
/// All valid channels a node has announced
pub channels: Vec<u64>,
/// 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<NodeAnnouncementInfo>,
}

#[cfg(feature = "uniffi")]
impl From<lightning::routing::gossip::NodeInfo> for NodeInfo {
fn from(value: lightning::routing::gossip::NodeInfo) -> Self {
Self {
channels: value.channels,
announcement_info: value.announcement_info.map(|a| a.into()),
}
}
}

/// Information received in the latest node_announcement from this node.
///
/// This is a simplified version of LDK's `NodeAnnouncementInfo` for bindings.
#[cfg(feature = "uniffi")]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NodeAnnouncementInfo {
/// 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,
/// List of addresses on which this node is reachable
pub addresses: Vec<SocketAddress>,
}

#[cfg(feature = "uniffi")]
impl From<lightning::routing::gossip::NodeAnnouncementInfo> for NodeAnnouncementInfo {
fn from(value: lightning::routing::gossip::NodeAnnouncementInfo) -> Self {
Self {
last_update: value.last_update,
alias: value.alias.to_string(),
addresses: value.addresses().iter().cloned().collect(),
}
}
}
18 changes: 16 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ mod error;
mod event;
mod fee_estimator;
mod gossip;
pub mod graph;
mod hex_utils;
pub mod io;
mod liquidity;
Expand Down Expand Up @@ -128,13 +129,14 @@ use config::{
use connection::ConnectionManager;
use event::{EventHandler, EventQueue};
use gossip::GossipSource;
use graph::NetworkGraph;
use liquidity::LiquiditySource;
use payment::store::PaymentStore;
use payment::{Bolt11Payment, Bolt12Payment, OnchainPayment, PaymentDetails, SpontaneousPayment};
use peer_store::{PeerInfo, PeerStore};
use types::{
Broadcaster, BumpTransactionEventHandler, ChainMonitor, ChannelManager, DynStore, FeeEstimator,
KeysManager, NetworkGraph, PeerManager, Router, Scorer, Sweeper, Wallet,
Graph, KeysManager, PeerManager, Router, Scorer, Sweeper, Wallet,
};
pub use types::{ChannelDetails, PeerDetails, UserChannelId};

Expand Down Expand Up @@ -183,7 +185,7 @@ pub struct Node {
peer_manager: Arc<PeerManager>,
connection_manager: Arc<ConnectionManager<Arc<FilesystemLogger>>>,
keys_manager: Arc<KeysManager>,
network_graph: Arc<NetworkGraph>,
network_graph: Arc<Graph>,
gossip_source: Arc<GossipSource>,
liquidity_source: Option<Arc<LiquiditySource<Arc<FilesystemLogger>>>>,
kv_store: Arc<DynStore>,
Expand Down Expand Up @@ -1407,6 +1409,18 @@ impl Node {
peers
}

/// Returns a handler allowing to query the network graph.
#[cfg(not(feature = "uniffi"))]
pub fn network_graph(&self) -> NetworkGraph {
NetworkGraph::new(Arc::clone(&self.network_graph))
}

/// Returns a handler allowing to query the network graph.
#[cfg(feature = "uniffi")]
pub fn network_graph(&self) -> Arc<NetworkGraph> {
Arc::new(NetworkGraph::new(Arc::clone(&self.network_graph)))
}

/// Creates a digital ECDSA signature of a message with the node's secret key.
///
/// A receiver knowing the corresponding `PublicKey` (e.g. the node’s id) and the message
Expand Down
Loading
Loading