Remove now-unused ServeStaticInvoice::invoice_id
What changed, and why it matters
This commit is a routine cleanup of an internal messaging protocol. It removes a now-unused field called invoice_id and standardizes on a different identifier (invoice_slot) for looking up stored invoices. There is no security fix here; it is purely a simplification of the code and data structures.
No security action required. Treat as normal code hygiene; review for API compatibility if downstream users depend on the removed invoice_id field.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change removes the invoice_id: u128 field from the ServeStaticInvoice async-payments context and from the PersistStaticInvoice event. Serialization is updated to drop the old invoice_id TLV field and keep only invoice_slot. handle_offer_paths_request no longer needs an EntropySource because it no longer generates a random invoice_id. Tests are updated to assert uniqueness of invoice_slot instead of invoice_id. This is a follow-up refactor after a previous transition to slot-based invoice lookup.
Changed components
lightning/src/blinded_path/message.rslightning/src/events/mod.rslightning/src/ln/channelmanager.rslightning/src/offers/flow.rslightning/src/ln/async_payments_tests.rsInspect captured patch +21 / −51
diff --git a/lightning/src/blinded_path/message.rs b/lightning/src/blinded_path/message.rs
index 4e58f66..954247d 100644
--- a/lightning/src/blinded_path/message.rs
+++ b/lightning/src/blinded_path/message.rs
@@ -474,7 +474,7 @@ pub enum AsyncPaymentsContext {
/// An identifier for the async recipient that is requesting that a [`StaticInvoice`] be served
/// on their behalf.
///
- /// Useful when surfaced alongside the below `invoice_id` when payers send an
+ /// Useful when surfaced alongside the below `invoice_slot` when payers send an
/// [`InvoiceRequest`], to pull the specific static invoice from the database.
///
/// Also useful to rate limit the invoices being persisted on behalf of a particular recipient.
@@ -485,13 +485,6 @@ pub enum AsyncPaymentsContext {
/// [`StaticInvoice`]: crate::offers::static_invoice::StaticInvoice
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
recipient_id: Vec<u8>,
- /// A random identifier for the specific [`StaticInvoice`] that the recipient is requesting be
- /// served on their behalf. Useful when surfaced alongside the above `recipient_id` when payers
- /// send an [`InvoiceRequest`], to pull the specific static invoice from the database.
- ///
- /// [`StaticInvoice`]: crate::offers::static_invoice::StaticInvoice
- /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
- invoice_id: u128,
/// The slot number for the specific [`StaticInvoice`] that the recipient is requesting be
/// served on their behalf. Useful when surfaced alongside the above `recipient_id` when payers
/// send an [`InvoiceRequest`], to pull the specific static invoice from the database. This id
@@ -600,9 +593,8 @@ impl_writeable_tlv_based_enum!(AsyncPaymentsContext,
},
(5, ServeStaticInvoice) => {
(0, recipient_id, required),
- (2, invoice_id, required),
+ (2, invoice_slot, required),
(4, path_absolute_expiry, required),
- (6, invoice_slot, required),
},
);
diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs
index eaf9e0d..30c9282 100644
--- a/lightning/src/events/mod.rs
+++ b/lightning/src/events/mod.rs
@@ -1661,18 +1661,11 @@ pub enum Event {
/// [`ChannelManager::blinded_paths_for_async_recipient`].
///
/// When an [`Event::StaticInvoiceRequested`] comes in for the invoice, this id will be surfaced
- /// and can be used alongside the `invoice_id` to retrieve the invoice from the database.
+ /// and can be used alongside the `invoice_slot` to retrieve the invoice from the database.
///
///[`ChannelManager::blinded_paths_for_async_recipient`]: crate::ln::channelmanager::ChannelManager::blinded_paths_for_async_recipient
recipient_id: Vec<u8>,
- /// A random identifier for the invoice. When an [`Event::StaticInvoiceRequested`] comes in for
- /// the invoice, this id will be surfaced and can be used alongside the `recipient_id` to
- /// retrieve the invoice from the database.
- ///
- /// Note that this id will remain the same for all invoice updates corresponding to a particular
- /// offer that the recipient has cached.
- invoice_id: u128,
- /// Once the [`StaticInvoice`], `invoice_slot` and `invoice_id` are persisted,
+ /// Once the [`StaticInvoice`] and `invoice_slot` are persisted,
/// [`ChannelManager::static_invoice_persisted`] should be called with this responder to confirm
/// to the recipient that their [`Offer`] is ready to be used for async payments.
///
diff --git a/lightning/src/ln/async_payments_tests.rs b/lightning/src/ln/async_payments_tests.rs
index 2903476..2fa5dee 100644
--- a/lightning/src/ln/async_payments_tests.rs
+++ b/lightning/src/ln/async_payments_tests.rs
@@ -66,7 +66,6 @@ use core::time::Duration;
struct StaticInvoiceServerFlowResult {
invoice: StaticInvoice,
invoice_slot: u16,
- invoice_id: u128,
// Returning messages that were sent along the way allows us to test handling duplicate messages.
offer_paths_request: msgs::OnionMessage,
@@ -148,16 +147,15 @@ fn pass_static_invoice_server_messages(
// that the static invoice should be persisted.
let mut events = server.node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
- let (invoice, invoice_slot, invoice_id, ack_path) = match events.pop().unwrap() {
+ let (invoice, invoice_slot, ack_path) = match events.pop().unwrap() {
Event::PersistStaticInvoice {
invoice,
invoice_persisted_path,
recipient_id: ev_id,
invoice_slot,
- invoice_id,
} => {
assert_eq!(recipient_id, ev_id);
- (invoice, invoice_slot, invoice_id, invoice_persisted_path)
+ (invoice, invoice_slot, invoice_persisted_path)
},
_ => panic!(),
};
@@ -183,7 +181,6 @@ fn pass_static_invoice_server_messages(
static_invoice_persisted_message: invoice_persisted_om,
invoice,
invoice_slot,
- invoice_id,
}
}
@@ -1626,13 +1623,13 @@ fn limit_serve_static_invoice_requests() {
// Build the target number of offers interactively with the static invoice server.
let mut offer_paths_req = None;
- let mut invoice_ids = new_hash_set();
+ let mut invoice_slots = new_hash_set();
for expected_inv_slot in 0..TEST_MAX_CACHED_OFFERS_TARGET {
let flow_res = pass_static_invoice_server_messages(server, recipient, recipient_id.clone());
assert_eq!(flow_res.invoice_slot, expected_inv_slot as u16);
offer_paths_req = Some(flow_res.offer_paths_request);
- invoice_ids.insert(flow_res.invoice_id);
+ invoice_slots.insert(flow_res.invoice_slot);
// Trigger a cache refresh
recipient.node.timer_tick_occurred();
@@ -1641,8 +1638,8 @@ fn limit_serve_static_invoice_requests() {
recipient.node.flow.test_get_async_receive_offers().len(),
TEST_MAX_CACHED_OFFERS_TARGET
);
- // Check that all invoice ids are unique.
- assert_eq!(invoice_ids.len(), TEST_MAX_CACHED_OFFERS_TARGET);
+ // Check that all invoice slot numbers are unique.
+ assert_eq!(invoice_slots.len(), TEST_MAX_CACHED_OFFERS_TARGET);
// Force allowing more offer paths request attempts so we can check that the recipient will not
// attempt to build any further offers.
@@ -1822,16 +1819,15 @@ fn refresh_static_invoices_for_used_offers() {
Event::PersistStaticInvoice {
invoice,
invoice_slot,
- invoice_id,
invoice_persisted_path,
recipient_id: ev_id,
} => {
assert_ne!(original_invoice, invoice);
assert_eq!(recipient_id, ev_id);
assert_eq!(invoice_slot, flow_res.invoice_slot);
- // When we update the invoice corresponding to a specific offer, the invoice_id stays the
+ // When we update the invoice corresponding to a specific offer, the invoice_slot stays the
// same.
- assert_eq!(invoice_id, flow_res.invoice_id);
+ assert_eq!(invoice_slot, flow_res.invoice_slot);
(invoice, invoice_persisted_path)
},
_ => panic!(),
diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index abd0716..352bd90 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -14445,9 +14445,8 @@ where
responder: Option<Responder>,
) -> Option<(OfferPaths, ResponseInstruction)> {
let peers = self.get_peers_for_blinded_path();
- let entropy = &*self.entropy_source;
let (message, reply_path_context) =
- match self.flow.handle_offer_paths_request(&message, context, peers, entropy) {
+ match self.flow.handle_offer_paths_request(&message, context, peers) {
Some(msg) => msg,
None => return None,
};
@@ -14490,9 +14489,9 @@ where
None => return,
};
- let (recipient_id, invoice_slot, invoice_id) =
+ let (recipient_id, invoice_slot) =
match self.flow.verify_serve_static_invoice_message(&message, context) {
- Ok((recipient_id, inv_slot, inv_id)) => (recipient_id, inv_slot, inv_id),
+ Ok((recipient_id, inv_slot)) => (recipient_id, inv_slot),
Err(()) => return,
};
@@ -14502,7 +14501,6 @@ where
invoice: message.invoice,
invoice_slot,
recipient_id,
- invoice_id,
invoice_persisted_path: responder,
},
None,
diff --git a/lightning/src/offers/flow.rs b/lightning/src/offers/flow.rs
index 519e459..38f472b 100644
--- a/lightning/src/offers/flow.rs
+++ b/lightning/src/offers/flow.rs
@@ -1371,13 +1371,10 @@ where
/// Handles an incoming [`OfferPathsRequest`] onion message from an often-offline recipient who
/// wants us (the static invoice server) to serve [`StaticInvoice`]s to payers on their behalf.
/// Sends out [`OfferPaths`] onion messages in response.
- pub fn handle_offer_paths_request<ES: Deref>(
+ pub fn handle_offer_paths_request(
&self, request: &OfferPathsRequest, context: AsyncPaymentsContext,
- peers: Vec<MessageForwardNode>, entropy_source: ES,
- ) -> Option<(OfferPaths, MessageContext)>
- where
- ES::Target: EntropySource,
- {
+ peers: Vec<MessageForwardNode>,
+ ) -> Option<(OfferPaths, MessageContext)> {
let duration_since_epoch = self.duration_since_epoch();
let recipient_id = match context {
@@ -1390,10 +1387,6 @@ where
_ => return None,
};
- let mut random_bytes = [0u8; 16];
- random_bytes.copy_from_slice(&entropy_source.get_secure_random_bytes()[..16]);
- let invoice_id = u128::from_be_bytes(random_bytes);
-
// Create the blinded paths that will be included in the async recipient's offer.
let (offer_paths, paths_expiry) = {
let path_absolute_expiry =
@@ -1418,7 +1411,6 @@ where
duration_since_epoch.saturating_add(DEFAULT_ASYNC_RECEIVE_OFFER_EXPIRY);
MessageContext::AsyncPayments(AsyncPaymentsContext::ServeStaticInvoice {
recipient_id,
- invoice_id,
invoice_slot: request.invoice_slot,
path_absolute_expiry,
})
@@ -1578,7 +1570,7 @@ where
/// wants us as a static invoice server to serve the [`ServeStaticInvoice::invoice`] to payers on
/// their behalf.
///
- /// On success, returns `(recipient_id, invoice_id)` for use in persisting and later retrieving
+ /// On success, returns `(recipient_id, invoice_slot)` for use in persisting and later retrieving
/// the static invoice from the database.
///
/// Errors if the [`ServeStaticInvoice::invoice`] is expired or larger than
@@ -1587,7 +1579,7 @@ where
/// [`ServeStaticInvoice::invoice`]: crate::onion_message::async_payments::ServeStaticInvoice::invoice
pub fn verify_serve_static_invoice_message(
&self, message: &ServeStaticInvoice, context: AsyncPaymentsContext,
- ) -> Result<(Vec<u8>, u16, u128), ()> {
+ ) -> Result<(Vec<u8>, u16), ()> {
if message.invoice.is_expired_no_std(self.duration_since_epoch()) {
return Err(());
}
@@ -1597,7 +1589,6 @@ where
match context {
AsyncPaymentsContext::ServeStaticInvoice {
recipient_id,
- invoice_id,
invoice_slot,
path_absolute_expiry,
} => {
@@ -1605,7 +1596,7 @@ where
return Err(());
}
- return Ok((recipient_id, invoice_slot, invoice_id));
+ return Ok((recipient_id, invoice_slot));
},
_ => return Err(()),
};
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.