Skip to content

Commit 51136d5

Browse files
committed
Add invoice constructor with custom payment hash
1 parent 5e577cb commit 51136d5

File tree

1 file changed

+109
-54
lines changed

1 file changed

+109
-54
lines changed

lightning-invoice/src/utils.rs

Lines changed: 109 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -286,72 +286,43 @@ where
286286
)
287287
}
288288

289-
/// See [`create_invoice_from_channelmanager_with_description_hash`]
290-
/// This version can be used in a `no_std` environment, where [`std::time::SystemTime`] is not
291-
/// available and the current time is supplied by the caller.
292-
pub fn create_invoice_from_channelmanager_with_description_hash_and_duration_since_epoch<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
293-
channelmanager: &ChannelManager<M, T, K, F, L>, keys_manager: K, logger: L,
294-
network: Currency, amt_msat: Option<u64>, description_hash: Sha256,
295-
duration_since_epoch: Duration, invoice_expiry_delta_secs: u32
296-
) -> Result<Invoice, SignOrCreationError<()>>
297-
where
298-
M::Target: chain::Watch<<K::Target as KeysInterface>::Signer>,
299-
T::Target: BroadcasterInterface,
300-
K::Target: KeysInterface,
301-
F::Target: FeeEstimator,
302-
L::Target: Logger,
303-
{
304-
_create_invoice_from_channelmanager_and_duration_since_epoch(
305-
channelmanager, keys_manager, logger, network, amt_msat,
306-
InvoiceDescription::Hash(&description_hash),
307-
duration_since_epoch, invoice_expiry_delta_secs
308-
)
309-
}
310-
311-
/// See [`create_invoice_from_channelmanager`]
312-
/// This version can be used in a `no_std` environment, where [`std::time::SystemTime`] is not
313-
/// available and the current time is supplied by the caller.
314-
pub fn create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
289+
///Function that allows for contructing invoices with custom payment hash
290+
pub fn create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
315291
channelmanager: &ChannelManager<M, T, K, F, L>, keys_manager: K, logger: L,
316292
network: Currency, amt_msat: Option<u64>, description: String, duration_since_epoch: Duration,
317-
invoice_expiry_delta_secs: u32
293+
invoice_expiry_delta_secs: u32, payment_hash: PaymentHash
318294
) -> Result<Invoice, SignOrCreationError<()>>
319-
where
320-
M::Target: chain::Watch<<K::Target as KeysInterface>::Signer>,
321-
T::Target: BroadcasterInterface,
322-
K::Target: KeysInterface,
323-
F::Target: FeeEstimator,
324-
L::Target: Logger,
295+
where
296+
M::Target: chain::Watch<<K::Target as KeysInterface>::Signer>,
297+
T::Target: BroadcasterInterface,
298+
K::Target: KeysInterface,
299+
F::Target: FeeEstimator,
300+
L::Target: Logger,
325301
{
326-
_create_invoice_from_channelmanager_and_duration_since_epoch(
302+
_create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
327303
channelmanager, keys_manager, logger, network, amt_msat,
328304
InvoiceDescription::Direct(
329305
&Description::new(description).map_err(SignOrCreationError::CreationError)?,
330306
),
331-
duration_since_epoch, invoice_expiry_delta_secs
307+
duration_since_epoch, invoice_expiry_delta_secs, payment_hash
332308
)
333309
}
334310

