Skip to content

Commit 8bb6614

Browse files
authored
Merge pull request #1878 from dunxen/2022-11-config-minfinalcltvexpiry
Allow configurable `min_final_cltv_expiry_delta`
2 parents 45a6f33 + 5b53670 commit 8bb6614

File tree

14 files changed

+435
-134
lines changed

14 files changed

+435
-134
lines changed

fuzz/src/chanmon_consistency.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ fn get_payment_secret_hash(dest: &ChanMan, payment_id: &mut u8) -> Option<(Payme
340340
let mut payment_hash;
341341
for _ in 0..256 {
342342
payment_hash = PaymentHash(Sha256::hash(&[*payment_id; 1]).into_inner());
343-
if let Ok(payment_secret) = dest.create_inbound_payment_for_hash(payment_hash, None, 3600) {
343+
if let Ok(payment_secret) = dest.create_inbound_payment_for_hash(payment_hash, None, 3600, None) {
344344
return Some((payment_secret, payment_hash));
345345
}
346346
*payment_id = payment_id.wrapping_add(1);

fuzz/src/full_stack.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
605605
let payment_hash = PaymentHash(Sha256::from_engine(sha).into_inner());
606606
// Note that this may fail - our hashes may collide and we'll end up trying to
607607
// double-register the same payment_hash.
608-
let _ = channelmanager.create_inbound_payment_for_hash(payment_hash, None, 1);
608+
let _ = channelmanager.create_inbound_payment_for_hash(payment_hash, None, 1, None);
609609
},
610610
9 => {
611611
for payment in payments_received.drain(..) {

lightning-invoice/src/de.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use secp256k1;
2222
use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
2323
use secp256k1::PublicKey;
2424

25-
use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiry, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
25+
use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiryDelta, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
2626
SemanticError, PrivateRoute, ParseError, ParseOrSemanticError, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawInvoice,
2727
constants, SignedRawInvoice, RawDataPart, InvoiceFeatures};
2828

@@ -451,8 +451,8 @@ impl FromBase32 for TaggedField {
451451
Ok(TaggedField::DescriptionHash(Sha256::from_base32(field_data)?)),
452452
constants::TAG_EXPIRY_TIME =>
453453
Ok(TaggedField::ExpiryTime(ExpiryTime::from_base32(field_data)?)),
454-
constants::TAG_MIN_FINAL_CLTV_EXPIRY =>
455-
Ok(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry::from_base32(field_data)?)),
454+
constants::TAG_MIN_FINAL_CLTV_EXPIRY_DELTA =>
455+
Ok(TaggedField::MinFinalCltvExpiryDelta(MinFinalCltvExpiryDelta::from_base32(field_data)?)),
456456
constants::TAG_FALLBACK =>
457457
Ok(TaggedField::Fallback(Fallback::from_base32(field_data)?)),
458458
constants::TAG_PRIVATE_ROUTE =>
@@ -523,13 +523,13 @@ impl FromBase32 for ExpiryTime {
523523
}
524524
}
525525

526-
impl FromBase32 for MinFinalCltvExpiry {
526+
impl FromBase32 for MinFinalCltvExpiryDelta {
527527
type Err = ParseError;
528528

529-
fn from_base32(field_data: &[u5]) -> Result<MinFinalCltvExpiry, ParseError> {
529+
fn from_base32(field_data: &[u5]) -> Result<MinFinalCltvExpiryDelta, ParseError> {
530530
let expiry = parse_int_be::<u64, u5>(field_data, 32);
531531
if let Some(expiry) = expiry {
532-
Ok(MinFinalCltvExpiry(expiry))
532+
Ok(MinFinalCltvExpiryDelta(expiry))
533533
} else {
534534
Err(ParseError::IntegerOverflowError)
535535
}
@@ -840,14 +840,14 @@ mod test {
840840
}
841841

842842
#[test]
843-
fn test_parse_min_final_cltv_expiry() {
844-
use crate::MinFinalCltvExpiry;
843+
fn test_parse_min_final_cltv_expiry_delta() {
844+
use crate::MinFinalCltvExpiryDelta;
845845
use bech32::FromBase32;
846846

847847
let input = from_bech32("pr".as_bytes());
848-
let expected = Ok(MinFinalCltvExpiry(35));
848+
let expected = Ok(MinFinalCltvExpiryDelta(35));
849849

850-
assert_eq!(MinFinalCltvExpiry::from_base32(&input), expected);
850+
assert_eq!(MinFinalCltvExpiryDelta::from_base32(&input), expected);
851851
}
852852

853853
#[test]

lightning-invoice/src/lib.rs

+30-23
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,11 @@ pub const DEFAULT_EXPIRY_TIME: u64 = 3600;
154154
/// Default minimum final CLTV expiry as defined by [BOLT 11].
155155
///
156156
/// Note that this is *not* the same value as rust-lightning's minimum CLTV expiry, which is
157-
/// provided in [`MIN_FINAL_CLTV_EXPIRY`].
157+
/// provided in [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
158158
///
159159
/// [BOLT 11]: https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
160-
/// [`MIN_FINAL_CLTV_EXPIRY`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY
161-
pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY: u64 = 18;
160+
/// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
161+
pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA: u64 = 18;
162162

163163
/// Builder for `Invoice`s. It's the most convenient and advised way to use this library. It ensures
164164
/// that only a semantically and syntactically correct Invoice can be built using it.
@@ -199,7 +199,7 @@ pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY: u64 = 18;
199199
/// .payment_hash(payment_hash)
200200
/// .payment_secret(payment_secret)
201201
/// .current_timestamp()
202-
/// .min_final_cltv_expiry(144)
202+
/// .min_final_cltv_expiry_delta(144)
203203
/// .build_signed(|hash| {
204204
/// Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)
205205
/// })
@@ -410,7 +410,7 @@ pub enum TaggedField {
410410
PayeePubKey(PayeePubKey),
411411
DescriptionHash(Sha256),
412412
ExpiryTime(ExpiryTime),
413-
MinFinalCltvExpiry(MinFinalCltvExpiry),
413+
MinFinalCltvExpiryDelta(MinFinalCltvExpiryDelta),
414414
Fallback(Fallback),
415415
PrivateRoute(PrivateRoute),
416416
PaymentSecret(PaymentSecret),
@@ -438,9 +438,9 @@ pub struct PayeePubKey(pub PublicKey);
438438
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
439439
pub struct ExpiryTime(Duration);
440440

441-
/// `min_final_cltv_expiry` to use for the last HTLC in the route
441+
/// `min_final_cltv_expiry_delta` to use for the last HTLC in the route
442442
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
443-
pub struct MinFinalCltvExpiry(pub u64);
443+
pub struct MinFinalCltvExpiryDelta(pub u64);
444444

445445
// TODO: better types instead onf byte arrays
446446
/// Fallback address in case no LN payment is possible
@@ -475,7 +475,7 @@ pub mod constants {
475475
pub const TAG_PAYEE_PUB_KEY: u8 = 19;
476476
pub const TAG_DESCRIPTION_HASH: u8 = 23;
477477
pub const TAG_EXPIRY_TIME: u8 = 6;
478-
pub const TAG_MIN_FINAL_CLTV_EXPIRY: u8 = 24;
478+
pub const TAG_MIN_FINAL_CLTV_EXPIRY_DELTA: u8 = 24;
479479
pub const TAG_FALLBACK: u8 = 9;
480480
pub const TAG_PRIVATE_ROUTE: u8 = 3;
481481
pub const TAG_PAYMENT_SECRET: u8 = 16;
@@ -654,9 +654,9 @@ impl<D: tb::Bool, H: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, tb
654654
}
655655

656656
impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, T, tb::False, S> {
657-
/// Sets `min_final_cltv_expiry`.
658-
pub fn min_final_cltv_expiry(mut self, min_final_cltv_expiry: u64) -> InvoiceBuilder<D, H, T, tb::True, S> {
659-
self.tagged_fields.push(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry(min_final_cltv_expiry)));
657+
/// Sets `min_final_cltv_expiry_delta`.
658+
pub fn min_final_cltv_expiry_delta(mut self, min_final_cltv_expiry_delta: u64) -> InvoiceBuilder<D, H, T, tb::True, S> {
659+
self.tagged_fields.push(TaggedField::MinFinalCltvExpiryDelta(MinFinalCltvExpiryDelta(min_final_cltv_expiry_delta)));
660660
self.set_flags()
661661
}
662662
}
@@ -929,8 +929,8 @@ impl RawInvoice {
929929
find_extract!(self.known_tagged_fields(), TaggedField::ExpiryTime(ref x), x)
930930
}
931931

932-
pub fn min_final_cltv_expiry(&self) -> Option<&MinFinalCltvExpiry> {
933-
find_extract!(self.known_tagged_fields(), TaggedField::MinFinalCltvExpiry(ref x), x)
932+
pub fn min_final_cltv_expiry_delta(&self) -> Option<&MinFinalCltvExpiryDelta> {
933+
find_extract!(self.known_tagged_fields(), TaggedField::MinFinalCltvExpiryDelta(ref x), x)
934934
}
935935

936936
pub fn payment_secret(&self) -> Option<&PaymentSecret> {
@@ -1243,12 +1243,12 @@ impl Invoice {
12431243
.unwrap_or_else(|| Duration::new(u64::max_value(), 1_000_000_000 - 1)) < at_time
12441244
}
12451245

1246-
/// Returns the invoice's `min_final_cltv_expiry` time, if present, otherwise
1247-
/// [`DEFAULT_MIN_FINAL_CLTV_EXPIRY`].
1248-
pub fn min_final_cltv_expiry(&self) -> u64 {
1249-
self.signed_invoice.min_final_cltv_expiry()
1246+
/// Returns the invoice's `min_final_cltv_expiry_delta` time, if present, otherwise
1247+
/// [`DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA`].
1248+
pub fn min_final_cltv_expiry_delta(&self) -> u64 {
1249+
self.signed_invoice.min_final_cltv_expiry_delta()
12501250
.map(|x| x.0)
1251-
.unwrap_or(DEFAULT_MIN_FINAL_CLTV_EXPIRY)
1251+
.unwrap_or(DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA)
12521252
}
12531253

12541254
/// Returns a list of all fallback addresses
@@ -1301,7 +1301,7 @@ impl TaggedField {
13011301
TaggedField::PayeePubKey(_) => constants::TAG_PAYEE_PUB_KEY,
13021302
TaggedField::DescriptionHash(_) => constants::TAG_DESCRIPTION_HASH,
13031303
TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
1304-
TaggedField::MinFinalCltvExpiry(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY,
1304+
TaggedField::MinFinalCltvExpiryDelta(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY_DELTA,
13051305
TaggedField::Fallback(_) => constants::TAG_FALLBACK,
13061306
TaggedField::PrivateRoute(_) => constants::TAG_PRIVATE_ROUTE,
13071307
TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
@@ -1448,6 +1448,11 @@ pub enum CreationError {
14481448
///
14491449
/// [phantom invoices]: crate::utils::create_phantom_invoice
14501450
MissingRouteHints,
1451+
1452+
/// The provided `min_final_cltv_expiry_delta` was less than [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
1453+
///
1454+
/// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
1455+
MinFinalCltvExpiryDeltaTooShort,
14511456
}
14521457

14531458
impl Display for CreationError {
@@ -1458,6 +1463,8 @@ impl Display for CreationError {
14581463
CreationError::TimestampOutOfBounds => f.write_str("The Unix timestamp of the supplied date is less than zero or greater than 35-bits"),
14591464
CreationError::InvalidAmount => f.write_str("The supplied millisatoshi amount was greater than the total bitcoin supply"),
14601465
CreationError::MissingRouteHints => f.write_str("The invoice required route hints and they weren't provided"),
1466+
CreationError::MinFinalCltvExpiryDeltaTooShort => f.write_str(
1467+
"The supplied final CLTV expiry delta was less than LDK's `MIN_FINAL_CLTV_EXPIRY_DELTA`"),
14611468
}
14621469
}
14631470
}
@@ -1804,7 +1811,7 @@ mod test {
18041811
let builder = InvoiceBuilder::new(Currency::Bitcoin)
18051812
.payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
18061813
.duration_since_epoch(Duration::from_secs(1234567))
1807-
.min_final_cltv_expiry(144);
1814+
.min_final_cltv_expiry_delta(144);
18081815

18091816
let too_long_string = String::from_iter(
18101817
(0..1024).map(|_| '?')
@@ -1922,7 +1929,7 @@ mod test {
19221929
.duration_since_epoch(Duration::from_secs(1234567))
19231930
.payee_pub_key(public_key.clone())
19241931
.expiry_time(Duration::from_secs(54321))
1925-
.min_final_cltv_expiry(144)
1932+
.min_final_cltv_expiry_delta(144)
19261933
.fallback(Fallback::PubKeyHash([0;20]))
19271934
.private_route(route_1.clone())
19281935
.private_route(route_2.clone())
@@ -1948,7 +1955,7 @@ mod test {
19481955
);
19491956
assert_eq!(invoice.payee_pub_key(), Some(&public_key));
19501957
assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
1951-
assert_eq!(invoice.min_final_cltv_expiry(), 144);
1958+
assert_eq!(invoice.min_final_cltv_expiry_delta(), 144);
19521959
assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
19531960
assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]);
19541961
assert_eq!(
@@ -1989,7 +1996,7 @@ mod test {
19891996
.unwrap();
19901997
let invoice = Invoice::from_signed(signed_invoice).unwrap();
19911998

1992-
assert_eq!(invoice.min_final_cltv_expiry(), DEFAULT_MIN_FINAL_CLTV_EXPIRY);
1999+
assert_eq!(invoice.min_final_cltv_expiry_delta(), DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA);
19932000
assert_eq!(invoice.expiry_time(), Duration::from_secs(DEFAULT_EXPIRY_TIME));
19942001
assert!(!invoice.would_expire(Duration::from_secs(1234568)));
19952002
}

lightning-invoice/src/payment.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ where
431431
let route_params = RouteParameters {
432432
payment_params,
433433
final_value_msat: invoice.amount_milli_satoshis().or(amount_msats).unwrap(),
434-
final_cltv_expiry_delta: invoice.min_final_cltv_expiry() as u32,
434+
final_cltv_expiry_delta: invoice.min_final_cltv_expiry_delta() as u32,
435435
};
436436

437437
let send_payment = |route: &Route| {
@@ -764,7 +764,7 @@ mod tests {
764764
.payment_hash(payment_hash)
765765
.payment_secret(PaymentSecret([0; 32]))
766766
.duration_since_epoch(duration_since_epoch())
767-
.min_final_cltv_expiry(144)
767+
.min_final_cltv_expiry_delta(144)
768768
.amount_milli_satoshis(128)
769769
.build_signed(|hash| {
770770
Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)
@@ -790,7 +790,7 @@ mod tests {
790790
.payment_hash(payment_hash)
791791
.payment_secret(PaymentSecret([0; 32]))
792792
.duration_since_epoch(duration_since_epoch())
793-
.min_final_cltv_expiry(144)
793+
.min_final_cltv_expiry_delta(144)
794794
.build_signed(|hash| {
795795
Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)
796796
})
@@ -809,7 +809,7 @@ mod tests {
809809
.payment_hash(payment_hash)
810810
.payment_secret(PaymentSecret([0; 32]))
811811
.duration_since_epoch(duration)
812-
.min_final_cltv_expiry(144)
812+
.min_final_cltv_expiry_delta(144)
813813
.amount_milli_satoshis(128)
814814
.build_signed(|hash| {
815815
Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)
@@ -1665,7 +1665,7 @@ mod tests {
16651665
RouteParameters {
16661666
payment_params,
16671667
final_value_msat,
1668-
final_cltv_expiry_delta: invoice.min_final_cltv_expiry() as u32,
1668+
final_cltv_expiry_delta: invoice.min_final_cltv_expiry_delta() as u32,
16691669
}
16701670
}
16711671
}
@@ -2085,7 +2085,7 @@ mod tests {
20852085

20862086
assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
20872087
&nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::Bitcoin,
2088-
Some(100_010_000), "Invoice".to_string(), duration_since_epoch(), 3600).unwrap())
2088+
Some(100_010_000), "Invoice".to_string(), duration_since_epoch(), 3600, None).unwrap())
20892089
.is_ok());
20902090
let htlc_msgs = nodes[0].node.get_and_clear_pending_msg_events();
20912091
assert_eq!(htlc_msgs.len(), 2);
@@ -2130,7 +2130,7 @@ mod tests {
21302130

21312131
assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
21322132
&nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::Bitcoin,
2133-
Some(100_010_000), "Invoice".to_string(), duration_since_epoch(), 3600).unwrap())
2133+
Some(100_010_000), "Invoice".to_string(), duration_since_epoch(), 3600, None).unwrap())
21342134
.is_ok());
21352135
let htlc_msgs = nodes[0].node.get_and_clear_pending_msg_events();
21362136
assert_eq!(htlc_msgs.len(), 2);
@@ -2211,7 +2211,7 @@ mod tests {
22112211

22122212
assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
22132213
&nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::Bitcoin,
2214-
Some(100_010_000), "Invoice".to_string(), duration_since_epoch(), 3600).unwrap())
2214+
Some(100_010_000), "Invoice".to_string(), duration_since_epoch(), 3600, None).unwrap())
22152215
.is_ok());
22162216
let htlc_updates = SendEvent::from_node(&nodes[0]);
22172217
check_added_monitors!(nodes[0], 1);

lightning-invoice/src/ser.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use core::fmt::{Display, Formatter};
33
use bech32::{ToBase32, u5, WriteBase32, Base32Len};
44
use crate::prelude::*;
55

6-
use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiry, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
6+
use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiryDelta, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
77
PrivateRoute, Description, RawTaggedField, Currency, RawHrp, SiPrefix, constants, SignedRawInvoice, RawDataPart};
88

99
/// Converts a stream of bytes written to it to base32. On finalization the according padding will
@@ -313,13 +313,13 @@ impl Base32Len for ExpiryTime {
313313
}
314314
}
315315

316-
impl ToBase32 for MinFinalCltvExpiry {
316+
impl ToBase32 for MinFinalCltvExpiryDelta {
317317
fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
318318
writer.write(&encode_int_be_base32(self.0))
319319
}
320320
}
321321

322-
impl Base32Len for MinFinalCltvExpiry {
322+
impl Base32Len for MinFinalCltvExpiryDelta {
323323
fn base32_len(&self) -> usize {
324324
encoded_int_be_base32_size(self.0)
325325
}
@@ -434,8 +434,8 @@ impl ToBase32 for TaggedField {
434434
TaggedField::ExpiryTime(ref duration) => {
435435
write_tagged_field(writer, constants::TAG_EXPIRY_TIME, duration)
436436
},
437-
TaggedField::MinFinalCltvExpiry(ref expiry) => {
438-
write_tagged_field(writer, constants::TAG_MIN_FINAL_CLTV_EXPIRY, expiry)
437+
TaggedField::MinFinalCltvExpiryDelta(ref expiry) => {
438+
write_tagged_field(writer, constants::TAG_MIN_FINAL_CLTV_EXPIRY_DELTA, expiry)
439439
},
440440
TaggedField::Fallback(ref fallback_address) => {
441441
write_tagged_field(writer, constants::TAG_FALLBACK, fallback_address)

0 commit comments

Comments
 (0)