Skip to content

Commit 01197fb

Browse files
committed
Add new payment type and metadata bytes
Adds two new payment `Method`s for identifying payments with custom `min_final_cltv_expiry_delta` as payments with LDK or user payment hashes. The `min_final_cltv_expiry_delta` value is packed into the metadata bytes of the payment secret, taking up 12 bits.
1 parent 065a3e1 commit 01197fb

File tree

8 files changed

+142
-43
lines changed

8 files changed

+142
-43
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ fn get_payment_secret_hash(dest: &ChanMan, payment_id: &mut u8) -> Option<(Payme
305305
let mut payment_hash;
306306
for _ in 0..256 {
307307
payment_hash = PaymentHash(Sha256::hash(&[*payment_id; 1]).into_inner());
308-
if let Ok(payment_secret) = dest.create_inbound_payment_for_hash(payment_hash, None, 3600) {
308+
if let Ok(payment_secret) = dest.create_inbound_payment_for_hash(payment_hash, None, 3600, None) {
309309
return Some((payment_secret, payment_hash));
310310
}
311311
*payment_id = payment_id.wrapping_add(1);

fuzz/src/full_stack.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
570570
let payment_hash = PaymentHash(Sha256::from_engine(sha).into_inner());
571571
// Note that this may fail - our hashes may collide and we'll end up trying to
572572
// double-register the same payment_hash.
573-
let _ = channelmanager.create_inbound_payment_for_hash(payment_hash, None, 1);
573+
let _ = channelmanager.create_inbound_payment_for_hash(payment_hash, None, 1, None);
574574
},
575575
9 => {
576576
for payment in payments_received.drain(..) {

lightning-invoice/src/utils.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ where
157157
.duration_since(UNIX_EPOCH)
158158
.expect("Time must be > 1970")
159159
.as_secs(),
160+
None,
160161
)
161162
.map_err(|_| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
162163
(payment_hash, payment_secret)
@@ -170,6 +171,7 @@ where
170171
.duration_since(UNIX_EPOCH)
171172
.expect("Time must be > 1970")
172173
.as_secs(),
174+
None,
173175
)
174176
.map_err(|_| SignOrCreationError::CreationError(CreationError::InvalidAmount))?
175177
};
@@ -362,10 +364,11 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T: Der
362364
// `create_inbound_payment` only returns an error if the amount is greater than the total bitcoin
363365
// supply.
364366
let (payment_hash, payment_secret) = channelmanager
365-
.create_inbound_payment(amt_msat, invoice_expiry_delta_secs)
367+
.create_inbound_payment(amt_msat, invoice_expiry_delta_secs, min_final_cltv_expiry_delta)
366368
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
367369
_create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
368-
channelmanager, keys_manager, logger, network, amt_msat, description, duration_since_epoch, invoice_expiry_delta_secs, payment_hash, payment_secret)
370+
channelmanager, keys_manager, logger, network, amt_msat, description, duration_since_epoch,
371+
invoice_expiry_delta_secs, payment_hash, payment_secret, min_final_cltv_expiry_delta)
369372
}
370373

371374
/// See [`create_invoice_from_channelmanager_and_duration_since_epoch`]
@@ -375,7 +378,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T: Der
375378
pub fn create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
376379
channelmanager: &ChannelManager<M, T, K, F, L>, keys_manager: K, logger: L,
377380
network: Currency, amt_msat: Option<u64>, description: String, duration_since_epoch: Duration,
378-
invoice_expiry_delta_secs: u32, payment_hash: PaymentHash
381+
invoice_expiry_delta_secs: u32, payment_hash: PaymentHash, min_final_cltv_expiry_delta: Option<u32>,
379382
) -> Result<Invoice, SignOrCreationError<()>>
380383
where
381384
M::Target: chain::Watch<<K::Target as KeysInterface>::Signer>,
@@ -385,21 +388,24 @@ pub fn create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_
385388
L::Target: Logger,
386389
{
387390
let payment_secret = channelmanager
388-
.create_inbound_payment_for_hash(payment_hash,amt_msat, invoice_expiry_delta_secs)
391+
.create_inbound_payment_for_hash(payment_hash, amt_msat, invoice_expiry_delta_secs,
392+
min_final_cltv_expiry_delta)
389393
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
390394
_create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
391395
channelmanager, keys_manager, logger, network, amt_msat,
392396
InvoiceDescription::Direct(
393397
&Description::new(description).map_err(SignOrCreationError::CreationError)?,
394398
),
395-
duration_since_epoch, invoice_expiry_delta_secs, payment_hash, payment_secret
399+
duration_since_epoch, invoice_expiry_delta_secs, payment_hash, payment_secret,
400+
min_final_cltv_expiry_delta,
396401
)
397402
}
398403

