Skip to content

Commit 0e18aa7

Browse files
authored
Merge pull request #60 from G8XSU/25-3-20-lsps2
Add experimental LSPS2 support.
2 parents 96de892 + 551015a commit 0e18aa7

File tree

5 files changed

+158
-47
lines changed

5 files changed

+158
-47
lines changed

ldk-server/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ lapin = { version = "2.4.0", features = ["rustls"], default-features = false, op
2626
default = []
2727
events-rabbitmq = ["dep:lapin"]
2828

29+
# Experimental Features.
30+
experimental-lsps2-support = []
31+
2932
# Feature-flags related to integration tests.
3033
integration-tests-events-rabbitmq = ["events-rabbitmq"]
3134

ldk-server/ldk-server-config.toml

+33-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,36 @@ rpc_password = "polarpass" # RPC password
1717
# RabbitMQ settings (only required if using events-rabbitmq feature)
1818
[rabbitmq]
1919
connection_string = "" # RabbitMQ connection string
20-
exchange_name = "" # RabbitMQ exchange name
20+
exchange_name = ""
21+
22+
# Experimental LSPS2 Service Support
23+
# CAUTION: LSPS2 support is highly experimental and for testing purposes only.
24+
[liquidity.lsps2_service]
25+
# Indicates whether the LSPS service will be announced via the gossip network.
26+
advertise_service = false
27+
28+
# The fee we withhold for the channel open from the initial payment.
29+
channel_opening_fee_ppm = 1000 # 0.1% fee
30+
31+
# The proportional overprovisioning for the channel.
32+
channel_over_provisioning_ppm = 500000 # 50% extra capacity
33+
34+
# The minimum fee required for opening a channel.
35+
min_channel_opening_fee_msat = 10000000 # 10,000 satoshis
36+
37+
# The minimum number of blocks after confirmation we promise to keep the channel open.
38+
min_channel_lifetime = 4320 # ~30 days
39+
40+
# The maximum number of blocks that the client is allowed to set its `to_self_delay` parameter.
41+
max_client_to_self_delay = 1440 # ~10 days
42+
43+
# The minimum payment size that we will accept when opening a channel.
44+
min_payment_size_msat = 10000000 # 10,000 satoshis
45+
46+
# The maximum payment size that we will accept when opening a channel.
47+
max_payment_size_msat = 25000000000 # 0.25 BTC
48+
49+
# Optional token for clients (uncomment and set if required)
50+
## A token we may require to be sent by the clients.
51+
## If set, only requests matching this token will be accepted. (uncomment and set if required)
52+
# require_token = ""

ldk-server/ldk-server.config

-29
This file was deleted.

ldk-server/src/main.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto};
2929
use hex::DisplayHex;
3030
use ldk_node::config::Config;
3131
use ldk_node::lightning::ln::channelmanager::PaymentId;
32-
use ldk_node::logger::LogLevel;
32+
#[cfg(feature = "experimental-lsps2-support")]
33+
use ldk_node::liquidity::LSPS2ServiceConfig;
3334
use ldk_server_protos::events;
3435
use ldk_server_protos::events::{event_envelope, EventEnvelope};
3536
use ldk_server_protos::types::Payment;
@@ -63,7 +64,13 @@ fn main() {
6364
}
6465

6566
let mut ldk_node_config = Config::default();
66-
let config_file = load_config(Path::new(arg)).expect("Invalid configuration file.");
67+
let config_file = match load_config(Path::new(arg)) {
68+
Ok(config) => config,
69+
Err(e) => {
70+
eprintln!("Invalid configuration file: {}", e);
71+
std::process::exit(-1);
72+
},
73+
};
6774

6875
ldk_node_config.storage_dir_path = config_file.storage_dir_path.clone();
6976
ldk_node_config.listening_addresses = Some(vec![config_file.listening_addr]);
@@ -81,6 +88,12 @@ fn main() {
8188
config_file.bitcoind_rpc_password,
8289
);
8390

