Skip to content

Commit 06509b7

Browse files
committed
Carry a configured fee claim into register_node
Bump the rust-lightning pin to 9b5f40f00, which brings the fee-claim wire field, the LSP-side verifier, and the new register_node parameter. That bump forces three coupled changes, so they land together. Client side: LSPS4ClientConfig and the internal LSPS4Client now hold an optional fee_claim, set_liquidity_source_lsps4 takes it as a third argument, and lsps4_register_node relays it on every registration. mdkd is the only caller, so widening the signature is contained. The value is opaque here, a lowercase-hex signed grant that only the LSP decodes. Service side: the bumped LdkLSPS4ServiceConfig grew an issuer_pubkeys field with no Default, so the struct literal no longer compiles without naming it. LSPS4ServiceConfig surfaces it; an empty Vec (the inert default for a node acting only as a client) honours no claim and keeps every peer on the standard policy. With no claim configured the request carries None, the LSP resolves the standard policy, and behaviour is unchanged.
1 parent a3226be commit 06509b7

3 files changed

Lines changed: 66 additions & 24 deletions

File tree

Cargo.toml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,17 @@ default = []
4242
# lightning-macros = { version = "0.2.0" }
4343

4444
# Branch: https://github.com/moneydevkit/rust-lightning/tree/lsp-0.2.0_accept-underpaying-htlcs_with_timing_logs
45-
lightning = { git = "https://github.com/moneydevkit/rust-lightning", rev = "f56f47fe6c874771cd079faaacf96c42b32fbe72", features = ["std"] }
46-
lightning-types = { git = "https://github.com/moneydevkit/rust-lightning", rev = "f56f47fe6c874771cd079faaacf96c42b32fbe72" }
47-
lightning-invoice = { git = "https://github.com/moneydevkit/rust-lightning", rev = "f56f47fe6c874771cd079faaacf96c42b32fbe72", features = ["std"] }
48-
lightning-net-tokio = { git = "https://github.com/moneydevkit/rust-lightning", rev = "f56f47fe6c874771cd079faaacf96c42b32fbe72", features = ["socks"] }
49-
lightning-persister = { git = "https://github.com/moneydevkit/rust-lightning", rev = "f56f47fe6c874771cd079faaacf96c42b32fbe72", features = ["tokio"] }
50-
lightning-background-processor = { git = "https://github.com/moneydevkit/rust-lightning", rev = "f56f47fe6c874771cd079faaacf96c42b32fbe72" }
51-
lightning-rapid-gossip-sync = { git = "https://github.com/moneydevkit/rust-lightning", rev = "f56f47fe6c874771cd079faaacf96c42b32fbe72" }
52-
lightning-block-sync = { git = "https://github.com/moneydevkit/rust-lightning", rev = "f56f47fe6c874771cd079faaacf96c42b32fbe72", features = ["rest-client", "rpc-client", "tokio"] }
53-
lightning-transaction-sync = { git = "https://github.com/moneydevkit/rust-lightning", rev = "f56f47fe6c874771cd079faaacf96c42b32fbe72", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
54-
lightning-liquidity = { git = "https://github.com/moneydevkit/rust-lightning", rev = "f56f47fe6c874771cd079faaacf96c42b32fbe72", features = ["std"] }
55-
lightning-macros = { git = "https://github.com/moneydevkit/rust-lightning", rev = "f56f47fe6c874771cd079faaacf96c42b32fbe72" }
45+
lightning = { git = "https://github.com/moneydevkit/rust-lightning", rev = "9b5f40f00a623ff5e1cbe2540d79c3665589be6e", features = ["std"] }
46+
lightning-types = { git = "https://github.com/moneydevkit/rust-lightning", rev = "9b5f40f00a623ff5e1cbe2540d79c3665589be6e" }
47+
lightning-invoice = { git = "https://github.com/moneydevkit/rust-lightning", rev = "9b5f40f00a623ff5e1cbe2540d79c3665589be6e", features = ["std"] }
48+
lightning-net-tokio = { git = "https://github.com/moneydevkit/rust-lightning", rev = "9b5f40f00a623ff5e1cbe2540d79c3665589be6e", features = ["socks"] }
49+
lightning-persister = { git = "https://github.com/moneydevkit/rust-lightning", rev = "9b5f40f00a623ff5e1cbe2540d79c3665589be6e", features = ["tokio"] }
50+
lightning-background-processor = { git = "https://github.com/moneydevkit/rust-lightning", rev = "9b5f40f00a623ff5e1cbe2540d79c3665589be6e" }
51+
lightning-rapid-gossip-sync = { git = "https://github.com/moneydevkit/rust-lightning", rev = "9b5f40f00a623ff5e1cbe2540d79c3665589be6e" }
52+
lightning-block-sync = { git = "https://github.com/moneydevkit/rust-lightning", rev = "9b5f40f00a623ff5e1cbe2540d79c3665589be6e", features = ["rest-client", "rpc-client", "tokio"] }
53+
lightning-transaction-sync = { git = "https://github.com/moneydevkit/rust-lightning", rev = "9b5f40f00a623ff5e1cbe2540d79c3665589be6e", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
54+
lightning-liquidity = { git = "https://github.com/moneydevkit/rust-lightning", rev = "9b5f40f00a623ff5e1cbe2540d79c3665589be6e", features = ["std"] }
55+
lightning-macros = { git = "https://github.com/moneydevkit/rust-lightning", rev = "9b5f40f00a623ff5e1cbe2540d79c3665589be6e" }
5656

5757
#lightning = { path = "../rust-lightning/lightning", features = ["std"] }
5858
#lightning-types = { path = "../rust-lightning/lightning-types" }
@@ -101,7 +101,7 @@ winapi = { version = "0.3", features = ["winbase"] }
101101
[dev-dependencies]
102102
# lightning = { version = "0.2.0", features = ["std", "_test_utils"] }
103103
# Branch: https://github.com/moneydevkit/rust-lightning/commits/lsp-0.2.0_accept-underpaying-htlcs_with_timing_logs
104-
lightning = { git = "https://github.com/moneydevkit/rust-lightning", rev = "f56f47fe6c874771cd079faaacf96c42b32fbe72", features = ["std", "_test_utils"] }
104+
lightning = { git = "https://github.com/moneydevkit/rust-lightning", rev = "9b5f40f00a623ff5e1cbe2540d79c3665589be6e", features = ["std", "_test_utils"] }
105105
#lightning = { path = "../rust-lightning/lightning", features = ["std", "_test_utils"] }
106106
proptest = "1.0.0"
107107
regex = "1.5.6"

src/builder.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -489,14 +489,14 @@ impl NodeBuilder {
489489
///
490490
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
491491
pub fn set_liquidity_source_lsps4(
492-
&mut self, node_id: PublicKey, address: SocketAddress,
492+
&mut self, node_id: PublicKey, address: SocketAddress, fee_claim: Option<String>,
493493
) -> &mut Self {
494494
// Mark the LSP as trusted for 0conf
495495
self.config.trusted_peers_0conf.push(node_id.clone());
496496

497497
let liquidity_source_config =
498498
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
499-
let lsps4_client_config = LSPS4ClientConfig { node_id, address };
499+
let lsps4_client_config = LSPS4ClientConfig { node_id, address, fee_claim };
500500
liquidity_source_config.lsps4_client = Some(lsps4_client_config);
501501
self
502502
}
@@ -1873,7 +1873,11 @@ fn build_with_store_internal(
18731873
});
18741874

18751875
lsc.lsps4_client.as_ref().map(|config| {
1876-
liquidity_source_builder.lsps4_client(config.node_id, config.address.clone())
1876+
liquidity_source_builder.lsps4_client(
1877+
config.node_id,
1878+
config.address.clone(),
1879+
config.fee_claim.clone(),
1880+
)
18771881
});
18781882

18791883
let promise_secret = {
@@ -2152,7 +2156,34 @@ pub(crate) fn sanitize_alias(alias_str: &str) -> Result<NodeAlias, BuildError> {
21522156

21532157
#[cfg(test)]
21542158
mod tests {
2155-
use super::{sanitize_alias, BuildError, NodeAlias};
2159+
use super::{sanitize_alias, BuildError, NodeAlias, NodeBuilder};
2160+
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
2161+
use lightning::ln::msgs::SocketAddress;
2162+
2163+
fn dummy_lsp() -> (PublicKey, SocketAddress) {
2164+
let node_id =
2165+
PublicKey::from_secret_key(&Secp256k1::new(), &SecretKey::from_slice(&[1u8; 32]).unwrap());
2166+
let address = SocketAddress::TcpIpV4 { addr: [127, 0, 0, 1], port: 9735 };
2167+
(node_id, address)
2168+
}
2169+
2170+
#[test]
2171+
fn lsps4_source_stores_the_fee_claim() {
2172+
let (node_id, address) = dummy_lsp();
2173+
let mut builder = NodeBuilder::new();
2174+
builder.set_liquidity_source_lsps4(node_id, address, Some("deadbeef".to_string()));
2175+
let config = builder.liquidity_source_config.unwrap().lsps4_client.unwrap();
2176+
assert_eq!(config.fee_claim, Some("deadbeef".to_string()));
2177+
}
2178+
2179+
#[test]
2180+
fn lsps4_source_without_a_claim_stores_none() {
2181+
let (node_id, address) = dummy_lsp();
2182+
let mut builder = NodeBuilder::new();
2183+
builder.set_liquidity_source_lsps4(node_id, address, None);
2184+
let config = builder.liquidity_source_config.unwrap().lsps4_client.unwrap();
2185+
assert_eq!(config.fee_claim, None);
2186+
}
21562187

21572188
#[test]
21582189
fn sanitize_empty_node_alias() {

src/liquidity.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::sync::{Arc, Mutex, RwLock};
1313
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
1414

1515
use bitcoin::hashes::{sha256, Hash};
16-
use bitcoin::secp256k1::{PublicKey, Secp256k1};
16+
use bitcoin::secp256k1::{PublicKey, Secp256k1, XOnlyPublicKey};
1717
use bitcoin::Transaction;
1818
use chrono::Utc;
1919
use lightning::events::HTLCHandlingFailureType;
@@ -155,6 +155,7 @@ struct LSPS4Client {
155155
lsp_node_id: PublicKey,
156156
lsp_address: SocketAddress,
157157
ldk_client_config: LdkLSPS4ClientConfig,
158+
fee_claim: Option<String>,
158159
pending_register_node_requests:
159160
Mutex<HashMap<LSPSRequestId, oneshot::Sender<LSPS4RegisterNodeResponse>>>,
160161
}
@@ -163,6 +164,9 @@ struct LSPS4Client {
163164
pub(crate) struct LSPS4ClientConfig {
164165
pub node_id: PublicKey,
165166
pub address: SocketAddress,
167+
/// Opaque lowercase-hex signed grant presented on `register_node`; the LSP verifies it against
168+
/// its configured issuer keys. `None` leaves the node on the standard fee policy.
169+
pub fee_claim: Option<String>,
166170
}
167171
struct LSPS4Service {
168172
service_config: LSPS4ServiceConfig,
@@ -189,6 +193,10 @@ pub struct LSPS4ServiceConfig {
189193
/// channels with the peer. The first entry applies when there are no channels, the second
190194
/// when there is already one, and so on. If empty, no tiering is applied.
191195
pub channel_size_tiers: Vec<u64>,
196+
/// X-only public keys whose signatures grant a non-standard fee policy. A `register_node`
197+
/// fee claim is honoured only if it verifies against one of these keys. Empty means no claim
198+
/// is ever honoured and every peer stays on the standard policy.
199+
pub issuer_pubkeys: Vec<XOnlyPublicKey>,
192200
}
193201

194202
pub(crate) struct LiquiditySourceBuilder<L: Deref>
@@ -284,14 +292,15 @@ where
284292
}
285293

286294
pub(crate) fn lsps4_client(
287-
&mut self, lsp_node_id: PublicKey, lsp_address: SocketAddress,
295+
&mut self, lsp_node_id: PublicKey, lsp_address: SocketAddress, fee_claim: Option<String>,
288296
) -> &mut Self {
289297
let ldk_client_config = LdkLSPS4ClientConfig {};
290298
let pending_register_node_requests = Mutex::new(HashMap::new());
291299
self.lsps4_client = Some(LSPS4Client {
292300
lsp_node_id,
293301
lsp_address,
294302
ldk_client_config,
303+
fee_claim,
295304
pending_register_node_requests,
296305
});
297306
self
@@ -306,12 +315,12 @@ where
306315
}
307316

308317
pub(crate) fn lsps4_service(&mut self, service_config: LSPS4ServiceConfig) -> &mut Self {
309-
let ldk_service_config =
310-
LdkLSPS4ServiceConfig {
311-
cltv_expiry_delta: LSPS2_CHANNEL_CLTV_EXPIRY_DELTA,
312-
forwarding_fee_proportional_millionths: service_config
318+
let ldk_service_config = LdkLSPS4ServiceConfig {
319+
cltv_expiry_delta: LSPS2_CHANNEL_CLTV_EXPIRY_DELTA,
320+
forwarding_fee_proportional_millionths: service_config
313321
.forwarding_fee_proportional_millionths,
314-
};
322+
issuer_pubkeys: service_config.issuer_pubkeys.clone(),
323+
};
315324
self.lsps4_service = Some(LSPS4Service { service_config, ldk_service_config });
316325
self
317326
}
@@ -1684,7 +1693,9 @@ where
16841693
{
16851694
let mut pending_register_node_requests_lock =
16861695
lsps4_client.pending_register_node_requests.lock().unwrap();
1687-
let request_id = client_handler.register_node(lsps4_client.lsp_node_id).unwrap();
1696+
let request_id = client_handler
1697+
.register_node(lsps4_client.lsp_node_id, lsps4_client.fee_claim.clone())
1698+
.unwrap();
16881699
pending_register_node_requests_lock.insert(request_id, register_node_sender);
16891700
}
16901701
log_info!(self.logger, "TIMING: lsps4_register_node() sent request, waiting for response...");

0 commit comments

Comments
 (0)