Skip to content

Commit 55baa15

Browse files
authored
Merge pull request #3246 from shaavan/blinded_api
Enable Creation of Offers and Refunds Without Blinded Path
2 parents 492fa70 + 596cf47 commit 55baa15

File tree

13 files changed

+616
-356
lines changed

13 files changed

+616
-356
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash;
3333
use bitcoin::hashes::Hash as TraitImport;
3434
use bitcoin::WPubkeyHash;
3535

36-
use lightning::blinded_path::message::{BlindedMessagePath, MessageContext};
36+
use lightning::blinded_path::message::{BlindedMessagePath, MessageContext, MessageForwardNode};
3737
use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs};
3838
use lightning::chain;
3939
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
@@ -144,7 +144,7 @@ impl MessageRouter for FuzzRouter {
144144

145145
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
146146
&self, _recipient: PublicKey, _local_node_receive_key: ReceiveAuthKey,
147-
_context: MessageContext, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
147+
_context: MessageContext, _peers: Vec<MessageForwardNode>, _secp_ctx: &Secp256k1<T>,
148148
) -> Result<Vec<BlindedMessagePath>, ()> {
149149
unreachable!()
150150
}

fuzz/src/full_stack.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use bitcoin::hashes::Hash as _;
3030
use bitcoin::hex::FromHex;
3131
use bitcoin::WPubkeyHash;
3232

33-
use lightning::blinded_path::message::{BlindedMessagePath, MessageContext};
33+
use lightning::blinded_path::message::{BlindedMessagePath, MessageContext, MessageForwardNode};
3434
use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs};
3535
use lightning::chain;
3636
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
@@ -175,7 +175,7 @@ impl MessageRouter for FuzzRouter {
175175

176176
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
177177
&self, _recipient: PublicKey, _local_node_receive_key: ReceiveAuthKey,
178-
_context: MessageContext, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
178+
_context: MessageContext, _peers: Vec<MessageForwardNode>, _secp_ctx: &Secp256k1<T>,
179179
) -> Result<Vec<BlindedMessagePath>, ()> {
180180
unreachable!()
181181
}

fuzz/src/onion_message.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use bitcoin::secp256k1::schnorr;
66
use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
77

88
use lightning::blinded_path::message::{
9-
AsyncPaymentsContext, BlindedMessagePath, MessageContext, OffersContext,
9+
AsyncPaymentsContext, BlindedMessagePath, MessageContext, MessageForwardNode, OffersContext,
1010
};
1111
use lightning::blinded_path::EmptyNodeIdLookUp;
1212
use lightning::ln::inbound_payment::ExpandedKey;
@@ -107,7 +107,7 @@ impl MessageRouter for TestMessageRouter {
107107

108108
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
109109
&self, _recipient: PublicKey, _local_node_receive_key: ReceiveAuthKey,
110-
_context: MessageContext, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
110+
_context: MessageContext, _peers: Vec<MessageForwardNode>, _secp_ctx: &Secp256k1<T>,
111111
) -> Result<Vec<BlindedMessagePath>, ()> {
112112
unreachable!()
113113
}

