Skip to content

Commit ec774ff

Browse files
committed
lightning-invoice/utils: Actually add expiry to invoices
1 parent dc8479a commit ec774ff

File tree

2 files changed

+46
-18
lines changed

2 files changed

+46
-18
lines changed

lightning-invoice/src/payment.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,7 @@ mod tests {
15581558

15591559
assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
15601560
&nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string(),
1561-
duration_since_epoch()).unwrap())
1561+
duration_since_epoch(), 3600).unwrap())
15621562
.is_ok());
15631563
let htlc_msgs = nodes[0].node.get_and_clear_pending_msg_events();
15641564
assert_eq!(htlc_msgs.len(), 2);
@@ -1604,7 +1604,7 @@ mod tests {
16041604

16051605
assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
16061606
&nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string(),
1607-
duration_since_epoch()).unwrap())
1607+
duration_since_epoch(), 3600).unwrap())
16081608
.is_ok());
16091609
let htlc_msgs = nodes[0].node.get_and_clear_pending_msg_events();
16101610
assert_eq!(htlc_msgs.len(), 2);
@@ -1686,7 +1686,7 @@ mod tests {
16861686

16871687
assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
16881688
&nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string(),
1689-
duration_since_epoch()).unwrap())
1689+
duration_since_epoch(), 3600).unwrap())
16901690
.is_ok());
16911691
let htlc_updates = SendEvent::from_node(&nodes[0]);
16921692
check_added_monitors!(nodes[0], 1);

lightning-invoice/src/utils.rs

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Convenient utilities to create an invoice.
22
3-
use {CreationError, Currency, DEFAULT_EXPIRY_TIME, Invoice, InvoiceBuilder, SignOrCreationError};
3+
use {CreationError, Currency, Invoice, InvoiceBuilder, SignOrCreationError};
44
use payment::{Payer, Router};
55

66
use crate::{prelude::*, Description, InvoiceDescription, Sha256};
@@ -162,7 +162,8 @@ fn _create_phantom_invoice<Signer: Sign, K: Deref>(
162162
.current_timestamp()
163163
.payment_hash(Hash::from_slice(&payment_hash.0).unwrap())
164164
.payment_secret(payment_secret)
165-
.min_final_cltv_expiry(MIN_FINAL_CLTV_EXPIRY.into());
165+
.min_final_cltv_expiry(MIN_FINAL_CLTV_EXPIRY.into())
166+
.expiry_time(Duration::from_secs(invoice_expiry_delta_secs.into()));
166167
if let Some(amt) = amt_msat {
167168
invoice = invoice.amount_milli_satoshis(amt);
168169
}
@@ -212,9 +213,12 @@ fn _create_phantom_invoice<Signer: Sign, K: Deref>(
212213
/// method stores the invoice's payment secret and preimage in `ChannelManager`, so (a) the user
213214
/// doesn't have to store preimage/payment secret information and (b) `ChannelManager` can verify
214215
/// that the payment secret is valid when the invoice is paid.
216+
///
217+
/// `invoice_expiry_delta_secs` describes the number of seconds that the invoice is valid for
218+
/// in excess of the current time.
215219
pub fn create_invoice_from_channelmanager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
216220
channelmanager: &ChannelManager<Signer, M, T, K, F, L>, keys_manager: K, network: Currency,
217-
amt_msat: Option<u64>, description: String
221+
amt_msat: Option<u64>, description: String, invoice_expiry_delta_secs: u32
218222
) -> Result<Invoice, SignOrCreationError<()>>
219223
where
220224
M::Target: chain::Watch<Signer>,
@@ -227,7 +231,8 @@ where
227231
let duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)
228232
.expect("for the foreseeable future this shouldn't happen");
229233
create_invoice_from_channelmanager_and_duration_since_epoch(
230-
channelmanager, keys_manager, network, amt_msat, description, duration
234+
channelmanager, keys_manager, network, amt_msat,
235+
description, duration, invoice_expiry_delta_secs
231236
)
232237
}
233238