91+
// LSPS2 support is highly experimental and for testing purposes only.
92+
#[cfg(feature = "experimental-lsps2-support")]
93+
builder.set_liquidity_provider_lsps2(
94+
config_file.lsps2_service_config.expect("Missing liquidity.lsps2_server config"),
95+
);
96+
8497
let runtime = match tokio::runtime::Builder::new_multi_thread().enable_all().build() {
8598
Ok(runtime) => Arc::new(runtime),
8699
Err(e) => {

ldk-server/src/util/config.rs

+107-15
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use ldk_node::bitcoin::Network;
22
use ldk_node::lightning::ln::msgs::SocketAddress;
3+
use ldk_node::liquidity::LSPS2ServiceConfig;
34
use serde::{Deserialize, Serialize};
45
use std::net::SocketAddr;
56
use std::path::Path;
67
use std::str::FromStr;
78
use std::{fs, io};
89

910
/// Configuration for LDK Server.
10-
#[derive(PartialEq, Eq, Debug)]
11+
#[derive(Debug)]
1112
pub struct Config {
1213
pub listening_addr: SocketAddress,
1314
pub network: Network,
@@ -18,6 +19,7 @@ pub struct Config {
1819
pub bitcoind_rpc_password: String,
1920
pub rabbitmq_connection_string: String,
2021
pub rabbitmq_exchange_name: String,
22+
pub lsps2_service_config: Option<LSPS2ServiceConfig>,
2123
}
2224

2325
impl TryFrom<TomlConfig> for Config {
@@ -61,6 +63,17 @@ impl TryFrom<TomlConfig> for Config {
6163
(rabbitmq.connection_string, rabbitmq.exchange_name)
6264
};
6365

66+
#[cfg(not(feature = "experimental-lsps2-support"))]
67+
let lsps2_service_config: Option<LSPS2ServiceConfig> = None;
68+
#[cfg(feature = "experimental-lsps2-support")]
69+
let lsps2_service_config = Some(toml_config.liquidity
70+
.and_then(|l| l.lsps2_service)
71+
.ok_or_else(|| io::Error::new(
72+
io::ErrorKind::InvalidInput,
73+
"`liquidity.lsps2_service` must be defined in config if enabling `experimental-lsps2-support` feature."
74+
))?
75+
.into());
76+
6477
Ok(Config {
6578
listening_addr,
6679
network: toml_config.node.network,
@@ -71,6 +84,7 @@ impl TryFrom<TomlConfig> for Config {
7184
bitcoind_rpc_password: toml_config.bitcoind.rpc_password,
7285
rabbitmq_connection_string,
7386
rabbitmq_exchange_name,
87+
lsps2_service_config,
7488
})
7589
}
7690
}
@@ -82,6 +96,7 @@ pub struct TomlConfig {
8296
storage: StorageConfig,
8397
bitcoind: BitcoindConfig,
8498
rabbitmq: Option<RabbitmqConfig>,
99+
liquidity: Option<LiquidityConfig>,
85100
}
86101

87102
#[derive(Deserialize, Serialize)]
@@ -114,6 +129,52 @@ struct RabbitmqConfig {
114129
exchange_name: String,
115130
}
116131

132+
#[derive(Deserialize, Serialize)]
133+
struct LiquidityConfig {
134+
lsps2_service: Option<LSPS2ServiceTomlConfig>,
135+
}
136+
137+
#[derive(Deserialize, Serialize, Debug)]
138+
struct LSPS2ServiceTomlConfig {
139+
advertise_service: bool,
140+
channel_opening_fee_ppm: u32,
141+
channel_over_provisioning_ppm: u32,
142+
min_channel_opening_fee_msat: u64,
143+
min_channel_lifetime: u32,
144+
max_client_to_self_delay: u32,
145+
min_payment_size_msat: u64,
146+
max_payment_size_msat: u64,
147+
require_token: Option<String>,
148+
}
149+
150+
impl Into<LSPS2ServiceConfig> for LSPS2ServiceTomlConfig {
151+
fn into(self) -> LSPS2ServiceConfig {
152+
match self {
153+
LSPS2ServiceTomlConfig {
154+
advertise_service,
155+
channel_opening_fee_ppm,
156+
channel_over_provisioning_ppm,
157+
min_channel_opening_fee_msat,
158+
min_channel_lifetime,
159+
max_client_to_self_delay,
160+
min_payment_size_msat,
161+
max_payment_size_msat,
162+
require_token,
163+
} => LSPS2ServiceConfig {
164+
advertise_service,
165+
channel_opening_fee_ppm,
166+
channel_over_provisioning_ppm,
167+
min_channel_opening_fee_msat,
168+
min_channel_lifetime,
169+
min_payment_size_msat,
170+
max_client_to_self_delay,
171+
max_payment_size_msat,
172+
require_token,
173+
},
174+
}
175+
}
176+
}
177+
117178
/// Loads the configuration from a TOML file at the given path.
118179
pub fn load_config<P: AsRef<Path>>(config_path: P) -> io::Result<Config> {
119180
let file_contents = fs::read_to_string(config_path.as_ref()).map_err(|e| {
@@ -160,23 +221,54 @@ mod tests {
160221
[rabbitmq]
161222
connection_string = "rabbitmq_connection_string"
162223
exchange_name = "rabbitmq_exchange_name"
224+
225+
[liquidity.lsps2_service]
226+
advertise_service = false
227+
channel_opening_fee_ppm = 1000 # 0.1% fee
228+
channel_over_provisioning_ppm = 500000 # 50% extra capacity
229+
min_channel_opening_fee_msat = 10000000 # 10,000 satoshis
230+
min_channel_lifetime = 4320 # ~30 days
231+
max_client_to_self_delay = 1440 # ~10 days
232+
min_payment_size_msat = 10000000 # 10,000 satoshis
233+
max_payment_size_msat = 25000000000 # 0.25 BTC
163234
"#;
164235

165236
fs::write(storage_path.join(config_file_name), toml_config).unwrap();
166237

167-
assert_eq!(
168-
load_config(storage_path.join(config_file_name)).unwrap(),
169-
Config {
170-
listening_addr: SocketAddress::from_str("localhost:3001").unwrap(),
171-
network: Network::Regtest,
172-
rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(),
173-
storage_dir_path: "/tmp".to_string(),
174-
bitcoind_rpc_addr: SocketAddr::from_str("127.0.0.1:8332").unwrap(),
175-
bitcoind_rpc_user: "bitcoind-testuser".to_string(),
176-
bitcoind_rpc_password: "bitcoind-testpassword".to_string(),
177-
rabbitmq_connection_string: "rabbitmq_connection_string".to_string(),
178-
rabbitmq_exchange_name: "rabbitmq_exchange_name".to_string(),
179-
}
180-
)
238+
let config = load_config(storage_path.join(config_file_name)).unwrap();
239+
let expected = Config {
240+
listening_addr: SocketAddress::from_str("localhost:3001").unwrap(),
241+
network: Network::Regtest,
242+
rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(),
243+
storage_dir_path: "/tmp".to_string(),
244+
bitcoind_rpc_addr: SocketAddr::from_str("127.0.0.1:8332").unwrap(),
245+
bitcoind_rpc_user: "bitcoind-testuser".to_string(),
246+
bitcoind_rpc_password: "bitcoind-testpassword".to_string(),
247+
rabbitmq_connection_string: "rabbitmq_connection_string".to_string(),
248+
rabbitmq_exchange_name: "rabbitmq_exchange_name".to_string(),
249+
lsps2_service_config: Some(LSPS2ServiceConfig {
250+
require_token: None,
251+
advertise_service: false,
252+
channel_opening_fee_ppm: 1000,
253+
channel_over_provisioning_ppm: 500000,
254+
min_channel_opening_fee_msat: 10000000,
255+
min_channel_lifetime: 4320,
256+
max_client_to_self_delay: 1440,
257+
min_payment_size_msat: 10000000,
258+
max_payment_size_msat: 25000000000,
259+
}),
260+
};
261+
262+
assert_eq!(config.listening_addr, expected.listening_addr);
263+
assert_eq!(config.network, expected.network);
264+
assert_eq!(config.rest_service_addr, expected.rest_service_addr);
265+
assert_eq!(config.storage_dir_path, expected.storage_dir_path);
266+
assert_eq!(config.bitcoind_rpc_addr, expected.bitcoind_rpc_addr);
267+
assert_eq!(config.bitcoind_rpc_user, expected.bitcoind_rpc_user);
268+
assert_eq!(config.bitcoind_rpc_password, expected.bitcoind_rpc_password);
269+
assert_eq!(config.rabbitmq_connection_string, expected.rabbitmq_connection_string);
270+
assert_eq!(config.rabbitmq_exchange_name, expected.rabbitmq_exchange_name);
271+
#[cfg(feature = "experimental-lsps2-support")]
272+
assert_eq!(config.lsps2_service_config.is_some(), expected.lsps2_service_config.is_some());
181273
}
182274
}

0 commit comments

Comments
 (0)