Skip to content

Commit 296c7f8

Browse files
committed
Add invoice constructor with custom payment hash
1 parent 5e577cb commit 296c7f8

File tree

1 file changed

+110
-53
lines changed

1 file changed

+110
-53
lines changed

lightning-invoice/src/utils.rs

Lines changed: 110 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -286,72 +286,45 @@ 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 to construct invoices with the given 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
326+
.create_inbound_payment_for_hash(payment_hash,amt_msat,invoice_expiry_delta_secs)
327+
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
355328
log_trace!(logger, "Creating invoice with payment hash {}", log_bytes!(payment_hash.0));
356329

357330
let invoice = match description {
@@ -392,6 +365,73 @@ where
392365
}
393366
}
394367

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

708+
#[test]
709+
fn test_create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash() {
710+
let chanmon_cfgs = create_chanmon_cfgs(2);
711+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
712+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
713+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
714+
let payment_hash = PaymentHash([0; 32]);
715+
let payment_secret = &nodes[1].node.create_inbound_payment_for_hash(payment_hash, Some(10_000), 3600);
716+
let invoice = crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
717+
&nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::BitcoinTestnet,
718+
Some(10_000), "test".to_string(), Duration::from_secs(1234567), 3600,
719+
payment_hash
720+
).unwrap();
721+
assert_eq!(invoice.amount_pico_btc(), Some(100_000));
722+
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
723+
assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
724+
assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&payment_hash.0[..]).unwrap());
725+
}
726+
668727
#[test]
669728
fn test_hints_includes_single_channels_to_nodes() {
670729
let chanmon_cfgs = create_chanmon_cfgs(3);
@@ -691,10 +750,8 @@ mod test {
691750
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());
692751
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());
693752
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-
695753
let mut scid_aliases = HashSet::new();
696754
scid_aliases.insert(chan_1_0_high_inbound_capacity.0.short_channel_id_alias.unwrap());
697-
698755
match_invoice_routes(Some(5000), &nodes[0], scid_aliases);
699756
}
700757

0 commit comments

Comments
 (0)