335-
fn _create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
311+
fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
336312
channelmanager: &ChannelManager<M, T, K, F, L>, keys_manager: K, logger: L,
337-
network: Currency, amt_msat: Option<u64>, description: InvoiceDescription,
338-
duration_since_epoch: Duration, invoice_expiry_delta_secs: u32
313+
network: Currency, amt_msat: Option<u64>, description: InvoiceDescription, duration_since_epoch: Duration,
314+
invoice_expiry_delta_secs: u32, payment_hash: PaymentHash
339315
) -> Result<Invoice, SignOrCreationError<()>>
340-
where
341-
M::Target: chain::Watch<<K::Target as KeysInterface>::Signer>,
342-
T::Target: BroadcasterInterface,
343-
K::Target: KeysInterface,
344-
F::Target: FeeEstimator,
345-
L::Target: Logger,
316+
where
317+
M::Target: chain::Watch<<K::Target as KeysInterface>::Signer>,
318+
T::Target: BroadcasterInterface,
319+
K::Target: KeysInterface,
320+
F::Target: FeeEstimator,
321+
L::Target: Logger,
346322
{
347-
// `create_inbound_payment` only returns an error if the amount is greater than the total bitcoin
348-
// supply.
349-
let (payment_hash, payment_secret) = channelmanager
350-
.create_inbound_payment(amt_msat, invoice_expiry_delta_secs)
351-
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
352323
let our_node_pubkey = channelmanager.get_our_node_id();
353324
let channels = channelmanager.list_channels();
354-
325+
let payment_secret = channelmanager.create_inbound_payment_for_hash(payment_hash,amt_msat,invoice_expiry_delta_secs);
355326
log_trace!(logger, "Creating invoice with payment hash {}", log_bytes!(payment_hash.0));
356327

357328
let invoice = match description {
@@ -365,7 +336,7 @@ where
365336
.duration_since_epoch(duration_since_epoch)
366337
.payee_pub_key(our_node_pubkey)
367338
.payment_hash(Hash::from_slice(&payment_hash.0).unwrap())
368-
.payment_secret(payment_secret)
339+
.payment_secret(map_err(payment_secret))
369340
.basic_mpp()
370341
.min_final_cltv_expiry(MIN_FINAL_CLTV_EXPIRY.into())
371342
.expiry_time(Duration::from_secs(invoice_expiry_delta_secs.into()));
@@ -392,6 +363,73 @@ where
392363
}
393364
}
394365