399404
fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
400405
channelmanager: &ChannelManager<M, T, K, F, L>, keys_manager: K, logger: L,
401406
network: Currency, amt_msat: Option<u64>, description: InvoiceDescription, duration_since_epoch: Duration,
402-
invoice_expiry_delta_secs: u32, payment_hash: PaymentHash, payment_secret: PaymentSecret
407+
invoice_expiry_delta_secs: u32, payment_hash: PaymentHash, payment_secret: PaymentSecret,
408+
min_final_cltv_expiry_delta: Option<u32>,
403409
) -> Result<Invoice, SignOrCreationError<()>>
404410
where
405411
M::Target: chain::Watch<<K::Target as KeysInterface>::Signer>,
@@ -411,6 +417,10 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
411417
let our_node_pubkey = channelmanager.get_our_node_id();
412418
let channels = channelmanager.list_channels();
413419

420+
if min_final_cltv_expiry_delta.is_some() && min_final_cltv_expiry_delta.unwrap() < MIN_FINAL_CLTV_EXPIRY_DELTA {
421+
return Err(SignOrCreationError::CreationError(CreationError::MinFinalCltvExpiryDeltaTooShort));
422+
}
423+
414424
log_trace!(logger, "Creating invoice with payment hash {}", log_bytes!(payment_hash.0));
415425

416426
let invoice = match description {
@@ -638,6 +648,7 @@ mod test {
638648
use lightning::util::config::UserConfig;
639649
use lightning::chain::keysinterface::KeysInterface;
640650
use crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch;
651+
use core::time::Duration;
641652
use std::collections::HashSet;
642653

643654
#[test]
@@ -731,16 +742,17 @@ mod test {
731742
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
732743
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
733744
let payment_hash = PaymentHash([0; 32]);
734-
let payment_secret = &nodes[1].node.create_inbound_payment_for_hash(payment_hash, Some(10_000), 3600);
745+
let payment_secret = &nodes[1].node.create_inbound_payment_for_hash(payment_hash, Some(10_000), 3600, None);
735746
let invoice = crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
736747
&nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::BitcoinTestnet,
737748
Some(10_000), "test".to_string(), Duration::from_secs(1234567), 3600,
738-
payment_hash
749+
payment_hash, None,
739750
).unwrap();
740751
assert_eq!(invoice.amount_pico_btc(), Some(100_000));
741-
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
752+
assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
742753
assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
743754
assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&payment_hash.0[..]).unwrap());
755+
assert_eq!(invoice.payment_secret(), &payment_secret.unwrap());
744756
}
745757

746758
#[test]
@@ -1079,7 +1091,7 @@ mod test {
10791091
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, channelmanager::provided_init_features(), channelmanager::provided_init_features());
10801092