lightning-dns-resolver/src/lib.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,9 @@ mod test {
159159
use bitcoin::secp256k1::{self, PublicKey, Secp256k1};
160160
use bitcoin::Block;
161161

162-
use lightning::blinded_path::message::{BlindedMessagePath, MessageContext};
162+
use lightning::blinded_path::message::{
163+
BlindedMessagePath, MessageContext, MessageForwardNode,
164+
};
163165
use lightning::blinded_path::NodeIdLookUp;
164166
use lightning::events::{Event, PaymentPurpose};
165167
use lightning::ln::channelmanager::{PaymentId, Retry};
@@ -228,7 +230,7 @@ mod test {
228230

229231
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
230232
&self, recipient: PublicKey, local_node_receive_key: ReceiveAuthKey,
231-
context: MessageContext, _peers: Vec<PublicKey>, secp_ctx: &Secp256k1<T>,
233+
context: MessageContext, _peers: Vec<MessageForwardNode>, secp_ctx: &Secp256k1<T>,
232234
) -> Result<Vec<BlindedMessagePath>, ()> {
233235
let keys = KeysManager::new(&[0; 32], 42, 43);
234236
Ok(vec![BlindedMessagePath::one_hop(
@@ -465,7 +467,7 @@ mod test {
465467
#[tokio::test]
466468
async fn end_to_end_test() {
467469
let chanmon_cfgs = create_chanmon_cfgs(2);
468-
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
470+
let node_cfgs = create_node_cfgs_with_node_id_message_router(2, &chanmon_cfgs);
469471
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
470472
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
471473

@@ -491,7 +493,7 @@ mod test {
491493

492494
let name = HumanReadableName::from_encoded("matt@mattcorallo.com").unwrap();
493495

494-
let bs_offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap();
496+
let bs_offer = nodes[1].node.create_offer_builder().unwrap().build().unwrap();
495497
let resolvers = vec![Destination::Node(resolver_id)];
496498
let retry = Retry::Attempts(0);
497499
let amt = 42_000;

lightning/src/ln/channelmanager.rs

Lines changed: 86 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2156,9 +2156,8 @@ where
21562156
/// #
21572157
/// # fn example<T: AChannelManager>(channel_manager: T) -> Result<(), Bolt12SemanticError> {
21582158
/// # let channel_manager = channel_manager.get_cm();
2159-
/// # let absolute_expiry = None;
21602159
/// let offer = channel_manager
2161-
/// .create_offer_builder(absolute_expiry)?
2160+
/// .create_offer_builder()?
21622161
/// # ;
21632162
/// # // Needed for compiling for c_bindings
21642163
/// # let builder: lightning::offers::offer::OfferBuilder<_, _> = offer.into();
@@ -2969,9 +2968,7 @@ const MAX_NO_CHANNEL_PEERS: usize = 250;
29692968
/// short-lived, while anything with a greater expiration is considered long-lived.
29702969
///
29712970
/// Using [`ChannelManager::create_offer_builder`] or [`ChannelManager::create_refund_builder`],
2972-
/// will included a [`BlindedMessagePath`] created using:
2973-
/// - [`MessageRouter::create_compact_blinded_paths`] when short-lived, and
2974-
/// - [`MessageRouter::create_blinded_paths`] when long-lived.
2971+
/// will include a [`BlindedMessagePath`] created using [`MessageRouter::create_blinded_paths`].
29752972
///
29762973
/// Using compact [`BlindedMessagePath`]s may provide better privacy as the [`MessageRouter`] could select
29772974
/// more hops. However, since they use short channel ids instead of pubkeys, they are more likely to
@@ -11570,10 +11567,8 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
1157011567
///
1157111568
/// # Privacy
1157211569
///
11573-
/// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the offer based on the given
11574-
/// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
11575-
/// privacy implications as well as those of the parameterized [`Router`], which implements
11576-
/// [`MessageRouter`].
11570+
/// Uses the [`MessageRouter`] provided to the [`ChannelManager`] at construction to build a
11571+
/// [`BlindedMessagePath`] for the offer. See those docs for privacy implications.
1157711572
///
1157811573
/// Also, uses a derived signing pubkey in the offer for recipient privacy.
1157911574
///
@@ -11583,17 +11578,40 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
1158311578
///
1158411579
/// # Errors
1158511580
///
11586-
/// Errors if the parameterized [`Router`] is unable to create a blinded path for the offer.
11581+
/// Errors if the parameterized [`MessageRouter`] is unable to create a blinded path for the offer.
1158711582
///
1158811583
/// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath
1158911584
/// [`Offer`]: crate::offers::offer::Offer
1159011585
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
11591-
pub fn create_offer_builder(
11592-
&$self, absolute_expiry: Option<Duration>
11593-
) -> Result<$builder, Bolt12SemanticError> {
11594-
let entropy = &*$self.entropy_source;
11586+
pub fn create_offer_builder(&$self) -> Result<$builder, Bolt12SemanticError> {
11587+
let builder = $self.flow.create_offer_builder(
11588+
&*$self.entropy_source, $self.get_peers_for_blinded_path()
11589+
)?;
1159511590

11596-
let builder = $self.flow.create_offer_builder(entropy, absolute_expiry, $self.get_peers_for_blinded_path())?;
11591+
Ok(builder.into())
11592+
}
11593+
11594+
/// Same as [`Self::create_offer_builder`], but allows specifying a custom [`MessageRouter`]
11595+
/// instead of using the [`MessageRouter`] provided to the [`ChannelManager`] at construction.
11596+
///
11597+
/// This gives users full control over how the [`BlindedMessagePath`] is constructed,
11598+
/// including the option to omit it entirely.
11599+
///
11600+
/// See [`Self::create_offer_builder`] for details on offer construction, privacy, and limitations.
11601+
///
11602+
/// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath
11603+
/// [`Offer`]: crate::offers::offer::Offer
11604+
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
11605+
pub fn create_offer_builder_using_router<ME: Deref>(
11606+
&$self,
11607+
router: ME,
11608+
) -> Result<$builder, Bolt12SemanticError>
11609+
where
11610+
ME::Target: MessageRouter,
11611+
{
11612+
let builder = $self.flow.create_offer_builder_using_router(
11613+
router, &*$self.entropy_source, $self.get_peers_for_blinded_path()
11614+
)?;
1159711615

1159811616
Ok(builder.into())
1159911617
}
@@ -11624,8 +11642,7 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
1162411642
///
1162511643
/// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the refund based on the given
1162611644
/// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
11627-
/// privacy implications as well as those of the parameterized [`Router`], which implements
11628-
/// [`MessageRouter`].
11645+
/// privacy implications.
1162911646
///
1163011647
/// Also, uses a derived payer id in the refund for payer privacy.
1163111648
///
@@ -11663,6 +11680,55 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
1166311680

1166411681
Ok(builder.into())
1166511682
}
11683+
11684+
/// Same as [`Self::create_refund_builder`], but allows specifying a custom [`MessageRouter`]
11685+
/// instead of using the one provided during [`ChannelManager`] construction for
11686+
/// [`BlindedMessagePath`] creation.
11687+
///
11688+
/// This gives users full control over how the [`BlindedMessagePath`] is constructed for the
11689+
/// refund, including the option to omit it entirely. This is useful for testing or when
11690+
/// alternative privacy strategies are needed.
11691+
///
11692+
/// See [`Self::create_refund_builder`] for:
11693+
/// - refund recognition by [`ChannelManager`] via [`Bolt12Invoice`] handling,
11694+
/// - `payment_id` rules and expiration behavior,
11695+
/// - invoice revocation and refund failure handling,
11696+
/// - defaulting behavior for `max_total_routing_fee_msat`,
11697+
/// - and detailed payment and privacy semantics.
11698+
///
11699+
/// # Errors
11700+
///
11701+
/// In addition to the errors in [`Self::create_refund_builder`], this returns an error if
11702+
/// the provided [`MessageRouter`] fails to construct a valid [`BlindedMessagePath`] for the refund.
11703+
///
11704+
/// [`Refund`]: crate::offers::refund::Refund
11705+
/// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath
11706+
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
11707+
pub fn create_refund_builder_using_router<ME: Deref>(
11708+
&$self, router: ME, amount_msats: u64, absolute_expiry: Duration, payment_id: PaymentId,
11709+
retry_strategy: Retry, route_params_config: RouteParametersConfig
11710+
) -> Result<$builder, Bolt12SemanticError>
11711+
where
11712+
ME::Target: MessageRouter,
11713+
{
11714+
let entropy = &*$self.entropy_source;
11715+
11716+
let builder = $self.flow.create_refund_builder_using_router(
11717+
router, entropy, amount_msats, absolute_expiry,
11718+
payment_id, $self.get_peers_for_blinded_path()
11719+
)?;
11720+
11721+
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop($self);
11722+
11723+
let expiration = StaleExpiration::AbsoluteTimeout(absolute_expiry);
11724+
$self.pending_outbound_payments
11725+
.add_new_awaiting_invoice(
11726+
payment_id, expiration, retry_strategy, route_params_config, None,
11727+
)
11728+
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
11729+
11730+
Ok(builder.into())
11731+
}
1166611732
} }
1166711733

1166811734
impl<
@@ -11821,8 +11887,7 @@ where
1182111887
/// # Privacy
1182211888
///
1182311889
/// For payer privacy, uses a derived payer id and uses [`MessageRouter::create_blinded_paths`]
11824-
/// to construct a [`BlindedMessagePath`] for the reply path. For further privacy implications, see the
11825-
/// docs of the parameterized [`Router`], which implements [`MessageRouter`].
11890+
/// to construct a [`BlindedMessagePath`] for the reply path.
1182611891
///
1182711892
/// # Limitations
1182811893
///
@@ -12001,8 +12066,7 @@ where
1200112066
/// # Privacy
1200212067
///
1200312068
/// For payer privacy, uses a derived payer id and uses [`MessageRouter::create_blinded_paths`]
12004-
/// to construct a [`BlindedMessagePath`] for the reply path. For further privacy implications, see the
12005-
/// docs of the parameterized [`Router`], which implements [`MessageRouter`].
12069+
/// to construct a [`BlindedMessagePath`] for the reply path.
1200612070
///
1200712071
/// # Limitations
1200812072
///
@@ -18318,7 +18382,7 @@ pub mod bench {
1831818382
let scorer = RwLock::new(test_utils::TestScorer::new());
1831918383
let entropy = test_utils::TestKeysInterface::new(&[0u8; 32], network);
1832018384
let router = test_utils::TestRouter::new(Arc::new(NetworkGraph::new(network, &logger_a)), &logger_a, &scorer);
18321-
let message_router = test_utils::TestMessageRouter::new(Arc::new(NetworkGraph::new(network, &logger_a)), &entropy);
18385+
let message_router = test_utils::TestMessageRouter::new_default(Arc::new(NetworkGraph::new(network, &logger_a)), &entropy);
1832218386

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

0 commit comments

Comments
 (0)