Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
tnull committed Jan 3, 2024
1 parent 5b20403 commit 92b4c42
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 11 deletions.
11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ lightning-persister = { version = "0.0.119" }
lightning-background-processor = { version = "0.0.119", features = ["futures"] }
lightning-rapid-gossip-sync = { version = "0.0.119" }
lightning-transaction-sync = { version = "0.0.119", features = ["esplora-async-https"] }
#lightning-liquidity = { git = "https://github.com/tnull/lightning-liquidity", branch="2023-12-upgrade-to-LDK-0.0.119", features = ["std"] }
lightning-liquidity = { git = "https://github.com/tnull/lightning-liquidity", branch="2024-01-async-event-queue", features = ["std"] }

#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["std"] }
#lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main" }
Expand All @@ -44,6 +46,15 @@ lightning-transaction-sync = { version = "0.0.119", features = ["esplora-async-h
#lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main" }
#lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["esplora-async"] }

# lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["std"] }
# lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main" }
# lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main" }
# lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main" }
# lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["futures"] }
# lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main" }
# lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["esplora-async"] }
# lightning-liquidity = { git = "https://github.com/lightningdevkit/lightning-liquidity", branch="main", features = ["std"] }

#lightning = { path = "../rust-lightning/lightning", features = ["std"] }
#lightning-invoice = { path = "../rust-lightning/lightning-invoice" }
#lightning-net-tokio = { path = "../rust-lightning/lightning-net-tokio" }
Expand Down
1 change: 1 addition & 0 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ interface Builder {
void set_esplora_server(string esplora_server_url);
void set_gossip_source_p2p();
void set_gossip_source_rgs(string rgs_server_url);
void set_liquidity_source_lsps2(string service_url, PublicKey service_node_id, string token);
void set_storage_dir_path(string storage_dir_path);
void set_network(Network network);
[Throws=BuildError]
Expand Down
83 changes: 75 additions & 8 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::fee_estimator::OnchainFeeEstimator;
use crate::gossip::GossipSource;
use crate::io;
use crate::io::sqlite_store::SqliteStore;
use crate::liquidity::LiquiditySource;
use crate::logger::{log_error, FilesystemLogger, Logger};
use crate::payment_store::PaymentStore;
use crate::peer_store::PeerStore;
Expand Down Expand Up @@ -40,6 +41,9 @@ use lightning_persister::fs_store::FilesystemStore;

use lightning_transaction_sync::EsploraSyncClient;

use lightning_liquidity::lsps2::client::LSPS2ClientConfig;
use lightning_liquidity::{LiquidityClientConfig, LiquidityManager};

#[cfg(any(vss, vss_test))]
use crate::io::vss_store::VssStore;
use bdk::bitcoin::secp256k1::Secp256k1;
Expand All @@ -49,6 +53,7 @@ use bdk::template::Bip84;

use bip39::Mnemonic;

use bitcoin::secp256k1::PublicKey;
use bitcoin::BlockHash;

use std::convert::TryInto;
Expand Down Expand Up @@ -78,6 +83,11 @@ enum GossipSourceConfig {
RapidGossipSync(String),
}

#[derive(Debug, Clone)]
enum LiquiditySourceConfig {
LSPS2Service { service_url: String, service_node_id: PublicKey, token: String },
}

/// An error encountered during building a [`Node`].
///
/// [`Node`]: crate::Node
Expand Down Expand Up @@ -144,16 +154,14 @@ pub struct NodeBuilder {
entropy_source_config: Option<EntropySourceConfig>,
chain_data_source_config: Option<ChainDataSourceConfig>,
gossip_source_config: Option<GossipSourceConfig>,
liquidity_source_config: Option<LiquiditySourceConfig>,
}

impl NodeBuilder {
/// Creates a new builder instance with the default configuration.
pub fn new() -> Self {
let config = Config::default();
let entropy_source_config = None;
let chain_data_source_config = None;
let gossip_source_config = None;
Self { config, entropy_source_config, chain_data_source_config, gossip_source_config }
Self::from_config(config)
}

/// Creates a new builder instance from an [`Config`].
Expand All @@ -162,7 +170,14 @@ impl NodeBuilder {
let entropy_source_config = None;
let chain_data_source_config = None;
let gossip_source_config = None;
Self { config, entropy_source_config, chain_data_source_config, gossip_source_config }
let liquidity_source_config = None;
Self {
config,
entropy_source_config,
chain_data_source_config,
gossip_source_config,
liquidity_source_config,
}
}

/// Configures the [`Node`] instance to source its wallet entropy from a seed file on disk.
Expand Down Expand Up @@ -216,6 +231,19 @@ impl NodeBuilder {
self
}

/// Configures the [`Node`] instance to source its inbound liquidity from the given
/// [LSPS2](https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md)
/// service.
///
/// The given `token` will be used by the LSP to authenticate the user.
pub fn set_liquidity_source_lsps2(
&mut self, service_url: String, service_node_id: PublicKey, token: String,
) -> &mut Self {
self.liquidity_source_config =
Some(LiquiditySourceConfig::LSPS2Service { service_url, service_node_id, token });
self
}

/// Sets the used storage directory path.
pub fn set_storage_dir_path(&mut self, storage_dir_path: String) -> &mut Self {
self.config.storage_dir_path = storage_dir_path;
Expand Down Expand Up @@ -307,6 +335,7 @@ impl NodeBuilder {
config,
self.chain_data_source_config.as_ref(),
self.gossip_source_config.as_ref(),
self.liquidity_source_config.as_ref(),
seed_bytes,
logger,
kv_store,
Expand Down Expand Up @@ -380,6 +409,17 @@ impl ArcedNodeBuilder {
self.inner.write().unwrap().set_gossip_source_rgs(rgs_server_url);
}

/// Configures the [`Node`] instance to source its inbound liquidity from the given
/// [LSPS2](https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md)
/// service.
///
/// The given `token` will be used by the LSP to authenticate the user.
pub fn set_liquidity_source_lsps2(
&self, service_url: String, service_node_id: PublicKey, token: String,
) {
self.inner.write().unwrap().set_liquidity_source_lsps2(service_url, service_node_id, token);
}

/// Sets the used storage directory path.
pub fn set_storage_dir_path(&self, storage_dir_path: String) {
self.inner.write().unwrap().set_storage_dir_path(storage_dir_path);
Expand Down Expand Up @@ -430,7 +470,8 @@ impl ArcedNodeBuilder {
/// Builds a [`Node`] instance according to the options previously configured.
fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
config: Arc<Config>, chain_data_source_config: Option<&ChainDataSourceConfig>,
gossip_source_config: Option<&GossipSourceConfig>, seed_bytes: [u8; 64],
gossip_source_config: Option<&GossipSourceConfig>,
liquidity_source_config: Option<&LiquiditySourceConfig>, seed_bytes: [u8; 64],
logger: Arc<FilesystemLogger>, kv_store: Arc<K>,
) -> Result<Node<K>, BuildError> {
// Initialize the on-chain wallet and chain access
Expand Down Expand Up @@ -707,20 +748,43 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
}
};

let liquidity_source = match liquidity_source_config {
Some(LiquiditySourceConfig::LSPS2Service { service_url, service_node_id, token }) => {
let lsps2_client_config = Some(LSPS2ClientConfig {});
let liquidity_client_config = Some(LiquidityClientConfig { lsps2_client_config });

let liquidity_manager = Arc::new(LiquidityManager::new(
Arc::clone(&keys_manager),
Arc::clone(&channel_manager),
Some(Arc::clone(&tx_sync)),
None,
None,
liquidity_client_config,
));
Arc::new(LiquiditySource::new_lsps2(
Arc::clone(&liquidity_manager),
service_url.clone(),
*service_node_id,
token.clone(),
))
}
None => Arc::new(LiquiditySource::new_none()),
};

let msg_handler = match gossip_source.as_gossip_sync() {
GossipSync::P2P(p2p_gossip_sync) => MessageHandler {
chan_handler: Arc::clone(&channel_manager),
route_handler: Arc::clone(&p2p_gossip_sync)
as Arc<dyn RoutingMessageHandler + Sync + Send>,
onion_message_handler: onion_messenger,
custom_message_handler: IgnoringMessageHandler {},
custom_message_handler: Arc::clone(&liquidity_source),
},
GossipSync::Rapid(_) => MessageHandler {
chan_handler: Arc::clone(&channel_manager),
route_handler: Arc::new(IgnoringMessageHandler {})
as Arc<dyn RoutingMessageHandler + Sync + Send>,
onion_message_handler: onion_messenger,
custom_message_handler: IgnoringMessageHandler {},
custom_message_handler: Arc::clone(&liquidity_source),
},
GossipSync::None => {
unreachable!("We must always have a gossip sync!");
Expand All @@ -743,6 +807,8 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
Arc::clone(&keys_manager),
));

liquidity_source.set_peer_manager(Arc::clone(&peer_manager));

// Init payment info storage
let payment_store = match io::utils::read_payments(Arc::clone(&kv_store), Arc::clone(&logger)) {
Ok(payments) => {
Expand Down Expand Up @@ -814,6 +880,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
keys_manager,
network_graph,
gossip_source,
liquidity_source,
kv_store,
logger,
_router: router,
Expand Down
16 changes: 16 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ mod fee_estimator;
mod gossip;
mod hex_utils;
pub mod io;
mod liquidity;
mod logger;
mod payment_store;
mod peer_store;
Expand Down Expand Up @@ -115,6 +116,7 @@ pub use builder::NodeBuilder as Builder;

use event::{EventHandler, EventQueue};
use gossip::GossipSource;
use liquidity::LiquiditySource;
use payment_store::PaymentStore;
pub use payment_store::{PaymentDetails, PaymentDirection, PaymentStatus};
use peer_store::{PeerInfo, PeerStore};
Expand Down Expand Up @@ -297,6 +299,7 @@ pub struct Node<K: KVStore + Sync + Send + 'static> {
keys_manager: Arc<KeysManager>,
network_graph: Arc<NetworkGraph>,
gossip_source: Arc<GossipSource>,
liquidity_source: Arc<LiquiditySource<K>>,
kv_store: Arc<K>,
logger: Arc<FilesystemLogger>,
_router: Arc<Router>,
Expand Down Expand Up @@ -750,6 +753,19 @@ impl<K: KVStore + Sync + Send + 'static> Node<K> {
});
});

let mut stop_liquidity_handler = self.stop_receiver.clone();
let liquidity_handler = Arc::clone(&self.liquidity_source);
runtime.spawn(async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
return;
}
_ = liquidity_handler.handle_next_event() => {}
}
}
});

