Skip to content

Commit 162754d

Browse files
committed
f allow explicit min of 21 blocks for delta in invoice
1 parent 5ef5e3d commit 162754d

File tree

1 file changed

+60
-3
lines changed

1 file changed

+60
-3
lines changed

lightning-invoice/src/utils.rs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ use core::time::Duration;
4242
/// `invoice_expiry_delta_secs` describes the number of seconds that the invoice is valid for
4343
/// in excess of the current time.
4444
///
45+
/// You can specify a custom `min_final_cltv_expiry_delta`, or let LDK default it to
46+
/// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]. The provided expiry must be at least [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
47+
/// Note that LDK will add a buffer of 3 blocks to the delta to allow for up to a few new block
48+
/// confirmations during routing.
49+
///
4550
/// Note that the provided `keys_manager`'s `NodeSigner` implementation must support phantom
4651
/// invoices in its `sign_invoice` implementation ([`PhantomKeysManager`] satisfies this
4752
/// requirement).
@@ -51,6 +56,7 @@ use core::time::Duration;
5156
/// [`ChannelManager::create_inbound_payment`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment
5257
/// [`ChannelManager::create_inbound_payment_for_hash`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash
5358
/// [`PhantomRouteHints::channels`]: lightning::ln::channelmanager::PhantomRouteHints::channels
59+
/// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
5460
pub fn create_phantom_invoice<ES: Deref, NS: Deref, L: Deref>(
5561
amt_msat: Option<u64>, payment_hash: Option<PaymentHash>, description: String,
5662
invoice_expiry_delta_secs: u32, phantom_route_hints: Vec<PhantomRouteHints>, entropy_source: ES,
@@ -137,7 +143,7 @@ where
137143
));
138144
}
139145

140-
if min_final_cltv_expiry_delta.is_some() && min_final_cltv_expiry_delta.unwrap() < MIN_FINAL_CLTV_EXPIRY_DELTA {
146+
if min_final_cltv_expiry_delta.is_some() && min_final_cltv_expiry_delta.unwrap() + 3 < MIN_FINAL_CLTV_EXPIRY_DELTA {
141147
return Err(SignOrCreationError::CreationError(CreationError::MinFinalCltvExpiryDeltaTooShort));
142148
}
143149

@@ -245,6 +251,8 @@ where
245251
///
246252
/// You can specify a custom `min_final_cltv_expiry_delta`, or let LDK default it to
247253
/// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]. The provided expiry must be at least [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
254+
/// Note that LDK will add a buffer of 3 blocks to the delta to allow for up to a few new block
255+
/// confirmations during routing.
248256
///
249257
/// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
250258
pub fn create_invoice_from_channelmanager<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>(
@@ -281,6 +289,13 @@ where
281289
///
282290
/// `invoice_expiry_delta_secs` describes the number of seconds that the invoice is valid for
283291
/// in excess of the current time.
292+
///
293+
/// You can specify a custom `min_final_cltv_expiry_delta`, or let LDK default it to
294+
/// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]. The provided expiry must be at least [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
295+
/// Note that LDK will add a buffer of 3 blocks to the delta to allow for up to a few new block
296+
/// confirmations during routing.
297+
///
298+
/// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
284299
pub fn create_invoice_from_channelmanager_with_description_hash<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>(
285300
channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>, node_signer: NS, logger: L,
286301
network: Currency, amt_msat: Option<u64>, description_hash: Sha256,
@@ -375,7 +390,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T: Der
375390
R::Target: Router,
376391
L::Target: Logger,
377392
{
378-
if min_final_cltv_expiry_delta.is_some() && min_final_cltv_expiry_delta.unwrap() < MIN_FINAL_CLTV_EXPIRY_DELTA {
393+
if min_final_cltv_expiry_delta.is_some() && min_final_cltv_expiry_delta.unwrap().saturating_add(3) < MIN_FINAL_CLTV_EXPIRY_DELTA {
379394
return Err(SignOrCreationError::CreationError(CreationError::MinFinalCltvExpiryDeltaTooShort));
380395
}
381396

@@ -440,6 +455,10 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
440455
let our_node_pubkey = channelmanager.get_our_node_id();
441456
let channels = channelmanager.list_channels();
442457

458+
if min_final_cltv_expiry_delta.is_some() && min_final_cltv_expiry_delta.unwrap().saturating_add(3) < MIN_FINAL_CLTV_EXPIRY_DELTA {
459+
return Err(SignOrCreationError::CreationError(CreationError::MinFinalCltvExpiryDeltaTooShort));
460+
}
461+
443462
log_trace!(logger, "Creating invoice with payment hash {}", log_bytes!(payment_hash.0));
444463

445464
let invoice = match description {
@@ -742,6 +761,44 @@ mod test {
742761
assert_eq!(events.len(), 2);
743762
}
744763

764+
fn do_create_invoice_min_final_cltv_delta(with_custom_delta: bool) {
765+
let chanmon_cfgs = create_chanmon_cfgs(2);
766+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
767+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
768+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
769+
let custom_min_final_cltv_expiry_delta = Some(50);
770+
771+
let invoice = crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch(
772+
&nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::BitcoinTestnet,
773+
Some(10_000), "".into(), Duration::from_secs(1234567), 3600,
774+
if with_custom_delta { custom_min_final_cltv_expiry_delta } else { None },
775+
).unwrap();
776+
assert_eq!(invoice.min_final_cltv_expiry_delta(), if with_custom_delta {
777+
custom_min_final_cltv_expiry_delta.unwrap() + 3 /* Buffer */} else { MIN_FINAL_CLTV_EXPIRY_DELTA } as u64);
778+
}
779+
780+
#[test]
781+
fn test_create_invoice_custom_min_final_cltv_delta() {
782+
do_create_invoice_min_final_cltv_delta(true);
783+
do_create_invoice_min_final_cltv_delta(false);
784+
}
785+
786+
#[test]
787+
fn create_invoice_min_final_cltv_delta_equals_htlc_fail_buffer() {
788+
let chanmon_cfgs = create_chanmon_cfgs(2);
789+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
790+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
791+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
792+
let custom_min_final_cltv_expiry_delta = Some(21);
793+
794+
let invoice = crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch(
795+
&nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::BitcoinTestnet,
796+
Some(10_000), "".into(), Duration::from_secs(1234567), 3600,
797+
custom_min_final_cltv_expiry_delta,
798+
).unwrap();
799+
assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
800+
}
801+
745802
#[test]
746803
fn test_create_invoice_with_description_hash() {
747804
let chanmon_cfgs = create_chanmon_cfgs(2);
@@ -1542,7 +1599,7 @@ mod test {
15421599
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
15431600
let result = crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch(
15441601
&nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::BitcoinTestnet,
1545-
Some(10_000), "Some description".into(), Duration::from_secs(1234567), 3600, Some(MIN_FINAL_CLTV_EXPIRY_DELTA - 1),
1602+
Some(10_000), "Some description".into(), Duration::from_secs(1234567), 3600, Some(MIN_FINAL_CLTV_EXPIRY_DELTA - 4),
15461603
);
15471604
match result {
15481605
Err(SignOrCreationError::CreationError(CreationError::MinFinalCltvExpiryDeltaTooShort)) => {},

0 commit comments

Comments
 (0)