Skip to content

Commit 4eddd20

Browse files
committed
Add invoice constructor with custom payment hash
1 parent 5e577cb commit 4eddd20

File tree

1 file changed

+81
-22
lines changed

1 file changed

+81
-22
lines changed

lightning-invoice/src/utils.rs

Lines changed: 81 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -294,12 +294,12 @@ pub fn create_invoice_from_channelmanager_with_description_hash_and_duration_sin
294294
network: Currency, amt_msat: Option<u64>, description_hash: Sha256,
295295
duration_since_epoch: Duration, invoice_expiry_delta_secs: u32
296296
) -> 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,
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,
303303
{
304304
_create_invoice_from_channelmanager_and_duration_since_epoch(
305305
channelmanager, keys_manager, logger, network, amt_msat,
@@ -316,12 +316,12 @@ pub fn create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T:
316316
network: Currency, amt_msat: Option<u64>, description: String, duration_since_epoch: Duration,
317317
invoice_expiry_delta_secs: u32
318318
) -> 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,
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,
325325
{
326326
_create_invoice_from_channelmanager_and_duration_since_epoch(
327327
channelmanager, keys_manager, logger, network, amt_msat,
@@ -337,21 +337,63 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T: Der
337337
network: Currency, amt_msat: Option<u64>, description: InvoiceDescription,
338338
duration_since_epoch: Duration, invoice_expiry_delta_secs: u32
339339
) -> 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,
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,
346346
{
347347
// `create_inbound_payment` only returns an error if the amount is greater than the total bitcoin
348348
// supply.
349349
let (payment_hash, payment_secret) = channelmanager
350350
.create_inbound_payment(amt_msat, invoice_expiry_delta_secs)
351351
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
352+
_create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
353+
channelmanager, keys_manager, logger, network, amt_msat, description, duration_since_epoch, invoice_expiry_delta_secs, payment_hash)
354+
}
355+
356+
/// See [`create_invoice_from_channelmanager_and_duration_since_epoch`]
357+
///Function that allows to construct invoices with the given payment hash.
358+
///This may be useful if you're building an on-chain swap or integrating with another protocol where the payment hash is fixed outside of lightning.
359+
pub fn create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
360+
channelmanager: &ChannelManager<M, T, K, F, L>, keys_manager: K, logger: L,
361+
network: Currency, amt_msat: Option<u64>, description: String, duration_since_epoch: Duration,
362+
invoice_expiry_delta_secs: u32, payment_hash: PaymentHash
363+
) -> Result<Invoice, SignOrCreationError<()>>
364+
where
365+
M::Target: chain::Watch<<K::Target as KeysInterface>::Signer>,
366+
T::Target: BroadcasterInterface,
367+
K::Target: KeysInterface,
368+
F::Target: FeeEstimator,
369+
L::Target: Logger,
370+
{
371+
_create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
372+
channelmanager, keys_manager, logger, network, amt_msat,
373+
InvoiceDescription::Direct(
374+
&Description::new(description).map_err(SignOrCreationError::CreationError)?,
375+
),
376+
duration_since_epoch, invoice_expiry_delta_secs, payment_hash
377+
)
378+
}
379+
380+
fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
381+
channelmanager: &ChannelManager<M, T, K, F, L>, keys_manager: K, logger: L,
382+
network: Currency, amt_msat: Option<u64>, description: InvoiceDescription, duration_since_epoch: Duration,
383+
invoice_expiry_delta_secs: u32, payment_hash: PaymentHash
384+
) -> Result<Invoice, SignOrCreationError<()>>
385+
where
386+
M::Target: chain::Watch<<K::Target as KeysInterface>::Signer>,
387+
T::Target: BroadcasterInterface,
388+
K::Target: KeysInterface,
389+
F::Target: FeeEstimator,
390+
L::Target: Logger,
391+
{
352392
let our_node_pubkey = channelmanager.get_our_node_id();
353393
let channels = channelmanager.list_channels();
354-
394+
let payment_secret = channelmanager
395+
.create_inbound_payment_for_hash(payment_hash,amt_msat,invoice_expiry_delta_secs)
396+
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
355397
log_trace!(logger, "Creating invoice with payment hash {}", log_bytes!(payment_hash.0));
356398

357399
let invoice = match description {
@@ -567,7 +609,7 @@ where
567609
mod test {
568610
use core::time::Duration;
569611
use crate::{Currency, Description, InvoiceDescription};
570-
use bitcoin_hashes::Hash;
612+
use bitcoin_hashes::{Hash, sha256};
571613
use bitcoin_hashes::sha256::Hash as Sha256;
572614
use lightning::chain::keysinterface::PhantomKeysManager;
573615
use lightning::ln::{PaymentPreimage, PaymentHash};
@@ -665,6 +707,25 @@ mod test {
665707
assert_eq!(invoice.description(), InvoiceDescription::Hash(&crate::Sha256(Sha256::hash("Testing description_hash".as_bytes()))));
666708
}
667709

710+
#[test]
711+
fn test_create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash() {
712+
let chanmon_cfgs = create_chanmon_cfgs(2);
713+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
714+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
715+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
716+
let payment_hash = PaymentHash([0; 32]);
717+
let payment_secret = &nodes[1].node.create_inbound_payment_for_hash(payment_hash, Some(10_000), 3600);
718+
let invoice = crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
719+
&nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::BitcoinTestnet,
720+
Some(10_000), "test".to_string(), Duration::from_secs(1234567), 3600,
721+
payment_hash
722+
).unwrap();
723+
assert_eq!(invoice.amount_pico_btc(), Some(100_000));
724+
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
725+
assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
726+
assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&payment_hash.0[..]).unwrap());
727+
}
728+
668729
#[test]
669730
fn test_hints_includes_single_channels_to_nodes() {
670731
let chanmon_cfgs = create_chanmon_cfgs(3);
@@ -691,10 +752,8 @@ mod test {
691752
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());
692753
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());
693754
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-
695755
let mut scid_aliases = HashSet::new();
696756
scid_aliases.insert(chan_1_0_high_inbound_capacity.0.short_channel_id_alias.unwrap());
697-
698757
match_invoice_routes(Some(5000), &nodes[0], scid_aliases);
699758
}
700759

0 commit comments

Comments
 (0)