*runtime_lock = Some(runtime);

log_info!(self.logger, "Startup complete.");
Expand Down
122 changes: 122 additions & 0 deletions src/liquidity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use crate::types::{LiquidityManager, PeerManager};

use lightning::ln::features::{InitFeatures, NodeFeatures};
use lightning::ln::peer_handler::CustomMessageHandler;
use lightning::ln::wire::CustomMessageReader;
use lightning::util::persist::KVStore;
use lightning_liquidity::events::Event;
use lightning_liquidity::lsps0::msgs::RawLSPSMessage;
use lightning_liquidity::lsps2::event::LSPS2ClientEvent;

use bitcoin::secp256k1::PublicKey;

use std::sync::Arc;

pub(crate) enum LiquiditySource<K: KVStore + Sync + Send + 'static> {
None,
LSPS2 {
liquidity_manager: Arc<LiquidityManager<K>>,
service_url: String,
service_node_id: PublicKey,
token: String,
},
}

impl<K: KVStore + Sync + Send> LiquiditySource<K> {
pub(crate) fn new_lsps2(
liquidity_manager: Arc<LiquidityManager<K>>, service_url: String,
service_node_id: PublicKey, token: String,
) -> Self {
Self::LSPS2 { liquidity_manager, service_url, service_node_id, token }
}

pub(crate) fn new_none() -> Self {
Self::None
}

pub(crate) fn set_peer_manager(&self, peer_manager: Arc<PeerManager<K>>) {
match self {
Self::LSPS2 { liquidity_manager, .. } => {
let process_msgs_callback = move || peer_manager.process_events();
liquidity_manager.set_process_msgs_callback(process_msgs_callback);
}
Self::None => {}
}
}

pub(crate) async fn handle_next_event(&self) {
match self {
Self::LSPS2 { liquidity_manager, service_url, service_node_id, token } => {
match liquidity_manager.next_event_async().await {
Event::LSPS2Client(LSPS2ClientEvent::GetInfoResponse {
jit_channel_id: _,
counterparty_node_id: _,
opening_fee_params_menu: _,
min_payment_size_msat: _,
max_payment_size_msat: _,
user_channel_id: _,
}) => {}
Event::LSPS2Client(LSPS2ClientEvent::InvoiceGenerationReady {
counterparty_node_id: _,
scid: _,
cltv_expiry_delta: _,
payment_size_msat: _,
client_trusts_lsp: _,
user_channel_id: _,
}) => {}
_ => {}
}
}
Self::None => {}
}
}
}

