Skip to content

Commit 8800d48

Browse files
committed
Add AsyncBolt12Offer support to LSPS2 BOLT12 router
Expand `LSPS2BOLT12Router` to also handle `PaymentContext::AsyncBolt12Offer` contexts in addition to `Bolt12Offer`. Since `AsyncBolt12OfferContext` uses an `offer_nonce` (rather than an `OfferId`), add a parallel nonce-keyed map with `register_offer_nonce` / `unregister_offer_nonce` methods. The `MessageRouter` implementation's SCID injection also checks the nonce map so that async offers benefit from compact message blinded paths. Co-Authored-By: HAL 9000
1 parent 7ca886d commit 8800d48

1 file changed

Lines changed: 51 additions & 16 deletions

File tree

lightning-liquidity/src/lsps2/router.rs

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ use lightning::blinded_path::message::{
2020
BlindedMessagePath, MessageContext, MessageForwardNode, OffersContext,
2121
};
2222
use lightning::blinded_path::payment::{
23-
BlindedPaymentPath, Bolt12OfferContext, ForwardTlvs, PaymentConstraints, PaymentContext,
24-
PaymentForwardNode, PaymentRelay, ReceiveTlvs,
23+
AsyncBolt12OfferContext, BlindedPaymentPath, Bolt12OfferContext, ForwardTlvs,
24+
PaymentConstraints, PaymentContext, PaymentForwardNode, PaymentRelay, ReceiveTlvs,
2525
};
2626
use lightning::ln::channel_state::ChannelDetails;
2727
use lightning::ln::channelmanager::{PaymentId, MIN_FINAL_CLTV_EXPIRY_DELTA};
28+
use lightning::offers::nonce::Nonce;
2829
use lightning::offers::offer::OfferId;
2930
use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath};
3031
use lightning::routing::router::{InFlightHtlcs, Route, RouteParameters, Router};
@@ -61,6 +62,7 @@ pub struct LSPS2BOLT12Router<R: Router, MR: MessageRouter, ES: EntropySource + S
6162
inner_message_router: MR,
6263
entropy_source: ES,
6364
offer_to_invoice_params: Mutex<HashMap<[u8; 32], LSPS2Bolt12InvoiceParameters>>,
65+
nonce_to_invoice_params: Mutex<HashMap<[u8; Nonce::LENGTH], LSPS2Bolt12InvoiceParameters>>,
6466
}
6567

6668
impl<R: Router, MR: MessageRouter, ES: EntropySource + Send + Sync> LSPS2BOLT12Router<R, MR, ES> {
@@ -71,6 +73,7 @@ impl<R: Router, MR: MessageRouter, ES: EntropySource + Send + Sync> LSPS2BOLT12R
7173
inner_message_router,
7274
entropy_source,
7375
offer_to_invoice_params: Mutex::new(new_hash_map()),
76+
nonce_to_invoice_params: Mutex::new(new_hash_map()),
7477
}
7578
}
7679

@@ -86,22 +89,50 @@ impl<R: Router, MR: MessageRouter, ES: EntropySource + Send + Sync> LSPS2BOLT12R
8689
self.offer_to_invoice_params.lock().unwrap().remove(&offer_id.0)
8790
}
8891

89-
/// Clears all LSPS2 parameters previously registered via [`Self::register_offer`].
92+
/// Registers LSPS2 parameters to be used when generating blinded payment paths for an async
93+
/// BOLT12 offer identified by its `offer_nonce`.
94+
///
95+
/// This is the async-offer counterpart to [`Self::register_offer`], used for
96+
/// [`PaymentContext::AsyncBolt12Offer`] contexts where the offer is identified by its nonce
97+
/// rather than its [`OfferId`].
98+
pub fn register_offer_nonce(
99+
&self, offer_nonce: Nonce, invoice_params: LSPS2Bolt12InvoiceParameters,
100+
) -> Option<LSPS2Bolt12InvoiceParameters> {
101+
let mut key = [0u8; Nonce::LENGTH];
102+
key.copy_from_slice(offer_nonce.as_slice());
103+
self.nonce_to_invoice_params.lock().unwrap().insert(key, invoice_params)
104+
}
105+
106+
/// Removes any previously registered LSPS2 parameters for `offer_nonce`.
107+
pub fn unregister_offer_nonce(
108+
&self, offer_nonce: &Nonce,
109+
) -> Option<LSPS2Bolt12InvoiceParameters> {
110+
let mut key = [0u8; Nonce::LENGTH];
111+
key.copy_from_slice(offer_nonce.as_slice());
112+
self.nonce_to_invoice_params.lock().unwrap().remove(&key)
113+
}
114+
115+
/// Clears all LSPS2 parameters previously registered via [`Self::register_offer`] and
116+
/// [`Self::register_offer_nonce`].
90117
pub fn clear_registered_offers(&self) {
91118
self.offer_to_invoice_params.lock().unwrap().clear();
119+
self.nonce_to_invoice_params.lock().unwrap().clear();
92120
}
93121

94122
fn registered_lsps2_params(
95123
&self, payment_context: &PaymentContext,
96124
) -> Option<LSPS2Bolt12InvoiceParameters> {
97-
// We intentionally only match `Bolt12Offer` here and not `AsyncBolt12Offer`, as LSPS2
98-
// JIT channels are not applicable to async (always-online) BOLT12 offer flows.
99-
let Bolt12OfferContext { offer_id, .. } = match payment_context {
100-
PaymentContext::Bolt12Offer(context) => context,
101-
_ => return None,
102-
};
103-
104-
self.offer_to_invoice_params.lock().unwrap().get(&offer_id.0).copied()
125+
match payment_context {
126+
PaymentContext::Bolt12Offer(Bolt12OfferContext { offer_id, .. }) => {
127+
self.offer_to_invoice_params.lock().unwrap().get(&offer_id.0).copied()
128+
},
129+
PaymentContext::AsyncBolt12Offer(AsyncBolt12OfferContext { offer_nonce }) => {
130+
let mut key = [0u8; Nonce::LENGTH];
131+
key.copy_from_slice(offer_nonce.as_slice());
132+
self.nonce_to_invoice_params.lock().unwrap().get(&key).copied()
133+
},
134+
_ => None,
135+
}
105136
}
106137
}
107138

@@ -212,14 +243,18 @@ impl<R: Router, MR: MessageRouter, ES: EntropySource + Send + Sync> MessageRoute
212243
// is only used for routing InvoiceRequests, not for payment interception.
213244
let peers = match &context {
214245
MessageContext::Offers(OffersContext::InvoiceRequest { .. }) => {
215-
let params = self.offer_to_invoice_params.lock().unwrap();
246+
let offer_params = self.offer_to_invoice_params.lock().unwrap();
247+
let nonce_params = self.nonce_to_invoice_params.lock().unwrap();
216248
peers
217249
.into_iter()
218250
.map(|mut peer| {
219-
if let Some(p) =
220-
params.values().find(|p| p.counterparty_node_id == peer.node_id)
221-
{
222-
peer.short_channel_id = Some(p.intercept_scid);
251+
let scid = offer_params
252+
.values()
253+
.chain(nonce_params.values())
254+
.find(|p| p.counterparty_node_id == peer.node_id)
255+
.map(|p| p.intercept_scid);
256+
if let Some(scid) = scid {
257+
peer.short_channel_id = Some(scid);
223258
}
224259
peer
225260
})

0 commit comments

Comments
 (0)