10811093
let payment_amt = 20_000;
1082-
let (payment_hash, _payment_secret) = nodes[1].node.create_inbound_payment(Some(payment_amt), 3600).unwrap();
1094+
let (payment_hash, _payment_secret) = nodes[1].node.create_inbound_payment(Some(payment_amt), 3600, None).unwrap();
10831095
let route_hints = vec![
10841096
nodes[1].node.get_phantom_route_hints(),
10851097
nodes[2].node.get_phantom_route_hints(),

lightning/src/ln/channelmanager.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5655,8 +5655,10 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
56555655
/// [`PaymentClaimable`]: events::Event::PaymentClaimable
56565656
/// [`PaymentClaimable::payment_preimage`]: events::Event::PaymentClaimable::payment_preimage
56575657
/// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
5658-
pub fn create_inbound_payment(&self, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32) -> Result<(PaymentHash, PaymentSecret), ()> {
5659-
inbound_payment::create(&self.inbound_payment_key, min_value_msat, invoice_expiry_delta_secs, &self.keys_manager, self.highest_seen_timestamp.load(Ordering::Acquire) as u64)
5658+
pub fn create_inbound_payment(&self, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32,
5659+
min_final_cltv_expiry_delta: Option<u32>) -> Result<(PaymentHash, PaymentSecret), ()> {
5660+
inbound_payment::create(&self.inbound_payment_key, min_value_msat, invoice_expiry_delta_secs,
5661+
&self.keys_manager, self.highest_seen_timestamp.load(Ordering::Acquire) as u64, min_final_cltv_expiry_delta)
56605662
}
56615663

56625664
/// Legacy version of [`create_inbound_payment`]. Use this method if you wish to share
@@ -5719,8 +5721,11 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
57195721
///
57205722
/// [`create_inbound_payment`]: Self::create_inbound_payment
57215723
/// [`PaymentClaimable`]: events::Event::PaymentClaimable
5722-
pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32) -> Result<PaymentSecret, ()> {
5723-
inbound_payment::create_from_hash(&self.inbound_payment_key, min_value_msat, payment_hash, invoice_expiry_delta_secs, self.highest_seen_timestamp.load(Ordering::Acquire) as u64)
5724+
pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option<u64>,
5725+
invoice_expiry_delta_secs: u32, min_final_cltv_expiry: Option<u32>) -> Result<PaymentSecret, ()> {
5726+
inbound_payment::create_from_hash(&self.inbound_payment_key, min_value_msat, payment_hash,
5727+
invoice_expiry_delta_secs, self.highest_seen_timestamp.load(Ordering::Acquire) as u64,
5728+
min_final_cltv_expiry)
57245729
}
57255730

57265731
/// Legacy version of [`create_inbound_payment_for_hash`]. Use this method if you wish to share
@@ -8484,7 +8489,7 @@ pub mod bench {
84848489
payment_preimage.0[0..8].copy_from_slice(&payment_count.to_le_bytes());
84858490
payment_count += 1;
84868491
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner());
8487-
let payment_secret = $node_b.create_inbound_payment_for_hash(payment_hash, None, 7200).unwrap();
8492+
let payment_secret = $node_b.create_inbound_payment_for_hash(payment_hash, None, 7200, None).unwrap();
84888493

84898494
$node_a.send_payment(&route, payment_hash, &Some(payment_secret), PaymentId(payment_hash.0)).unwrap();
84908495
let payment_event = SendEvent::from_event($node_a.get_and_clear_pending_msg_events().pop().unwrap());

lightning/src/ln/functional_test_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1343,7 +1343,7 @@ macro_rules! get_payment_preimage_hash {
13431343
*payment_count += 1;
13441344
let payment_hash = $crate::ln::PaymentHash(
13451345
bitcoin::hashes::sha256::Hash::hash(&payment_preimage.0[..]).into_inner());
1346-
let payment_secret = $dest_node.node.create_inbound_payment_for_hash(payment_hash, $min_value_msat, 7200).unwrap();
1346+
let payment_secret = $dest_node.node.create_inbound_payment_for_hash(payment_hash, $min_value_msat, 7200, None).unwrap();
13471347
(payment_preimage, payment_hash, payment_secret)
13481348
}
13491349
}

lightning/src/ln/functional_tests.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,7 +1240,7 @@ fn test_duplicate_htlc_different_direction_onchain() {
12401240
let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &vec!(&nodes[1])[..], 900_000);
12411241