@@ -238,9 +243,12 @@ where
238243
/// doesn't have to store preimage/payment secret information and (b) `ChannelManager` can verify
239244
/// that the payment secret is valid when the invoice is paid.
240245
/// Use this variant if you want to pass the `description_hash` to the invoice.
246+
///
247+
/// `invoice_expiry_delta_secs` describes the number of seconds that the invoice is valid for
248+
/// in excess of the current time.
241249
pub fn create_invoice_from_channelmanager_with_description_hash<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
242250
channelmanager: &ChannelManager<Signer, M, T, K, F, L>, keys_manager: K, network: Currency,
243-
amt_msat: Option<u64>, description_hash: Sha256,
251+
amt_msat: Option<u64>, description_hash: Sha256, invoice_expiry_delta_secs: u32
244252
) -> Result<Invoice, SignOrCreationError<()>>
245253
where
246254
M::Target: chain::Watch<Signer>,
@@ -256,7 +264,8 @@ where
256264
.expect("for the foreseeable future this shouldn't happen");
257265

258266
create_invoice_from_channelmanager_with_description_hash_and_duration_since_epoch(
259-
channelmanager, keys_manager, network, amt_msat, description_hash, duration,
267+
channelmanager, keys_manager, network, amt_msat,
268+
description_hash, duration, invoice_expiry_delta_secs
260269
)
261270
}
262271

@@ -266,6 +275,7 @@ where
266275
pub fn create_invoice_from_channelmanager_with_description_hash_and_duration_since_epoch<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
267276
channelmanager: &ChannelManager<Signer, M, T, K, F, L>, keys_manager: K, network: Currency,
268277
amt_msat: Option<u64>, description_hash: Sha256, duration_since_epoch: Duration,
278+
invoice_expiry_delta_secs: u32
269279
) -> Result<Invoice, SignOrCreationError<()>>
270280
where
271281
M::Target: chain::Watch<Signer>,
@@ -277,7 +287,7 @@ where
277287
_create_invoice_from_channelmanager_and_duration_since_epoch(
278288
channelmanager, keys_manager, network, amt_msat,
279289
InvoiceDescription::Hash(&description_hash),
280-
duration_since_epoch,
290+
duration_since_epoch, invoice_expiry_delta_secs
281291
)
282292
}
283293

@@ -287,6 +297,7 @@ where
287297
pub fn create_invoice_from_channelmanager_and_duration_since_epoch<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
288298
channelmanager: &ChannelManager<Signer, M, T, K, F, L>, keys_manager: K, network: Currency,
289299
amt_msat: Option<u64>, description: String, duration_since_epoch: Duration,
300+
invoice_expiry_delta_secs: u32
290301
) -> Result<Invoice, SignOrCreationError<()>>
291302
where
292303
M::Target: chain::Watch<Signer>,
@@ -300,13 +311,14 @@ where
300311
InvoiceDescription::Direct(
301312
&Description::new(description).map_err(SignOrCreationError::CreationError)?,
302313
),
303-
duration_since_epoch,
314+
duration_since_epoch, invoice_expiry_delta_secs
304315
)
305316
}
306317

307318
fn _create_invoice_from_channelmanager_and_duration_since_epoch<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
308319
channelmanager: &ChannelManager<Signer, M, T, K, F, L>, keys_manager: K, network: Currency,
309320
amt_msat: Option<u64>, description: InvoiceDescription, duration_since_epoch: Duration,
321+
invoice_expiry_delta_secs: u32
310322
) -> Result<Invoice, SignOrCreationError<()>>
311323
where
312324
M::Target: chain::Watch<Signer>,
@@ -320,7 +332,7 @@ where
320332
// `create_inbound_payment` only returns an error if the amount is greater than the total bitcoin
321333
// supply.
322334
let (payment_hash, payment_secret) = channelmanager
323-
.create_inbound_payment(amt_msat, DEFAULT_EXPIRY_TIME.try_into().unwrap())
335+
.create_inbound_payment(amt_msat, invoice_expiry_delta_secs)
324336
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
325337
let our_node_pubkey = channelmanager.get_our_node_id();
326338

