Skip to content

Commit 3a0d0ff

Browse files
committed
Provide an InvoiceGenerated event for offers
When responding to an InvoiceRequest for an Offer, provide an event when an invoice has been generated. This allows event handler to know when an inbound payment may occur along with information from the invoice such as metadata, payer_id, and payment_hash.
1 parent 1be1630 commit 3a0d0ff

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed

lightning/src/events/mod.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::ln::features::ChannelTypeFeatures;
2525
use crate::ln::msgs;
2626
use crate::ln::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret};
2727
use crate::chain::transaction;
28+
use crate::offers::invoice::Bolt12Invoice;
2829
use crate::routing::gossip::NetworkUpdate;
2930
use crate::util::errors::APIError;
3031
use crate::util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReadable, Readable, RequiredWrapper, UpgradableRequired, WithoutLength};
@@ -582,6 +583,39 @@ pub enum Event {
582583
/// The `payment_id` to have been associated with payment for the requested invoice.
583584
payment_id: PaymentId,
584585
},
586+
/// Indicates that a [`Bolt12Invoice`] was generated in response to an [`InvoiceRequest`] and is
587+
/// being prepared to be sent via an [`OnionMessage`].
588+
///
589+
/// Note that this doesn't necessarily mean that the invoice was sent and -- once sent -- it may
590+
/// never reach its destination because of the unreliable nature of onion messages. Any of the
591+
/// following scenarios may occur.
592+
/// - Dropped by a node along the path to the destination
593+
/// - Dropped upon node restart prior to being sent
594+
/// - Buffered waiting to be sent by [`PeerManager`]
595+
/// - Buffered waiting for an [`Event::ConnectionNeeded`] to be handled and peer connected
596+
/// - Dropped waiting too long for such a peer connection
597+
/// - Dropped because the onion message buffer was full
598+
/// - Dropped because the [`MessageRouter`] failed to find an [`OnionMessagePath`] to the
599+
/// destination
600+
///
601+
/// Thus, this event is largely for informational purposes as the corresponding [`Offer`] and
602+
/// [`InvoiceRequest`] fields are accessible from the invoice. In particular:
603+
/// - [`Bolt12Invoice::metadata`] can help identify the corresponding [`Offer`]
604+
/// - A common [`Bolt12Invoice::payer_id`] indicates the payer sent multiple requests for
605+
/// redundancy, though in that case the [`Bolt12Invoice::payment_hash`] used may be different.
606+
///
607+
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
608+
/// [`OnionMessage`]: crate::ln::msgs::OnionMessage
609+
/// [`PeerManager`]: crate::ln::peer_handler::PeerManager
610+
/// [`MessageRouter`]: crate::onion_message::messenger::MessageRouter
611+
/// [`OnionMessagePath`]: crate::onion_message::messenger::OnionMessagePath
612+
/// [`Offer`]: crate::offers::offer::Offer
613+
InvoiceGenerated {
614+
/// An invoice that was generated in response to an [`InvoiceRequest`].
615+
///
616+
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
617+
invoice: Bolt12Invoice,
618+
},
585619
/// Indicates an outbound payment we made succeeded (i.e. it made it all the way to its target
586620
/// and we got back the payment preimage for it).
587621
///
@@ -1262,6 +1296,12 @@ impl Writeable for Event {
12621296
35u8.write(writer)?;
12631297
// Never write ConnectionNeeded events as buffered onion messages aren't serialized.
12641298
},
1299+
&Event::InvoiceGenerated { ref invoice } => {
1300+
37u8.write(writer)?;
1301+
write_tlv_fields!(writer, {
1302+
(0, invoice, required),
1303+
})
1304+
},
12651305
// Note that, going forward, all new events must only write data inside of
12661306
// `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write
12671307
// data via `write_tlv_fields`.
@@ -1668,6 +1708,18 @@ impl MaybeReadable for Event {
16681708
},
16691709
// Note that we do not write a length-prefixed TLV for ConnectionNeeded events.
16701710
35u8 => Ok(None),
1711+
37u8 => {
1712+
let f = || {
1713+
let mut invoice_bytes = WithoutLength(Vec::new());
1714+
read_tlv_fields!(reader, {
1715+
(0, invoice_bytes, required),
1716+
});
1717+
let invoice = Bolt12Invoice::try_from(invoice_bytes.0)
1718+
.map_err(|_| msgs::DecodeError::InvalidValue)?;
1719+
Ok(Some(Event::InvoiceGenerated { invoice }))
1720+
};
1721+
f()
1722+
},
16711723
// Versions prior to 0.0.100 did not ignore odd types, instead returning InvalidValue.
16721724
// Version 0.0.100 failed to properly ignore odd types, possibly resulting in corrupt
16731725
// reads.

