Skip to content

Enable Creation of Offers and Refunds Without Blinded Path #3246

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
4 changes: 2 additions & 2 deletions fuzz/src/chanmon_consistency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash;
use bitcoin::hashes::Hash as TraitImport;
use bitcoin::WPubkeyHash;

use lightning::blinded_path::message::{BlindedMessagePath, MessageContext};
use lightning::blinded_path::message::{BlindedMessagePath, MessageContext, MessageForwardNode};
use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs};
use lightning::chain;
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
Expand Down Expand Up @@ -142,7 +142,7 @@ impl MessageRouter for FuzzRouter {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<MessageForwardNode>,
_secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
unreachable!()
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/full_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use bitcoin::hashes::Hash as _;
use bitcoin::hex::FromHex;
use bitcoin::WPubkeyHash;

use lightning::blinded_path::message::{BlindedMessagePath, MessageContext};
use lightning::blinded_path::message::{BlindedMessagePath, MessageContext, MessageForwardNode};
use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs};
use lightning::chain;
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
Expand Down Expand Up @@ -173,7 +173,7 @@ impl MessageRouter for FuzzRouter {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<MessageForwardNode>,
_secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
unreachable!()
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/onion_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use bitcoin::secp256k1::schnorr;
use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};

use lightning::blinded_path::message::{
AsyncPaymentsContext, BlindedMessagePath, MessageContext, OffersContext,
AsyncPaymentsContext, BlindedMessagePath, MessageContext, MessageForwardNode, OffersContext,
};
use lightning::blinded_path::EmptyNodeIdLookUp;
use lightning::ln::inbound_payment::ExpandedKey;
Expand Down Expand Up @@ -104,7 +104,7 @@ impl MessageRouter for TestMessageRouter {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<MessageForwardNode>,
_secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
unreachable!()
Expand Down
10 changes: 6 additions & 4 deletions lightning-dns-resolver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ mod test {
use bitcoin::secp256k1::{self, PublicKey, Secp256k1};
use bitcoin::Block;

use lightning::blinded_path::message::{BlindedMessagePath, MessageContext};
use lightning::blinded_path::message::{
BlindedMessagePath, MessageContext, MessageForwardNode,
};
use lightning::blinded_path::NodeIdLookUp;
use lightning::events::{Event, PaymentPurpose};
use lightning::ln::channelmanager::{PaymentId, Retry};
Expand Down Expand Up @@ -230,7 +232,7 @@ mod test {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, recipient: PublicKey, context: MessageContext, _peers: Vec<PublicKey>,
&self, recipient: PublicKey, context: MessageContext, _peers: Vec<MessageForwardNode>,
secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
let keys = KeysManager::new(&[0; 32], 42, 43);
Expand Down Expand Up @@ -454,7 +456,7 @@ mod test {
#[tokio::test]
async fn end_to_end_test() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_cfgs = create_node_cfgs_with_node_id_message_router(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);

Expand All @@ -480,7 +482,7 @@ mod test {

let name = HumanReadableName::from_encoded("[email protected]").unwrap();

let bs_offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap();
let bs_offer = nodes[1].node.create_offer_builder().unwrap().build().unwrap();
let resolvers = vec![Destination::Node(resolver_id)];
let retry = Retry::Attempts(0);
let amt = 42_000;
Expand Down
134 changes: 113 additions & 21 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2214,9 +2214,8 @@ where
/// #
/// # fn example<T: AChannelManager>(channel_manager: T) -> Result<(), Bolt12SemanticError> {
/// # let channel_manager = channel_manager.get_cm();
/// # let absolute_expiry = None;
/// let offer = channel_manager
/// .create_offer_builder(absolute_expiry)?
/// .create_offer_builder()?
/// # ;
/// # // Needed for compiling for c_bindings
/// # let builder: lightning::offers::offer::OfferBuilder<_, _> = offer.into();
Expand Down Expand Up @@ -3024,9 +3023,7 @@ const MAX_NO_CHANNEL_PEERS: usize = 250;
/// short-lived, while anything with a greater expiration is considered long-lived.
///
/// Using [`ChannelManager::create_offer_builder`] or [`ChannelManager::create_refund_builder`],
/// will included a [`BlindedMessagePath`] created using:
/// - [`MessageRouter::create_compact_blinded_paths`] when short-lived, and
/// - [`MessageRouter::create_blinded_paths`] when long-lived.
/// will include a [`BlindedMessagePath`] created using [`MessageRouter::create_blinded_paths`]
///
/// Using compact [`BlindedMessagePath`]s may provide better privacy as the [`MessageRouter`] could select
/// more hops. However, since they use short channel ids instead of pubkeys, they are more likely to
Expand Down Expand Up @@ -10901,10 +10898,8 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
///
/// # Privacy
///
/// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the offer based on the given
/// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
/// privacy implications as well as those of the parameterized [`Router`], which implements
/// [`MessageRouter`].
/// Uses the [`ChannelManager`]'s [`MessageRouter`] to construct a [`BlindedMessagePath`] for
/// the offer. See those docs for privacy implications.
///
/// Also, uses a derived signing pubkey in the offer for recipient privacy.
///
Expand All @@ -10919,12 +10914,46 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
/// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath
/// [`Offer`]: crate::offers::offer::Offer
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
pub fn create_offer_builder(
&$self, absolute_expiry: Option<Duration>
) -> Result<$builder, Bolt12SemanticError> {
let entropy = &*$self.entropy_source;
pub fn create_offer_builder(&$self) -> Result<$builder, Bolt12SemanticError> {
let builder = $self.flow.create_offer_builder(
&*$self.entropy_source, $self.get_peers_for_blinded_path()
)?;

let builder = $self.flow.create_offer_builder(entropy, absolute_expiry, $self.get_peers_for_blinded_path())?;
Ok(builder.into())
}

/// Creates an [`OfferBuilder`] such that the [`Offer`] it builds is recognized by the
/// [`ChannelManager`] when handling [`InvoiceRequest`] messages for the offer.
///
/// # Privacy
///
/// Constructs a [`BlindedMessagePath`] for the offer using a custom [`MessageRouter`].
/// Users can implement a custom [`MessageRouter`] to define properties of the
/// [`BlindedMessagePath`] as required or opt not to create any `BlindedMessagePath`.
///
/// Also, uses a derived signing pubkey in the offer for recipient privacy.
///
/// # Limitations
///
/// See [`OffersMessageFlow::create_offer_builder`] for limitations on the offer builder.
///
/// # Errors
///
/// Errors if the provided [`MessageRouter`] is unable to create a blinded path for the offer.
///
/// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath
/// [`Offer`]: crate::offers::offer::Offer
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
pub fn create_offer_builder_using_router<ME: Deref>(
&$self,
router: ME,
) -> Result<$builder, Bolt12SemanticError>
where
ME::Target: MessageRouter,
{
let builder = $self.flow.create_offer_builder_using_router(
router, &*$self.entropy_source, $self.get_peers_for_blinded_path()
)?;

Ok(builder.into())
}
Expand Down Expand Up @@ -10955,8 +10984,7 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
///
/// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the refund based on the given
/// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
/// privacy implications as well as those of the parameterized [`Router`], which implements
/// [`MessageRouter`].
/// privacy implications.
///
/// Also, uses a derived payer id in the refund for payer privacy.
///
Expand Down Expand Up @@ -10994,6 +11022,72 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {

Ok(builder.into())
}

/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
/// [`ChannelManager`] when handling [`Bolt12Invoice`] messages for the refund.
///
/// # Payment
///
/// The provided `payment_id` is used to ensure that only one invoice is paid for the refund.
/// See [Avoiding Duplicate Payments] for other requirements once the payment has been sent.
///
/// The builder will have the provided expiration set. Any changes to the expiration on the
/// returned builder will not be honored by [`ChannelManager`]. For non-`std`, the highest seen
/// block time minus two hours is used for the current time when determining if the refund has
/// expired.
///
/// To revoke the refund, use [`ChannelManager::abandon_payment`] prior to receiving the
/// invoice. If abandoned, or an invoice isn't received before expiration, the payment will fail
/// with an [`Event::PaymentFailed`].
///
/// If `max_total_routing_fee_msat` is not specified, The default from
/// [`RouteParameters::from_payment_params_and_value`] is applied.
///
/// # Privacy
///
/// Constructs a [`BlindedMessagePath`] for the refund using a custom [`MessageRouter`].
/// Users can implement a custom [`MessageRouter`] to define properties of the
/// [`BlindedMessagePath`] as required or opt not to create any `BlindedMessagePath`.
///
/// Also, uses a derived payer id in the refund for payer privacy.
///
/// # Errors
///
/// Errors if:
/// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
/// - `amount_msats` is invalid, or
/// - the provided [`MessageRouter`] is unable to create a blinded path for the refund.
///
/// [`Refund`]: crate::offers::refund::Refund
/// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
/// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths
/// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
pub fn create_refund_builder_using_router<ME: Deref>(
&$self, router: ME, amount_msats: u64, absolute_expiry: Duration, payment_id: PaymentId,
retry_strategy: Retry, route_params_config: RouteParametersConfig
) -> Result<$builder, Bolt12SemanticError>
where
ME::Target: MessageRouter,
{
let entropy = &*$self.entropy_source;

let builder = $self.flow.create_refund_builder_using_router(
router, entropy, amount_msats, absolute_expiry,
payment_id, $self.get_peers_for_blinded_path()
)?;

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop($self);

let expiration = StaleExpiration::AbsoluteTimeout(absolute_expiry);
$self.pending_outbound_payments
.add_new_awaiting_invoice(
payment_id, expiration, retry_strategy, route_params_config, None,
)
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;

Ok(builder.into())
}
} }

impl<
Expand Down Expand Up @@ -11152,8 +11246,7 @@ where
/// # Privacy
///
/// For payer privacy, uses a derived payer id and uses [`MessageRouter::create_blinded_paths`]
/// to construct a [`BlindedMessagePath`] for the reply path. For further privacy implications, see the
/// docs of the parameterized [`Router`], which implements [`MessageRouter`].
/// to construct a [`BlindedMessagePath`] for the reply path.
///
/// # Limitations
///
Expand Down Expand Up @@ -11332,8 +11425,7 @@ where
/// # Privacy
///
/// For payer privacy, uses a derived payer id and uses [`MessageRouter::create_blinded_paths`]
/// to construct a [`BlindedMessagePath`] for the reply path. For further privacy implications, see the
/// docs of the parameterized [`Router`], which implements [`MessageRouter`].
/// to construct a [`BlindedMessagePath`] for the reply path.
///
/// # Limitations
///
Expand Down Expand Up @@ -17234,7 +17326,7 @@ pub mod bench {
let scorer = RwLock::new(test_utils::TestScorer::new());
let entropy = test_utils::TestKeysInterface::new(&[0u8; 32], network);
let router = test_utils::TestRouter::new(Arc::new(NetworkGraph::new(network, &logger_a)), &logger_a, &scorer);
let message_router = test_utils::TestMessageRouter::new(Arc::new(NetworkGraph::new(network, &logger_a)), &entropy);
let message_router = test_utils::TestMessageRouter::new_default(Arc::new(NetworkGraph::new(network, &logger_a)), &entropy);

let mut config: UserConfig = Default::default();
config.channel_config.max_dust_htlc_exposure = MaxDustHTLCExposure::FeeRateMultiplier(5_000_000 / 253);
Expand Down
Loading
Loading