@@ -337,7 +349,8 @@ where
337349
.payment_hash(Hash::from_slice(&payment_hash.0).unwrap())
338350
.payment_secret(payment_secret)
339351
.basic_mpp()
340-
.min_final_cltv_expiry(MIN_FINAL_CLTV_EXPIRY.into());
352+
.min_final_cltv_expiry(MIN_FINAL_CLTV_EXPIRY.into())
353+
.expiry_time(Duration::from_secs(invoice_expiry_delta_secs.into()));
341354
if let Some(amt) = amt_msat {
342355
invoice = invoice.amount_milli_satoshis(amt);
343356
}
@@ -528,10 +541,11 @@ mod test {
528541
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
529542
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch(
530543
&nodes[1].node, nodes[1].keys_manager, Currency::BitcoinTestnet, Some(10_000), "test".to_string(),
531-
Duration::from_secs(1234567)).unwrap();
544+
Duration::from_secs(1234567), 3600).unwrap();
532545
assert_eq!(invoice.amount_pico_btc(), Some(100_000));
533546
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
534547
assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
548+
assert_eq!(invoice.expiry_time(), Duration::from_secs(3600));
535549

536550
// Invoice SCIDs should always use inbound SCID aliases over the real channel ID, if one is
537551
// available.
@@ -592,7 +606,7 @@ mod test {
592606
let description_hash = crate::Sha256(Hash::hash("Testing description_hash".as_bytes()));
593607
let invoice = ::utils::create_invoice_from_channelmanager_with_description_hash_and_duration_since_epoch(
594608
&nodes[1].node, nodes[1].keys_manager, Currency::BitcoinTestnet, Some(10_000),
595-
description_hash, Duration::from_secs(1234567),
609+
description_hash, Duration::from_secs(1234567), 3600
596610
).unwrap();
597611
assert_eq!(invoice.amount_pico_btc(), Some(100_000));
598612
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
@@ -752,7 +766,7 @@ mod test {
752766
) {
753767
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch(
754768
&invoice_node.node, invoice_node.keys_manager, Currency::BitcoinTestnet, invoice_amt, "test".to_string(),
755-
Duration::from_secs(1234567)).unwrap();
769+
Duration::from_secs(1234567), 3600).unwrap();
756770
let hints = invoice.private_routes();
757771

758772
for hint in hints {
@@ -811,6 +825,7 @@ mod test {
811825
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
812826
assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
813827
assert_eq!(invoice.route_hints().len(), 2);
828+
assert_eq!(invoice.expiry_time(), Duration::from_secs(3600));
814829
assert!(!invoice.features().unwrap().supports_basic_mpp());
815830

816831
let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key())
@@ -931,10 +946,23 @@ mod test {
931946
];
932947

933948
let description_hash = crate::Sha256(Hash::hash("Description hash phantom invoice".as_bytes()));
934-
let invoice = ::utils::create_phantom_invoice_with_description_hash::<EnforcingSigner,&test_utils::TestKeysInterface>(Some(payment_amt), None, 3600, description_hash, route_hints, &nodes[1].keys_manager, Currency::BitcoinTestnet).unwrap();
935-
949+
let non_default_invoice_expiry_secs = 4200;
950+
let invoice = ::utils::create_phantom_invoice_with_description_hash::<
951+
EnforcingSigner,
952+
&test_utils::TestKeysInterface,
953+
>(
954+
Some(payment_amt),
955+
None,
956+
non_default_invoice_expiry_secs,
957+
description_hash,
958+
route_hints,
959+
&nodes[1].keys_manager,
960+
Currency::BitcoinTestnet,
961+
)
962+
.unwrap();
936963
assert_eq!(invoice.amount_pico_btc(), Some(200_000));
937964
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
965+
assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));
938966
assert_eq!(invoice.description(), InvoiceDescription::Hash(&crate::Sha256(Sha256::hash("Description hash phantom invoice".as_bytes()))));
939967
}
940968

0 commit comments

Comments
 (0)