366+
/// See [`create_invoice_from_channelmanager_with_description_hash`]
367+
/// This version can be used in a `no_std` environment, where [`std::time::SystemTime`] is not
368+
/// available and the current time is supplied by the caller.
369+
pub fn create_invoice_from_channelmanager_with_description_hash_and_duration_since_epoch<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
370+
channelmanager: &ChannelManager<M, T, K, F, L>, keys_manager: K, logger: L,
371+
network: Currency, amt_msat: Option<u64>, description_hash: Sha256,
372+
duration_since_epoch: Duration, invoice_expiry_delta_secs: u32
373+
) -> Result<Invoice, SignOrCreationError<()>>
374+
where
375+
M::Target: chain::Watch<<K::Target as KeysInterface>::Signer>,
376+
T::Target: BroadcasterInterface,
377+
K::Target: KeysInterface,
378+
F::Target: FeeEstimator,
379+
L::Target: Logger,
380+
{
381+
_create_invoice_from_channelmanager_and_duration_since_epoch(
382+
channelmanager, keys_manager, logger, network, amt_msat,
383+
InvoiceDescription::Hash(&description_hash),
384+
duration_since_epoch, invoice_expiry_delta_secs
385+
)
386+
}
387+
388+
/// See [`create_invoice_from_channelmanager`]
389+
/// This version can be used in a `no_std` environment, where [`std::time::SystemTime`] is not
390+
/// available and the current time is supplied by the caller.
391+
pub fn create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
392+
channelmanager: &ChannelManager<M, T, K, F, L>, keys_manager: K, logger: L,
393+
network: Currency, amt_msat: Option<u64>, description: String, duration_since_epoch: Duration,
394+
invoice_expiry_delta_secs: u32
395+
) -> Result<Invoice, SignOrCreationError<()>>
396+
where
397+
M::Target: chain::Watch<<K::Target as KeysInterface>::Signer>,
398+
T::Target: BroadcasterInterface,
399+
K::Target: KeysInterface,
400+
F::Target: FeeEstimator,
401+
L::Target: Logger,
402+
{
403+
_create_invoice_from_channelmanager_and_duration_since_epoch(
404+
channelmanager, keys_manager, logger, network, amt_msat,
405+
InvoiceDescription::Direct(
406+
&Description::new(description).map_err(SignOrCreationError::CreationError)?,
407+
),
408+
duration_since_epoch, invoice_expiry_delta_secs
409+
)
410+
}
411+
412+
fn _create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
413+
channelmanager: &ChannelManager<M, T, K, F, L>, keys_manager: K, logger: L,
414+
network: Currency, amt_msat: Option<u64>, description: InvoiceDescription,
415+
duration_since_epoch: Duration, invoice_expiry_delta_secs: u32
416+
) -> Result<Invoice, SignOrCreationError<()>>
417+
where
418+
M::Target: chain::Watch<<K::Target as KeysInterface>::Signer>,
419+
T::Target: BroadcasterInterface,
420+
K::Target: KeysInterface,
421+
F::Target: FeeEstimator,
422+
L::Target: Logger,
423+
{
424+
// `create_inbound_payment` only returns an error if the amount is greater than the total bitcoin
425+
// supply.
426+
let (payment_hash, payment_secret) = channelmanager
427+
.create_inbound_payment(amt_msat, invoice_expiry_delta_secs)
428+
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
429+
_create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
430+
channelmanager, keys_manager, logger, network, amt_msat, description, duration_since_epoch, invoice_expiry_delta_secs, payment_hash)
431+
}
432+
395433
/// Filters the `channels` for an invoice, and returns the corresponding `RouteHint`s to include
396434
/// in the invoice.
397435
///
@@ -567,7 +605,7 @@ where
567605
mod test {
568606
use core::time::Duration;
569607
use crate::{Currency, Description, InvoiceDescription};
570-
use bitcoin_hashes::Hash;
608+
use bitcoin_hashes::{Hash, sha256};
571609
use bitcoin_hashes::sha256::Hash as Sha256;
572610
use lightning::chain::keysinterface::PhantomKeysManager;
573611
use lightning::ln::{PaymentPreimage, PaymentHash};
@@ -665,6 +703,25 @@ mod test {
665703
assert_eq!(invoice.description(), InvoiceDescription::Hash(&crate::Sha256(Sha256::hash("Testing description_hash".as_bytes()))));
666704
}
667705

706+
#[test]
707+
fn test_create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash() {
708+
let chanmon_cfgs = create_chanmon_cfgs(2);
709+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
710+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
711+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
712+
let payment_hash = PaymentHash([0; 32]);
713+
let payment_secret = &nodes[1].node.create_inbound_payment_for_hash(payment_hash, Some(10_000), 3600);
714+
let invoice = crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
715+
&nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::BitcoinTestnet,
716+
Some(10_000), "test".to_string(), Duration::from_secs(1234567), 3600,
717+
payment_hash
718+
).unwrap();
719+
assert_eq!(invoice.amount_pico_btc(), Some(100_000));
720+
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
721+
assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
722+
assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&payment_hash.0[..]).unwrap());
723+
}
724+
668725
#[test]
669726
fn test_hints_includes_single_channels_to_nodes() {
670727
let chanmon_cfgs = create_chanmon_cfgs(3);
@@ -691,10 +748,8 @@ mod test {
691748
let _chan_1_0_low_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 100_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
692749
let chan_1_0_high_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 10_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
693750
let _chan_1_0_medium_inbound_capacity = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 0, 1_000_000, 0, channelmanager::provided_init_features(), channelmanager::provided_init_features());
694-
695751
let mut scid_aliases = HashSet::new();
696752
scid_aliases.insert(chan_1_0_high_inbound_capacity.0.short_channel_id_alias.unwrap());
697-
698753
match_invoice_routes(Some(5000), &nodes[0], scid_aliases);
699754
}
700755

0 commit comments

Comments
 (0)