lightning/src/ln/channelmanager.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9486,7 +9486,11 @@ where
94869486
};
94879487

94889488
match response {
9489-
Ok(invoice) => Some(OffersMessage::Invoice(invoice)),
9489+
Ok(invoice) => {
9490+
let event = Event::InvoiceGenerated { invoice: invoice.clone() };
9491+
self.pending_events.lock().unwrap().push_back((event, None));
9492+
Some(OffersMessage::Invoice(invoice))
9493+
},
94909494
Err(error) => Some(OffersMessage::InvoiceError(error.into())),
94919495
}
94929496
},

lightning/src/ln/offers_tests.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,24 @@ fn extract_invoice_error<'a, 'b, 'c>(
211211
}
212212
}
213213

214+
fn expect_invoice_generated_event<'a, 'b, 'c, 'd>(
215+
node: &'a Node<'b, 'c, 'd>, expected_invoice: &Bolt12Invoice
216+
) {
217+
use crate::io::Cursor;
218+
use crate::util::ser::MaybeReadable;
219+
use crate::util::ser::Writeable;
220+
221+
let event = get_event!(node, Event::InvoiceGenerated);
222+
match &event {
223+
Event::InvoiceGenerated { invoice } => assert_eq!(invoice, expected_invoice),
224+
_ => panic!(),
225+
}
226+
227+
let mut bytes = Vec::new();
228+
event.write(&mut bytes).unwrap();
229+
assert_eq!(Some(event), MaybeReadable::read(&mut Cursor::new(&bytes)).unwrap());
230+
}
231+
214232
/// Checks that blinded paths without Tor-only nodes are preferred when constructing an offer.
215233
#[test]
216234
fn prefers_non_tor_nodes_in_blinded_paths() {
@@ -403,6 +421,8 @@ fn creates_and_pays_for_offer_using_two_hop_blinded_path() {
403421
david.onion_messenger.handle_onion_message(&charlie_id, &onion_message);
404422

405423
let invoice = extract_invoice(david, &onion_message);
424+
expect_invoice_generated_event(alice, &invoice);
425+
406426
assert_eq!(invoice.amount_msats(), 10_000_000);
407427
assert_ne!(invoice.signing_pubkey(), alice_id);
408428
assert!(!invoice.payment_paths().is_empty());
@@ -540,6 +560,8 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() {
540560
bob.onion_messenger.handle_onion_message(&alice_id, &onion_message);
541561

542562
let invoice = extract_invoice(bob, &onion_message);
563+
expect_invoice_generated_event(alice, &invoice);
564+
543565
assert_eq!(invoice.amount_msats(), 10_000_000);
544566
assert_ne!(invoice.signing_pubkey(), alice_id);
545567
assert!(!invoice.payment_paths().is_empty());
@@ -644,6 +666,8 @@ fn pays_for_offer_without_blinded_paths() {
644666
bob.onion_messenger.handle_onion_message(&alice_id, &onion_message);
645667

646668
let invoice = extract_invoice(bob, &onion_message);
669+
expect_invoice_generated_event(alice, &invoice);
670+
647671
route_bolt12_payment(bob, &[alice], &invoice);
648672
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
649673

0 commit comments

Comments
 (0)