12421242
let (route, _, _, _) = get_route_and_payment_hash!(nodes[1], nodes[0], 800_000);
1243-
let node_a_payment_secret = nodes[0].node.create_inbound_payment_for_hash(payment_hash, None, 7200).unwrap();
1243+
let node_a_payment_secret = nodes[0].node.create_inbound_payment_for_hash(payment_hash, None, 7200, None).unwrap();
12441244
send_along_route_with_secret(&nodes[1], route, &[&[&nodes[0]]], 800_000, payment_hash, node_a_payment_secret);
12451245

12461246
// Provide preimage to node 0 by claiming payment
@@ -4727,7 +4727,7 @@ fn test_duplicate_payment_hash_one_failure_one_success() {
47274727

47284728
let (our_payment_preimage, duplicate_payment_hash, _) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 900_000);
47294729

4730-
let payment_secret = nodes[3].node.create_inbound_payment_for_hash(duplicate_payment_hash, None, 7200).unwrap();
4730+
let payment_secret = nodes[3].node.create_inbound_payment_for_hash(duplicate_payment_hash, None, 7200, None).unwrap();
47314731
// We reduce the final CLTV here by a somewhat arbitrary constant to keep it under the one-byte
47324732
// script push size limit so that the below script length checks match
47334733
// ACCEPTED_HTLC_SCRIPT_WEIGHT.
@@ -4945,30 +4945,30 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
49454945
let (_, payment_hash_2, _) = route_payment(&nodes[0], &[&nodes[2], &nodes[3], &nodes[4]], ds_dust_limit*1000); // not added < dust limit + HTLC tx fee
49464946
let (route, _, _, _) = get_route_and_payment_hash!(nodes[1], nodes[5], ds_dust_limit*1000);
49474947
// 2nd HTLC:
4948-
send_along_route_with_secret(&nodes[1], route.clone(), &[&[&nodes[2], &nodes[3], &nodes[5]]], ds_dust_limit*1000, payment_hash_1, nodes[5].node.create_inbound_payment_for_hash(payment_hash_1, None, 7200).unwrap()); // not added < dust limit + HTLC tx fee
4948+
send_along_route_with_secret(&nodes[1], route.clone(), &[&[&nodes[2], &nodes[3], &nodes[5]]], ds_dust_limit*1000, payment_hash_1, nodes[5].node.create_inbound_payment_for_hash(payment_hash_1, None, 7200, None).unwrap()); // not added < dust limit + HTLC tx fee
49494949
// 3rd HTLC:
4950-
send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], ds_dust_limit*1000, payment_hash_2, nodes[5].node.create_inbound_payment_for_hash(payment_hash_2, None, 7200).unwrap()); // not added < dust limit + HTLC tx fee
4950+
send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], ds_dust_limit*1000, payment_hash_2, nodes[5].node.create_inbound_payment_for_hash(payment_hash_2, None, 7200, None).unwrap()); // not added < dust limit + HTLC tx fee
49514951
// 4th HTLC:
49524952
let (_, payment_hash_3, _) = route_payment(&nodes[0], &[&nodes[2], &nodes[3], &nodes[4]], 1000000);
49534953
// 5th HTLC:
49544954
let (_, payment_hash_4, _) = route_payment(&nodes[0], &[&nodes[2], &nodes[3], &nodes[4]], 1000000);
49554955
let (route, _, _, _) = get_route_and_payment_hash!(nodes[1], nodes[5], 1000000);
49564956
// 6th HTLC:
4957-
send_along_route_with_secret(&nodes[1], route.clone(), &[&[&nodes[2], &nodes[3], &nodes[5]]], 1000000, payment_hash_3, nodes[5].node.create_inbound_payment_for_hash(payment_hash_3, None, 7200).unwrap());
4957+
send_along_route_with_secret(&nodes[1], route.clone(), &[&[&nodes[2], &nodes[3], &nodes[5]]], 1000000, payment_hash_3, nodes[5].node.create_inbound_payment_for_hash(payment_hash_3, None, 7200, None).unwrap());
49584958
// 7th HTLC:
4959-
send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], 1000000, payment_hash_4, nodes[5].node.create_inbound_payment_for_hash(payment_hash_4, None, 7200).unwrap());
4959+
send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], 1000000, payment_hash_4, nodes[5].node.create_inbound_payment_for_hash(payment_hash_4, None, 7200, None).unwrap());
49604960

