Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lightning-dns-resolver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ mod test {

let name = HumanReadableName::from_encoded("matt@mattcorallo.com").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
43 changes: 32 additions & 11 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2157,9 +2157,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 @@ -11465,9 +11464,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.
/// Uses the [`MessageRouter`] provided to the [`ChannelManager`] at construction to build a
/// [`BlindedMessagePath`] for the offer. See those docs for privacy implications.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly here, not sure what "those docs" refers to, we can probably just drop that sentence or rephrase as "see the documentation for the selected MessageRouter for information on its design decisions and privacy tradeoffs made".

This applies elsewhere here including for refunds as well as in flow.rs for both offers and refunds.

///
/// Also, uses a derived signing pubkey in the offer for recipient privacy.
///
Expand All @@ -11477,17 +11475,40 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
///
/// # Errors
///
/// Errors if the parameterized [`Router`] is unable to create a blinded path for the offer.
/// Errors if the parameterized [`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(
&$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())
}

/// Same as [`Self::create_offer_builder`], but allows specifying a custom [`MessageRouter`]
/// instead of using the [`MessageRouter`] provided to the [`ChannelManager`] at construction.
///
/// This gives users full control over how the [`BlindedMessagePath`] is constructed,
/// including the option to omit it entirely.
///
/// See [`Self::create_offer_builder`] for details on offer construction, privacy, and limitations.
///
/// [`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
2 changes: 1 addition & 1 deletion lightning/src/ln/max_payment_path_len_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ fn bolt12_invoice_too_large_blinded_paths() {
),
]);

let offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap();
let offer = nodes[1].node.create_offer_builder().unwrap().build().unwrap();
let payment_id = PaymentId([1; 32]);
let route_config = RouteParametersConfig::default();
nodes[0]
Expand Down
70 changes: 29 additions & 41 deletions lightning/src/ln/offers_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ use crate::offers::invoice_error::InvoiceError;
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields};
use crate::offers::nonce::Nonce;
use crate::offers::parse::Bolt12SemanticError;
use crate::onion_message::messenger::{Destination, PeeledOnion, MessageSendInstructions};
use crate::onion_message::messenger::{Destination, MessageSendInstructions, NodeIdMessageRouter, PeeledOnion};
use crate::onion_message::offers::OffersMessage;
use crate::routing::gossip::{NodeAlias, NodeId};
use crate::routing::router::{PaymentParameters, RouteParameters, RouteParametersConfig};
Expand Down Expand Up @@ -307,7 +307,7 @@ fn prefers_non_tor_nodes_in_blinded_paths() {
announce_node_address(charlie, &[alice, bob, david, &nodes[4], &nodes[5]], tor.clone());

let offer = bob.node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_ne!(offer.issuer_signing_pubkey(), Some(bob_id));
Expand All @@ -323,7 +323,7 @@ fn prefers_non_tor_nodes_in_blinded_paths() {
announce_node_address(&nodes[5], &[alice, bob, charlie, david, &nodes[4]], tor.clone());

let offer = bob.node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_ne!(offer.issuer_signing_pubkey(), Some(bob_id));
Expand Down Expand Up @@ -374,7 +374,7 @@ fn prefers_more_connected_nodes_in_blinded_paths() {
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);

let offer = bob.node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_ne!(offer.issuer_signing_pubkey(), Some(bob_id));
Expand All @@ -399,11 +399,9 @@ fn creates_short_lived_offer() {
let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1];

let absolute_expiry = alice.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY;
let offer = alice.node
.create_offer_builder(Some(absolute_expiry)).unwrap()
.create_offer_builder().unwrap()
.build().unwrap();
assert_eq!(offer.absolute_expiry(), Some(absolute_expiry));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
let introduction_node_id = resolve_introduction_node(bob, &path);
Expand All @@ -416,7 +414,7 @@ fn creates_short_lived_offer() {
#[test]
fn creates_long_lived_offer() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs_with_node_id_message_router(2, &chanmon_cfgs);
let node_cfgs = create_node_cfgs(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 @@ -425,22 +423,11 @@ fn creates_long_lived_offer() {
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();

let absolute_expiry = alice.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY
+ Duration::from_secs(1);
let router = NodeIdMessageRouter::new(alice.network_graph, alice.keys_manager);
let offer = alice.node
.create_offer_builder(Some(absolute_expiry))
.create_offer_builder_using_router(&router)
.unwrap()
.build().unwrap();
assert_eq!(offer.absolute_expiry(), Some(absolute_expiry));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
}

let offer = alice.node
.create_offer_builder(None).unwrap()
.build().unwrap();
assert_eq!(offer.absolute_expiry(), None);
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
Expand Down Expand Up @@ -542,7 +529,7 @@ fn creates_and_pays_for_offer_using_two_hop_blinded_path() {
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);

let offer = alice.node
.create_offer_builder(None)
.create_offer_builder()
.unwrap()
.amount_msats(10_000_000)
.build().unwrap();
Expand Down Expand Up @@ -709,7 +696,7 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() {
let bob_id = bob.node.get_our_node_id();

let offer = alice.node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
Expand Down Expand Up @@ -832,7 +819,7 @@ fn pays_for_offer_without_blinded_paths() {
let bob_id = bob.node.get_our_node_id();

let offer = alice.node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.clear_paths()
.amount_msats(10_000_000)
.build().unwrap();
Expand Down Expand Up @@ -956,7 +943,7 @@ fn send_invoice_requests_with_distinct_reply_path() {
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);

let offer = alice.node
.create_offer_builder(None)
.create_offer_builder()
.unwrap()
.amount_msats(10_000_000)
.build().unwrap();
Expand Down Expand Up @@ -1092,7 +1079,7 @@ fn creates_and_pays_for_offer_with_retry() {
let bob_id = bob.node.get_our_node_id();

let offer = alice.node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
Expand Down Expand Up @@ -1168,7 +1155,7 @@ fn pays_bolt12_invoice_asynchronously() {
let bob_id = bob.node.get_our_node_id();

let offer = alice.node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();

Expand Down Expand Up @@ -1260,7 +1247,7 @@ fn creates_offer_with_blinded_path_using_unannounced_introduction_node() {
let bob_id = bob.node.get_our_node_id();

let offer = alice.node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
Expand Down Expand Up @@ -1390,7 +1377,7 @@ fn fails_authentication_when_handling_invoice_request() {
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);

let offer = alice.node
.create_offer_builder(None)
.create_offer_builder()
.unwrap()
.amount_msats(10_000_000)
.build().unwrap();
Expand All @@ -1402,7 +1389,7 @@ fn fails_authentication_when_handling_invoice_request() {
}

let invalid_path = alice.node
.create_offer_builder(None)
.create_offer_builder()
.unwrap()
.build().unwrap()
.paths().first().unwrap()
Expand Down Expand Up @@ -1502,7 +1489,7 @@ fn fails_authentication_when_handling_invoice_for_offer() {
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);

let offer = alice.node
.create_offer_builder(None)
.create_offer_builder()
.unwrap()
.amount_msats(10_000_000)
.build().unwrap();
Expand Down Expand Up @@ -1698,8 +1685,7 @@ fn fails_creating_or_paying_for_offer_without_connected_peers() {
disconnect_peers(alice, &[bob, charlie, david, &nodes[4], &nodes[5]]);
disconnect_peers(david, &[bob, charlie, &nodes[4], &nodes[5]]);

let absolute_expiry = alice.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY;
match alice.node.create_offer_builder(Some(absolute_expiry)) {
match alice.node.create_offer_builder() {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
}
Expand All @@ -1708,9 +1694,11 @@ fn fails_creating_or_paying_for_offer_without_connected_peers() {
args.send_channel_ready = (true, true);
reconnect_nodes(args);

let absolute_expiry = alice.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY;
let offer = alice.node
.create_offer_builder(Some(absolute_expiry)).unwrap()
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.absolute_expiry(absolute_expiry)
.build().unwrap();

let payment_id = PaymentId([1; 32]);
Expand Down Expand Up @@ -1813,7 +1801,7 @@ fn fails_creating_invoice_request_for_unsupported_chain() {
let bob = &nodes[1];

let offer = alice.node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.clear_chains()
.chain(Network::Signet)
.build().unwrap();
Expand Down Expand Up @@ -1872,7 +1860,7 @@ fn fails_creating_invoice_request_without_blinded_reply_path() {
disconnect_peers(david, &[bob, charlie, &nodes[4], &nodes[5]]);

let offer = alice.node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();

Expand Down Expand Up @@ -1906,7 +1894,7 @@ fn fails_creating_invoice_request_with_duplicate_payment_id() {
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);

let offer = alice.node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();

Expand Down Expand Up @@ -1992,7 +1980,7 @@ fn fails_sending_invoice_without_blinded_payment_paths_for_offer() {
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);

let offer = alice.node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();

Expand Down Expand Up @@ -2201,7 +2189,7 @@ fn fails_paying_invoice_with_unknown_required_features() {
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);

let offer = alice.node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();

Expand Down Expand Up @@ -2280,7 +2268,7 @@ fn rejects_keysend_to_non_static_invoice_path() {
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);

// First pay the offer and save the payment preimage and invoice.
let offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap();
let offer = nodes[1].node.create_offer_builder().unwrap().build().unwrap();
let amt_msat = 5000;
let payment_id = PaymentId([1; 32]);
nodes[0].node.pay_for_offer(&offer, None, Some(amt_msat), None, payment_id, Retry::Attempts(1), RouteParametersConfig::default()).unwrap();
Expand Down Expand Up @@ -2360,7 +2348,7 @@ fn no_double_pay_with_stale_channelmanager() {

let amt_msat = nodes[0].node.list_usable_channels()[0].next_outbound_htlc_limit_msat + 1; // Force MPP
let offer = nodes[1].node
.create_offer_builder(None).unwrap()
.create_offer_builder().unwrap()
.clear_paths()
.amount_msats(amt_msat)
.build().unwrap();
Expand Down
Loading