impl<K: KVStore + Sync + Send + 'static> CustomMessageReader for LiquiditySource<K> {
type CustomMessage = RawLSPSMessage;

fn read<RD: lightning::io::Read>(
&self, message_type: u16, buffer: &mut RD,
) -> Result<Option<Self::CustomMessage>, lightning::ln::msgs::DecodeError> {
match self {
Self::LSPS2 { liquidity_manager, .. } => liquidity_manager.read(message_type, buffer),
Self::None => Ok(None),
}
}
}

impl<K: KVStore + Sync + Send + 'static> CustomMessageHandler for LiquiditySource<K> {
fn handle_custom_message(
&self, msg: Self::CustomMessage, sender_node_id: &PublicKey,
) -> Result<(), lightning::ln::msgs::LightningError> {
match self {
Self::LSPS2 { liquidity_manager, .. } => {
liquidity_manager.handle_custom_message(msg, sender_node_id)
}
Self::None => Ok(()), // Should be unreachable!() as the reader will return `None`
}
}

fn get_and_clear_pending_msg(&self) -> Vec<(PublicKey, Self::CustomMessage)> {
match self {
Self::LSPS2 { liquidity_manager, .. } => liquidity_manager.get_and_clear_pending_msg(),
Self::None => Vec::new(),
}
}

fn provided_node_features(&self) -> NodeFeatures {
match self {
Self::LSPS2 { liquidity_manager, .. } => liquidity_manager.provided_node_features(),
Self::None => NodeFeatures::empty(),
}
}

fn provided_init_features(&self, their_node_id: &PublicKey) -> InitFeatures {
match self {
Self::LSPS2 { liquidity_manager, .. } => {
liquidity_manager.provided_init_features(their_node_id)
}
Self::None => InitFeatures::empty(),
}
}
}
Loading

0 comments on commit 92b4c42

Please sign in to comment.