Skip to content

Allow configurable min_final_cltv_expiry_delta #1878

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fuzz/src/chanmon_consistency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ fn get_payment_secret_hash(dest: &ChanMan, payment_id: &mut u8) -> Option<(Payme
let mut payment_hash;
for _ in 0..256 {
payment_hash = PaymentHash(Sha256::hash(&[*payment_id; 1]).into_inner());
if let Ok(payment_secret) = dest.create_inbound_payment_for_hash(payment_hash, None, 3600) {
if let Ok(payment_secret) = dest.create_inbound_payment_for_hash(payment_hash, None, 3600, None) {
return Some((payment_secret, payment_hash));
}
*payment_id = payment_id.wrapping_add(1);
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/full_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
let payment_hash = PaymentHash(Sha256::from_engine(sha).into_inner());
// Note that this may fail - our hashes may collide and we'll end up trying to
// double-register the same payment_hash.
let _ = channelmanager.create_inbound_payment_for_hash(payment_hash, None, 1);
let _ = channelmanager.create_inbound_payment_for_hash(payment_hash, None, 1, None);
},
9 => {
for payment in payments_received.drain(..) {
Expand Down
20 changes: 10 additions & 10 deletions lightning-invoice/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use secp256k1;
use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
use secp256k1::PublicKey;

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

Expand Down Expand Up @@ -451,8 +451,8 @@ impl FromBase32 for TaggedField {
Ok(TaggedField::DescriptionHash(Sha256::from_base32(field_data)?)),
constants::TAG_EXPIRY_TIME =>
Ok(TaggedField::ExpiryTime(ExpiryTime::from_base32(field_data)?)),
constants::TAG_MIN_FINAL_CLTV_EXPIRY =>
Ok(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry::from_base32(field_data)?)),
constants::TAG_MIN_FINAL_CLTV_EXPIRY_DELTA =>
Ok(TaggedField::MinFinalCltvExpiryDelta(MinFinalCltvExpiryDelta::from_base32(field_data)?)),
constants::TAG_FALLBACK =>
Ok(TaggedField::Fallback(Fallback::from_base32(field_data)?)),
constants::TAG_PRIVATE_ROUTE =>
Expand Down Expand Up @@ -523,13 +523,13 @@ impl FromBase32 for ExpiryTime {
}
}

impl FromBase32 for MinFinalCltvExpiry {
impl FromBase32 for MinFinalCltvExpiryDelta {
type Err = ParseError;

fn from_base32(field_data: &[u5]) -> Result<MinFinalCltvExpiry, ParseError> {
fn from_base32(field_data: &[u5]) -> Result<MinFinalCltvExpiryDelta, ParseError> {
let expiry = parse_int_be::<u64, u5>(field_data, 32);
if let Some(expiry) = expiry {
Ok(MinFinalCltvExpiry(expiry))
Ok(MinFinalCltvExpiryDelta(expiry))
} else {
Err(ParseError::IntegerOverflowError)
}
Expand Down Expand Up @@ -840,14 +840,14 @@ mod test {
}

#[test]
fn test_parse_min_final_cltv_expiry() {
use crate::MinFinalCltvExpiry;
fn test_parse_min_final_cltv_expiry_delta() {
use crate::MinFinalCltvExpiryDelta;
use bech32::FromBase32;

let input = from_bech32("pr".as_bytes());
let expected = Ok(MinFinalCltvExpiry(35));
let expected = Ok(MinFinalCltvExpiryDelta(35));

assert_eq!(MinFinalCltvExpiry::from_base32(&input), expected);
assert_eq!(MinFinalCltvExpiryDelta::from_base32(&input), expected);
}

#[test]
Expand Down
53 changes: 30 additions & 23 deletions lightning-invoice/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,11 @@ pub const DEFAULT_EXPIRY_TIME: u64 = 3600;
/// Default minimum final CLTV expiry as defined by [BOLT 11].
///
/// Note that this is *not* the same value as rust-lightning's minimum CLTV expiry, which is
/// provided in [`MIN_FINAL_CLTV_EXPIRY`].
/// provided in [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
///
/// [BOLT 11]: https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
/// [`MIN_FINAL_CLTV_EXPIRY`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY
pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY: u64 = 18;
/// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA: u64 = 18;

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

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

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

impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, T, tb::False, S> {
/// Sets `min_final_cltv_expiry`.
pub fn min_final_cltv_expiry(mut self, min_final_cltv_expiry: u64) -> InvoiceBuilder<D, H, T, tb::True, S> {
self.tagged_fields.push(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry(min_final_cltv_expiry)));
/// Sets `min_final_cltv_expiry_delta`.
pub fn min_final_cltv_expiry_delta(mut self, min_final_cltv_expiry_delta: u64) -> InvoiceBuilder<D, H, T, tb::True, S> {
self.tagged_fields.push(TaggedField::MinFinalCltvExpiryDelta(MinFinalCltvExpiryDelta(min_final_cltv_expiry_delta)));
self.set_flags()
}
}
Expand Down Expand Up @@ -929,8 +929,8 @@ impl RawInvoice {
find_extract!(self.known_tagged_fields(), TaggedField::ExpiryTime(ref x), x)
}

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

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

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

/// Returns a list of all fallback addresses
Expand Down Expand Up @@ -1301,7 +1301,7 @@ impl TaggedField {
TaggedField::PayeePubKey(_) => constants::TAG_PAYEE_PUB_KEY,
TaggedField::DescriptionHash(_) => constants::TAG_DESCRIPTION_HASH,
TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
TaggedField::MinFinalCltvExpiry(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY,
TaggedField::MinFinalCltvExpiryDelta(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY_DELTA,
TaggedField::Fallback(_) => constants::TAG_FALLBACK,
TaggedField::PrivateRoute(_) => constants::TAG_PRIVATE_ROUTE,
TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
Expand Down Expand Up @@ -1448,6 +1448,11 @@ pub enum CreationError {
///
/// [phantom invoices]: crate::utils::create_phantom_invoice
MissingRouteHints,

/// The provided `min_final_cltv_expiry_delta` was less than [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
///
/// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
MinFinalCltvExpiryDeltaTooShort,
}

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

let too_long_string = String::from_iter(
(0..1024).map(|_| '?')
Expand Down Expand Up @@ -1922,7 +1929,7 @@ mod test {
.duration_since_epoch(Duration::from_secs(1234567))
.payee_pub_key(public_key.clone())
.expiry_time(Duration::from_secs(54321))
.min_final_cltv_expiry(144)
.min_final_cltv_expiry_delta(144)
.fallback(Fallback::PubKeyHash([0;20]))
.private_route(route_1.clone())
.private_route(route_2.clone())
Expand All @@ -1948,7 +1955,7 @@ mod test {
);
assert_eq!(invoice.payee_pub_key(), Some(&public_key));
assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
assert_eq!(invoice.min_final_cltv_expiry(), 144);
assert_eq!(invoice.min_final_cltv_expiry_delta(), 144);
assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]);
assert_eq!(
Expand Down Expand Up @@ -1989,7 +1996,7 @@ mod test {
.unwrap();
let invoice = Invoice::from_signed(signed_invoice).unwrap();

assert_eq!(invoice.min_final_cltv_expiry(), DEFAULT_MIN_FINAL_CLTV_EXPIRY);
assert_eq!(invoice.min_final_cltv_expiry_delta(), DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA);
assert_eq!(invoice.expiry_time(), Duration::from_secs(DEFAULT_EXPIRY_TIME));
assert!(!invoice.would_expire(Duration::from_secs(1234568)));
}
Expand Down
16 changes: 8 additions & 8 deletions lightning-invoice/src/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ where
let route_params = RouteParameters {
payment_params,
final_value_msat: invoice.amount_milli_satoshis().or(amount_msats).unwrap(),
final_cltv_expiry_delta: invoice.min_final_cltv_expiry() as u32,
final_cltv_expiry_delta: invoice.min_final_cltv_expiry_delta() as u32,
};

let send_payment = |route: &Route| {
Expand Down Expand Up @@ -764,7 +764,7 @@ mod tests {
.payment_hash(payment_hash)
.payment_secret(PaymentSecret([0; 32]))
.duration_since_epoch(duration_since_epoch())
.min_final_cltv_expiry(144)
.min_final_cltv_expiry_delta(144)
.amount_milli_satoshis(128)
.build_signed(|hash| {
Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)
Expand All @@ -790,7 +790,7 @@ mod tests {
.payment_hash(payment_hash)
.payment_secret(PaymentSecret([0; 32]))
.duration_since_epoch(duration_since_epoch())
.min_final_cltv_expiry(144)
.min_final_cltv_expiry_delta(144)
.build_signed(|hash| {
Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)
})
Expand All @@ -809,7 +809,7 @@ mod tests {
.payment_hash(payment_hash)
.payment_secret(PaymentSecret([0; 32]))
.duration_since_epoch(duration)
.min_final_cltv_expiry(144)
.min_final_cltv_expiry_delta(144)
.amount_milli_satoshis(128)
.build_signed(|hash| {
Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)
Expand Down Expand Up @@ -1665,7 +1665,7 @@ mod tests {
RouteParameters {
payment_params,
final_value_msat,
final_cltv_expiry_delta: invoice.min_final_cltv_expiry() as u32,
final_cltv_expiry_delta: invoice.min_final_cltv_expiry_delta() as u32,
}
}
}
Expand Down Expand Up @@ -2085,7 +2085,7 @@ mod tests {

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

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

assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
&nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::Bitcoin,
Some(100_010_000), "Invoice".to_string(), duration_since_epoch(), 3600).unwrap())
Some(100_010_000), "Invoice".to_string(), duration_since_epoch(), 3600, None).unwrap())
.is_ok());
let htlc_updates = SendEvent::from_node(&nodes[0]);
check_added_monitors!(nodes[0], 1);
Expand Down
10 changes: 5 additions & 5 deletions lightning-invoice/src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use core::fmt::{Display, Formatter};
use bech32::{ToBase32, u5, WriteBase32, Base32Len};
use crate::prelude::*;

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

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

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

impl Base32Len for MinFinalCltvExpiry {
impl Base32Len for MinFinalCltvExpiryDelta {
fn base32_len(&self) -> usize {
encoded_int_be_base32_size(self.0)
}
Expand Down Expand Up @@ -434,8 +434,8 @@ impl ToBase32 for TaggedField {
TaggedField::ExpiryTime(ref duration) => {
write_tagged_field(writer, constants::TAG_EXPIRY_TIME, duration)
},
TaggedField::MinFinalCltvExpiry(ref expiry) => {
write_tagged_field(writer, constants::TAG_MIN_FINAL_CLTV_EXPIRY, expiry)
TaggedField::MinFinalCltvExpiryDelta(ref expiry) => {
write_tagged_field(writer, constants::TAG_MIN_FINAL_CLTV_EXPIRY_DELTA, expiry)
},
TaggedField::Fallback(ref fallback_address) => {
write_tagged_field(writer, constants::TAG_FALLBACK, fallback_address)
Expand Down
Loading