mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-03-15 15:39:09 +01:00
Add a BOLT11 invoice utility to ChannelManager
Now that the lightning crate depends on the lightning_invoice crate, the utility functions previously living in the latter can be implemented on ChannelManager. Additionally, the parameters are now moved to a struct in order to remove the increasingly combinatorial blow-up of methods. The new Bolt11InvoiceParameters is used to determine what values to set in the invoice. Using None for any given parameter results in a reasonable the default or a behavior determined by the ChannelManager as detailed in the documentation.
This commit is contained in:
parent
284cb28af2
commit
3c6896c9fa
2 changed files with 195 additions and 184 deletions
|
@ -102,6 +102,8 @@ use {
|
|||
crate::offers::refund::RefundMaybeWithDerivedMetadataBuilder,
|
||||
};
|
||||
|
||||
use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, CreationError, Currency, Description, InvoiceBuilder as Bolt11InvoiceBuilder, SignOrCreationError, DEFAULT_EXPIRY_TIME};
|
||||
|
||||
use alloc::collections::{btree_map, BTreeMap};
|
||||
|
||||
use crate::io;
|
||||
|
@ -2199,7 +2201,7 @@ where
|
|||
L::Target: Logger,
|
||||
{
|
||||
default_configuration: UserConfig,
|
||||
pub(super) chain_hash: ChainHash,
|
||||
chain_hash: ChainHash,
|
||||
fee_estimator: LowerBoundedFeeEstimator<F>,
|
||||
chain_monitor: M,
|
||||
tx_broadcaster: T,
|
||||
|
@ -9093,6 +9095,145 @@ where
|
|||
self.finish_close_channel(failure);
|
||||
}
|
||||
}
|
||||
|
||||
/// Utility for creating a BOLT11 invoice that can be verified by [`ChannelManager`] without
|
||||
/// storing any additional state. It achieves this by including a [`PaymentSecret`] in the
|
||||
/// invoice which it uses to verify that the invoice has not expired and the payment amount is
|
||||
/// sufficient, reproducing the [`PaymentPreimage`] if applicable.
|
||||
pub fn create_bolt11_invoice(
|
||||
&self, params: Bolt11InvoiceParameters,
|
||||
) -> Result<Bolt11Invoice, SignOrCreationError<()>> {
|
||||
let Bolt11InvoiceParameters {
|
||||
amount_msats, description, invoice_expiry_delta_secs, min_final_cltv_expiry_delta,
|
||||
payment_hash,
|
||||
} = params;
|
||||
|
||||
let currency =
|
||||
Network::from_chain_hash(self.chain_hash).map(Into::into).unwrap_or(Currency::Bitcoin);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
let duration_since_epoch = {
|
||||
use std::time::SystemTime;
|
||||
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)
|
||||
.expect("for the foreseeable future this shouldn't happen")
|
||||
};
|
||||
#[cfg(not(feature = "std"))]
|
||||
let duration_since_epoch =
|
||||
Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);
|
||||
|
||||
if let Some(min_final_cltv_expiry_delta) = min_final_cltv_expiry_delta {
|
||||
if min_final_cltv_expiry_delta.saturating_add(3) < MIN_FINAL_CLTV_EXPIRY_DELTA {
|
||||
return Err(SignOrCreationError::CreationError(CreationError::MinFinalCltvExpiryDeltaTooShort));
|
||||
}
|
||||
}
|
||||
|
||||
let (payment_hash, payment_secret) = match payment_hash {
|
||||
Some(payment_hash) => {
|
||||
let payment_secret = self
|
||||
.create_inbound_payment_for_hash(
|
||||
payment_hash, amount_msats,
|
||||
invoice_expiry_delta_secs.unwrap_or(DEFAULT_EXPIRY_TIME as u32),
|
||||
min_final_cltv_expiry_delta,
|
||||
)
|
||||
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
|
||||
(payment_hash, payment_secret)
|
||||
},
|
||||
None => {
|
||||
self
|
||||
.create_inbound_payment(
|
||||
amount_msats, invoice_expiry_delta_secs.unwrap_or(DEFAULT_EXPIRY_TIME as u32),
|
||||
min_final_cltv_expiry_delta,
|
||||
)
|
||||
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?
|
||||
},
|
||||
};
|
||||
|
||||
log_trace!(self.logger, "Creating invoice with payment hash {}", &payment_hash);
|
||||
|
||||
let invoice = Bolt11InvoiceBuilder::new(currency);
|
||||
let invoice = match description {
|
||||
Bolt11InvoiceDescription::Direct(description) => invoice.description(description.into_inner().0),
|
||||
Bolt11InvoiceDescription::Hash(hash) => invoice.description_hash(hash.0),
|
||||
};
|
||||
|
||||
let mut invoice = invoice
|
||||
.duration_since_epoch(duration_since_epoch)
|
||||
.payee_pub_key(self.get_our_node_id())
|
||||
.payment_hash(Hash::from_slice(&payment_hash.0).unwrap())
|
||||
.payment_secret(payment_secret)
|
||||
.basic_mpp()
|
||||
.min_final_cltv_expiry_delta(
|
||||
// Add a buffer of 3 to the delta if present, otherwise use LDK's minimum.
|
||||
min_final_cltv_expiry_delta.map(|x| x.saturating_add(3)).unwrap_or(MIN_FINAL_CLTV_EXPIRY_DELTA).into()
|
||||
);
|
||||
|
||||
if let Some(invoice_expiry_delta_secs) = invoice_expiry_delta_secs{
|
||||
invoice = invoice.expiry_time(Duration::from_secs(invoice_expiry_delta_secs.into()));
|
||||
}
|
||||
|
||||
if let Some(amount_msats) = amount_msats {
|
||||
invoice = invoice.amount_milli_satoshis(amount_msats);
|
||||
}
|
||||
|
||||
let channels = self.list_channels();
|
||||
let route_hints = super::invoice_utils::sort_and_filter_channels(channels, amount_msats, &self.logger);
|
||||
for hint in route_hints {
|
||||
invoice = invoice.private_route(hint);
|
||||
}
|
||||
|
||||
let raw_invoice = invoice.build_raw().map_err(|e| SignOrCreationError::CreationError(e))?;
|
||||
let signature = self.node_signer.sign_invoice(&raw_invoice, Recipient::Node);
|
||||
|
||||
raw_invoice
|
||||
.sign(|_| signature)
|
||||
.map(|invoice| Bolt11Invoice::from_signed(invoice).unwrap())
|
||||
.map_err(|e| SignOrCreationError::SignError(e))
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters used with [`create_bolt11_invoice`].
|
||||
///
|
||||
/// [`create_bolt11_invoice`]: ChannelManager::create_bolt11_invoice
|
||||
pub struct Bolt11InvoiceParameters {
|
||||
/// The amount for the invoice, if any.
|
||||
pub amount_msats: Option<u64>,
|
||||
|
||||
/// The description for what the invoice is for, or hash of such description.
|
||||
pub description: Bolt11InvoiceDescription,
|
||||
|
||||
/// The invoice expiration relative to its creation time. If not set, the invoice will expire in
|
||||
/// [`DEFAULT_EXPIRY_TIME`] by default.
|
||||
///
|
||||
/// The creation time used is the duration since the Unix epoch for `std` builds. For non-`std`
|
||||
/// builds, the highest block timestamp seen is used instead.
|
||||
pub invoice_expiry_delta_secs: Option<u32>,
|
||||
|
||||
/// The minimum `cltv_expiry` for the last HTLC in the route. If not set, will use
|
||||
/// [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
|
||||
///
|
||||
/// If set, must be at least [`MIN_FINAL_CLTV_EXPIRY_DELTA`], and a three-block buffer will be
|
||||
/// added as well to allow for up to a few new block confirmations during routing.
|
||||
pub min_final_cltv_expiry_delta: Option<u16>,
|
||||
|
||||
/// The payment hash used in the invoice. If not set, a payment hash will be generated using a
|
||||
/// preimage that can be reproduced by [`ChannelManager`] without storing any state.
|
||||
///
|
||||
/// Uses the payment hash if set. This may be useful if you're building an on-chain swap or
|
||||
/// involving another protocol where the payment hash is also involved outside the scope of
|
||||
/// lightning.
|
||||
pub payment_hash: Option<PaymentHash>,
|
||||
}
|
||||
|
||||
impl Default for Bolt11InvoiceParameters {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
amount_msats: None,
|
||||
description: Bolt11InvoiceDescription::Direct(Description::empty()),
|
||||
invoice_expiry_delta_secs: None,
|
||||
min_final_cltv_expiry_delta: None,
|
||||
payment_hash: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
|
||||
|
|
|
@ -6,13 +6,12 @@ use lightning_invoice::{Description, Bolt11InvoiceDescription, Sha256};
|
|||
use crate::prelude::*;
|
||||
|
||||
use bitcoin::hashes::Hash;
|
||||
use bitcoin::network::Network;
|
||||
use crate::chain;
|
||||
use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
|
||||
use crate::sign::{Recipient, NodeSigner, SignerProvider, EntropySource};
|
||||
use crate::types::payment::{PaymentHash, PaymentSecret};
|
||||
use crate::types::payment::PaymentHash;
|
||||
use crate::ln::channel_state::ChannelDetails;
|
||||
use crate::ln::channelmanager::{ChannelManager, PhantomRouteHints, MIN_CLTV_EXPIRY_DELTA, MIN_FINAL_CLTV_EXPIRY_DELTA};
|
||||
use crate::ln::channelmanager::{Bolt11InvoiceParameters, ChannelManager, PhantomRouteHints, MIN_CLTV_EXPIRY_DELTA, MIN_FINAL_CLTV_EXPIRY_DELTA};
|
||||
use crate::ln::inbound_payment::{create, create_from_hash, ExpandedKey};
|
||||
use crate::routing::gossip::RoutingFees;
|
||||
use crate::routing::router::{RouteHint, RouteHintHop, Router};
|
||||
|
@ -314,7 +313,6 @@ fn rotate_through_iterators<T, I: Iterator<Item = T>>(mut vecs: Vec<I>) -> impl
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// Utility to construct an invoice. Generally, unless you want to do something like a custom
|
||||
/// cltv_expiry, this is what you should be using to create an invoice. The reason being, this
|
||||
/// method stores the invoice's payment secret and preimage in `ChannelManager`, so (a) the user
|
||||
|
@ -331,9 +329,8 @@ fn rotate_through_iterators<T, I: Iterator<Item = T>>(mut vecs: Vec<I>) -> impl
|
|||
///
|
||||
/// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: crate::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
|
||||
pub fn create_invoice_from_channelmanager<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref>(
|
||||
channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, MR, L>, node_signer: NS, logger: L,
|
||||
amt_msat: Option<u64>, description: String, invoice_expiry_delta_secs: u32,
|
||||
min_final_cltv_expiry_delta: Option<u16>,
|
||||
channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, MR, L>, amt_msat: Option<u64>,
|
||||
description: String, invoice_expiry_delta_secs: u32, min_final_cltv_expiry_delta: Option<u16>,
|
||||
) -> Result<Bolt11Invoice, SignOrCreationError<()>>
|
||||
where
|
||||
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
|
||||
|
@ -346,21 +343,17 @@ where
|
|||
MR::Target: MessageRouter,
|
||||
L::Target: Logger,
|
||||
{
|
||||
use std::time::SystemTime;
|
||||
let duration_since_epoch = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.expect("for the foreseeable future this shouldn't happen");
|
||||
|
||||
_create_invoice_from_channelmanager_and_duration_since_epoch(
|
||||
channelmanager, node_signer, logger, amt_msat,
|
||||
Bolt11InvoiceDescription::Direct(
|
||||
Description::new(description).map_err(SignOrCreationError::CreationError)?,
|
||||
),
|
||||
duration_since_epoch, invoice_expiry_delta_secs, min_final_cltv_expiry_delta,
|
||||
)
|
||||
let description = Description::new(description).map_err(SignOrCreationError::CreationError)?;
|
||||
let params = Bolt11InvoiceParameters {
|
||||
amount_msats: amt_msat,
|
||||
description: Bolt11InvoiceDescription::Direct(description),
|
||||
invoice_expiry_delta_secs: Some(invoice_expiry_delta_secs),
|
||||
min_final_cltv_expiry_delta,
|
||||
payment_hash: None,
|
||||
};
|
||||
channelmanager.create_bolt11_invoice(params)
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// Utility to construct an invoice. Generally, unless you want to do something like a custom
|
||||
/// cltv_expiry, this is what you should be using to create an invoice. The reason being, this
|
||||
/// method stores the invoice's payment secret and preimage in `ChannelManager`, so (a) the user
|
||||
|
@ -378,9 +371,9 @@ where
|
|||
///
|
||||
/// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: crate::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
|
||||
pub fn create_invoice_from_channelmanager_with_description_hash<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref>(
|
||||
channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, MR, L>, node_signer: NS, logger: L,
|
||||
amt_msat: Option<u64>, description_hash: Sha256,
|
||||
invoice_expiry_delta_secs: u32, min_final_cltv_expiry_delta: Option<u16>,
|
||||
channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, MR, L>, amt_msat: Option<u64>,
|
||||
description_hash: Sha256, invoice_expiry_delta_secs: u32,
|
||||
min_final_cltv_expiry_delta: Option<u16>,
|
||||
) -> Result<Bolt11Invoice, SignOrCreationError<()>>
|
||||
where
|
||||
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
|
||||
|
@ -393,49 +386,16 @@ where
|
|||
MR::Target: MessageRouter,
|
||||
L::Target: Logger,
|
||||
{
|
||||
use std::time::SystemTime;
|
||||
let duration_since_epoch = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.expect("for the foreseeable future this shouldn't happen");
|
||||
|
||||
_create_invoice_from_channelmanager_and_duration_since_epoch(
|
||||
channelmanager, node_signer, logger, amt_msat,
|
||||
Bolt11InvoiceDescription::Hash(description_hash),
|
||||
duration_since_epoch, invoice_expiry_delta_secs, min_final_cltv_expiry_delta,
|
||||
)
|
||||
let params = Bolt11InvoiceParameters {
|
||||
amount_msats: amt_msat,
|
||||
description: Bolt11InvoiceDescription::Hash(description_hash),
|
||||
invoice_expiry_delta_secs: Some(invoice_expiry_delta_secs),
|
||||
min_final_cltv_expiry_delta,
|
||||
payment_hash: None,
|
||||
};
|
||||
channelmanager.create_bolt11_invoice(params)
|
||||
}
|
||||
|
||||
fn _create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref>(
|
||||
channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, MR, L>, node_signer: NS, logger: L,
|
||||
amt_msat: Option<u64>, description: Bolt11InvoiceDescription,
|
||||
duration_since_epoch: Duration, invoice_expiry_delta_secs: u32, min_final_cltv_expiry_delta: Option<u16>,
|
||||
) -> Result<Bolt11Invoice, SignOrCreationError<()>>
|
||||
where
|
||||
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
|
||||
T::Target: BroadcasterInterface,
|
||||
ES::Target: EntropySource,
|
||||
NS::Target: NodeSigner,
|
||||
SP::Target: SignerProvider,
|
||||
F::Target: FeeEstimator,
|
||||
R::Target: Router,
|
||||
MR::Target: MessageRouter,
|
||||
L::Target: Logger,
|
||||
{
|
||||
if min_final_cltv_expiry_delta.is_some() && min_final_cltv_expiry_delta.unwrap().saturating_add(3) < MIN_FINAL_CLTV_EXPIRY_DELTA {
|
||||
return Err(SignOrCreationError::CreationError(CreationError::MinFinalCltvExpiryDeltaTooShort));
|
||||
}
|
||||
|
||||
// `create_inbound_payment` only returns an error if the amount is greater than the total bitcoin
|
||||
// supply.
|
||||
let (payment_hash, payment_secret) = channelmanager
|
||||
.create_inbound_payment(amt_msat, invoice_expiry_delta_secs, min_final_cltv_expiry_delta)
|
||||
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
|
||||
_create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
|
||||
channelmanager, node_signer, logger, amt_msat, description, duration_since_epoch,
|
||||
invoice_expiry_delta_secs, payment_hash, payment_secret, min_final_cltv_expiry_delta)
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// See [`create_invoice_from_channelmanager`].
|
||||
///
|
||||
/// This version allows for providing custom [`PaymentHash`] and description hash for the invoice.
|
||||
|
@ -444,9 +404,9 @@ where
|
|||
/// the payment hash is also involved outside the scope of lightning and want to set the
|
||||
/// description hash.
|
||||
pub fn create_invoice_from_channelmanager_with_description_hash_and_payment_hash<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref>(
|
||||
channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, MR, L>, node_signer: NS, logger: L,
|
||||
amt_msat: Option<u64>, description_hash: Sha256,
|
||||
invoice_expiry_delta_secs: u32, payment_hash: PaymentHash, min_final_cltv_expiry_delta: Option<u16>,
|
||||
channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, MR, L>, amt_msat: Option<u64>,
|
||||
description_hash: Sha256, invoice_expiry_delta_secs: u32, payment_hash: PaymentHash,
|
||||
min_final_cltv_expiry_delta: Option<u16>,
|
||||
) -> Result<Bolt11Invoice, SignOrCreationError<()>>
|
||||
where
|
||||
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
|
||||
|
@ -459,33 +419,25 @@ where
|
|||
MR::Target: MessageRouter,
|
||||
L::Target: Logger,
|
||||
{
|
||||
use std::time::SystemTime;
|
||||
let duration_since_epoch = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.expect("for the foreseeable future this shouldn't happen");
|
||||
|
||||
let payment_secret = channelmanager
|
||||
.create_inbound_payment_for_hash(payment_hash, amt_msat, invoice_expiry_delta_secs,
|
||||
min_final_cltv_expiry_delta)
|
||||
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
|
||||
_create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
|
||||
channelmanager, node_signer, logger, amt_msat,
|
||||
Bolt11InvoiceDescription::Hash(description_hash),
|
||||
duration_since_epoch, invoice_expiry_delta_secs, payment_hash, payment_secret,
|
||||
let params = Bolt11InvoiceParameters {
|
||||
amount_msats: amt_msat,
|
||||
description: Bolt11InvoiceDescription::Hash(description_hash),
|
||||
invoice_expiry_delta_secs: Some(invoice_expiry_delta_secs),
|
||||
min_final_cltv_expiry_delta,
|
||||
)
|
||||
payment_hash: Some(payment_hash),
|
||||
};
|
||||
channelmanager.create_bolt11_invoice(params)
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// See [`create_invoice_from_channelmanager`].
|
||||
///
|
||||
/// This version allows for providing a custom [`PaymentHash`] for the invoice.
|
||||
/// This may be useful if you're building an on-chain swap or involving another protocol where
|
||||
/// the payment hash is also involved outside the scope of lightning.
|
||||
pub fn create_invoice_from_channelmanager_with_payment_hash<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref>(
|
||||
channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, MR, L>, node_signer: NS, logger: L,
|
||||
amt_msat: Option<u64>, description: String, invoice_expiry_delta_secs: u32,
|
||||
payment_hash: PaymentHash, min_final_cltv_expiry_delta: Option<u16>,
|
||||
channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, MR, L>, amt_msat: Option<u64>,
|
||||
description: String, invoice_expiry_delta_secs: u32, payment_hash: PaymentHash,
|
||||
min_final_cltv_expiry_delta: Option<u16>,
|
||||
) -> Result<Bolt11Invoice, SignOrCreationError<()>>
|
||||
where
|
||||
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
|
||||
|
@ -498,91 +450,15 @@ where
|
|||
MR::Target: MessageRouter,
|
||||
L::Target: Logger,
|
||||
{
|
||||
use std::time::SystemTime;
|
||||
let duration_since_epoch = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.expect("for the foreseeable future this shouldn't happen");
|
||||
|
||||
let payment_secret = channelmanager
|
||||
.create_inbound_payment_for_hash(payment_hash, amt_msat, invoice_expiry_delta_secs,
|
||||
min_final_cltv_expiry_delta)
|
||||
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
|
||||
_create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
|
||||
channelmanager, node_signer, logger, amt_msat,
|
||||
Bolt11InvoiceDescription::Direct(
|
||||
Description::new(description).map_err(SignOrCreationError::CreationError)?,
|
||||
),
|
||||
duration_since_epoch, invoice_expiry_delta_secs, payment_hash, payment_secret,
|
||||
let description = Description::new(description).map_err(SignOrCreationError::CreationError)?;
|
||||
let params = Bolt11InvoiceParameters {
|
||||
amount_msats: amt_msat,
|
||||
description: Bolt11InvoiceDescription::Direct(description),
|
||||
invoice_expiry_delta_secs: Some(invoice_expiry_delta_secs),
|
||||
min_final_cltv_expiry_delta,
|
||||
)
|
||||
}
|
||||
|
||||
fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref>(
|
||||
channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, MR, L>, node_signer: NS, logger: L,
|
||||
amt_msat: Option<u64>, description: Bolt11InvoiceDescription,
|
||||
duration_since_epoch: Duration, invoice_expiry_delta_secs: u32, payment_hash: PaymentHash,
|
||||
payment_secret: PaymentSecret, min_final_cltv_expiry_delta: Option<u16>,
|
||||
) -> Result<Bolt11Invoice, SignOrCreationError<()>>
|
||||
where
|
||||
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
|
||||
T::Target: BroadcasterInterface,
|
||||
ES::Target: EntropySource,
|
||||
NS::Target: NodeSigner,
|
||||
SP::Target: SignerProvider,
|
||||
F::Target: FeeEstimator,
|
||||
R::Target: Router,
|
||||
MR::Target: MessageRouter,
|
||||
L::Target: Logger,
|
||||
{
|
||||
let our_node_pubkey = channelmanager.get_our_node_id();
|
||||
let channels = channelmanager.list_channels();
|
||||
|
||||
let network = Network::from_chain_hash(channelmanager.chain_hash)
|
||||
.map(Into::into)
|
||||
.unwrap_or(Currency::Bitcoin);
|
||||
|
||||
if min_final_cltv_expiry_delta.is_some() && min_final_cltv_expiry_delta.unwrap().saturating_add(3) < MIN_FINAL_CLTV_EXPIRY_DELTA {
|
||||
return Err(SignOrCreationError::CreationError(CreationError::MinFinalCltvExpiryDeltaTooShort));
|
||||
}
|
||||
|
||||
log_trace!(logger, "Creating invoice with payment hash {}", &payment_hash);
|
||||
|
||||
let invoice = match description {
|
||||
Bolt11InvoiceDescription::Direct(description) => {
|
||||
InvoiceBuilder::new(network).description(description.into_inner().0)
|
||||
}
|
||||
Bolt11InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0),
|
||||
payment_hash: Some(payment_hash),
|
||||
};
|
||||
|
||||
let mut invoice = invoice
|
||||
.duration_since_epoch(duration_since_epoch)
|
||||
.payee_pub_key(our_node_pubkey)
|
||||
.payment_hash(Hash::from_slice(&payment_hash.0).unwrap())
|
||||
.payment_secret(payment_secret)
|
||||
.basic_mpp()
|
||||
.min_final_cltv_expiry_delta(
|
||||
// Add a buffer of 3 to the delta if present, otherwise use LDK's minimum.
|
||||
min_final_cltv_expiry_delta.map(|x| x.saturating_add(3)).unwrap_or(MIN_FINAL_CLTV_EXPIRY_DELTA).into())
|
||||
.expiry_time(Duration::from_secs(invoice_expiry_delta_secs.into()));
|
||||
if let Some(amt) = amt_msat {
|
||||
invoice = invoice.amount_milli_satoshis(amt);
|
||||
}
|
||||
|
||||
let route_hints = sort_and_filter_channels(channels, amt_msat, &logger);
|
||||
for hint in route_hints {
|
||||
invoice = invoice.private_route(hint);
|
||||
}
|
||||
|
||||
let raw_invoice = match invoice.build_raw() {
|
||||
Ok(inv) => inv,
|
||||
Err(e) => return Err(SignOrCreationError::CreationError(e))
|
||||
};
|
||||
let signature = node_signer.sign_invoice(&raw_invoice, Recipient::Node);
|
||||
let signed_raw_invoice = raw_invoice.sign(|_| signature);
|
||||
match signed_raw_invoice {
|
||||
Ok(inv) => Ok(Bolt11Invoice::from_signed(inv).unwrap()),
|
||||
Err(e) => Err(SignOrCreationError::SignError(e))
|
||||
}
|
||||
channelmanager.create_bolt11_invoice(params)
|
||||
}
|
||||
|
||||
/// Sorts and filters the `channels` for an invoice, and returns the corresponding `RouteHint`s to include
|
||||
|
@ -604,7 +480,7 @@ where
|
|||
/// * Limited to a total of 3 channels.
|
||||
/// * Sorted by lowest inbound capacity if an online channel with the minimum amount requested exists,
|
||||
/// otherwise sort by highest inbound capacity to give the payment the best chance of succeeding.
|
||||
fn sort_and_filter_channels<L: Deref>(
|
||||
pub(super) fn sort_and_filter_channels<L: Deref>(
|
||||
channels: Vec<ChannelDetails>,
|
||||
min_inbound_capacity_msat: Option<u64>,
|
||||
logger: &L,
|
||||
|
@ -878,8 +754,7 @@ mod test {
|
|||
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001);
|
||||
let non_default_invoice_expiry_secs = 4200;
|
||||
let invoice = create_invoice_from_channelmanager(
|
||||
nodes[1].node, nodes[1].keys_manager, nodes[1].logger,
|
||||
Some(10_000), "test".to_string(), non_default_invoice_expiry_secs, None,
|
||||
nodes[1].node, Some(10_000), "test".to_string(), non_default_invoice_expiry_secs, None,
|
||||
).unwrap();
|
||||
assert_eq!(invoice.amount_milli_satoshis(), Some(10_000));
|
||||
// If no `min_final_cltv_expiry_delta` is specified, then it should be `MIN_FINAL_CLTV_EXPIRY_DELTA`.
|
||||
|
@ -929,8 +804,7 @@ mod test {
|
|||
let custom_min_final_cltv_expiry_delta = Some(50);
|
||||
|
||||
let invoice = create_invoice_from_channelmanager(
|
||||
nodes[1].node, nodes[1].keys_manager, nodes[1].logger,
|
||||
Some(10_000), "".into(), 3600,
|
||||
nodes[1].node, Some(10_000), "".into(), 3600,
|
||||
if with_custom_delta { custom_min_final_cltv_expiry_delta } else { None },
|
||||
).unwrap();
|
||||
assert_eq!(invoice.min_final_cltv_expiry_delta(), if with_custom_delta {
|
||||
|
@ -952,8 +826,7 @@ mod test {
|
|||
let custom_min_final_cltv_expiry_delta = Some(21);
|
||||
|
||||
let invoice = create_invoice_from_channelmanager(
|
||||
nodes[1].node, nodes[1].keys_manager, nodes[1].logger,
|
||||
Some(10_000), "".into(), 3600, custom_min_final_cltv_expiry_delta,
|
||||
nodes[1].node, Some(10_000), "".into(), 3600, custom_min_final_cltv_expiry_delta,
|
||||
).unwrap();
|
||||
assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
|
||||
}
|
||||
|
@ -966,8 +839,7 @@ mod test {
|
|||
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
|
||||
let description_hash = Sha256(Hash::hash("Testing description_hash".as_bytes()));
|
||||
let invoice = create_invoice_from_channelmanager_with_description_hash(
|
||||
nodes[1].node, nodes[1].keys_manager, nodes[1].logger,
|
||||
Some(10_000), description_hash, 3600, None,
|
||||
nodes[1].node, Some(10_000), description_hash, 3600, None,
|
||||
).unwrap();
|
||||
assert_eq!(invoice.amount_milli_satoshis(), Some(10_000));
|
||||
assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
|
||||
|
@ -982,8 +854,7 @@ mod test {
|
|||
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
|
||||
let payment_hash = PaymentHash([0; 32]);
|
||||
let invoice = create_invoice_from_channelmanager_with_payment_hash(
|
||||
nodes[1].node, nodes[1].keys_manager, nodes[1].logger,
|
||||
Some(10_000), "test".to_string(), 3600, payment_hash, None,
|
||||
nodes[1].node, Some(10_000), "test".to_string(), 3600, payment_hash, None,
|
||||
).unwrap();
|
||||
assert_eq!(invoice.amount_milli_satoshis(), Some(10_000));
|
||||
assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
|
||||
|
@ -1273,8 +1144,7 @@ mod test {
|
|||
mut chan_ids_to_match: HashSet<u64>
|
||||
) {
|
||||
let invoice = create_invoice_from_channelmanager(
|
||||
invoice_node.node, invoice_node.keys_manager, invoice_node.logger,
|
||||
invoice_amt, "test".to_string(), 3600, None,
|
||||
invoice_node.node, invoice_amt, "test".to_string(), 3600, None,
|
||||
).unwrap();
|
||||
let hints = invoice.private_routes();
|
||||
|
||||
|
@ -1911,8 +1781,8 @@ mod test {
|
|||
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
|
||||
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
|
||||
let result = create_invoice_from_channelmanager(
|
||||
nodes[1].node, nodes[1].keys_manager, nodes[1].logger,
|
||||
Some(10_000), "Some description".into(), 3600, Some(MIN_FINAL_CLTV_EXPIRY_DELTA - 4),
|
||||
nodes[1].node, Some(10_000), "Some description".into(), 3600,
|
||||
Some(MIN_FINAL_CLTV_EXPIRY_DELTA - 4),
|
||||
);
|
||||
match result {
|
||||
Err(SignOrCreationError::CreationError(CreationError::MinFinalCltvExpiryDeltaTooShort)) => {},
|
||||
|
|
Loading…
Add table
Reference in a new issue