49614961
// 8th HTLC:
49624962
let (_, payment_hash_5, _) = route_payment(&nodes[0], &[&nodes[2], &nodes[3], &nodes[4]], 1000000);
49634963
// 9th HTLC:
49644964
let (route, _, _, _) = get_route_and_payment_hash!(nodes[1], nodes[5], ds_dust_limit*1000);
4965-
send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], ds_dust_limit*1000, payment_hash_5, nodes[5].node.create_inbound_payment_for_hash(payment_hash_5, None, 7200).unwrap()); // not added < dust limit + HTLC tx fee
4965+
send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], ds_dust_limit*1000, payment_hash_5, nodes[5].node.create_inbound_payment_for_hash(payment_hash_5, None, 7200, None).unwrap()); // not added < dust limit + HTLC tx fee
49664966

49674967
// 10th HTLC:
49684968
let (_, payment_hash_6, _) = route_payment(&nodes[0], &[&nodes[2], &nodes[3], &nodes[4]], ds_dust_limit*1000); // not added < dust limit + HTLC tx fee
49694969
// 11th HTLC:
49704970
let (route, _, _, _) = get_route_and_payment_hash!(nodes[1], nodes[5], 1000000);
4971-
send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], 1000000, payment_hash_6, nodes[5].node.create_inbound_payment_for_hash(payment_hash_6, None, 7200).unwrap());
4971+
send_along_route_with_secret(&nodes[1], route, &[&[&nodes[2], &nodes[3], &nodes[5]]], 1000000, payment_hash_6, nodes[5].node.create_inbound_payment_for_hash(payment_hash_6, None, 7200, None).unwrap());
49724972

49734973
// Double-check that six of the new HTLC were added
49744974
// We now have six HTLCs pending over the dust limit and six HTLCs under the dust limit (ie,
@@ -6937,7 +6937,7 @@ fn test_check_htlc_underpaying() {
69376937
let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id()).with_features(channelmanager::provided_invoice_features());
69386938
let route = get_route(&nodes[0].node.get_our_node_id(), &payment_params, &nodes[0].network_graph.read_only(), None, 10_000, TEST_FINAL_CLTV, nodes[0].logger, &scorer, &random_seed_bytes).unwrap();
69396939
let (_, our_payment_hash, _) = get_payment_preimage_hash!(nodes[0]);
6940-
let our_payment_secret = nodes[1].node.create_inbound_payment_for_hash(our_payment_hash, Some(100_000), 7200).unwrap();
6940+
let our_payment_secret = nodes[1].node.create_inbound_payment_for_hash(our_payment_hash, Some(100_000), 7200, None).unwrap();
69416941
nodes[0].node.send_payment(&route, our_payment_hash, &Some(our_payment_secret), PaymentId(our_payment_hash.0)).unwrap();
69426942
check_added_monitors!(nodes[0], 1);
69436943

@@ -7940,7 +7940,7 @@ fn test_preimage_storage() {
79407940
create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features()).0.contents.short_channel_id;
79417941

79427942
{
7943-
let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(Some(100_000), 7200).unwrap();
7943+
let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(Some(100_000), 7200, None).unwrap();
79447944
let (route, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[1], 100_000);
79457945
nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret), PaymentId(payment_hash.0)).unwrap();
79467946
check_added_monitors!(nodes[0], 1);
@@ -8046,7 +8046,7 @@ fn test_bad_secret_hash() {
80468046

80478047
let random_payment_hash = PaymentHash([42; 32]);
80488048
let random_payment_secret = PaymentSecret([43; 32]);
8049-
let (our_payment_hash, our_payment_secret) = nodes[1].node.create_inbound_payment(Some(100_000), 2).unwrap();
8049+
let (our_payment_hash, our_payment_secret) = nodes[1].node.create_inbound_payment(Some(100_000), 2, None).unwrap();
80508050
let (route, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[1], 100_000);
80518051

80528052
// All the below cases should end up being handled exactly identically, so we macro the

0 commit comments

Comments
 (0)