Support encoding invreqs in outbound onion payloads

Per BOLTs PR 1149, when paying a static invoice we need to include our original
invoice request in the HTLC onion since the recipient wouldn't have received it
previously.

We use an experimental TLV type for this new onion payload field, since the
spec is still not merged in the BOLTs.
This commit is contained in:
Valentine Wallace 2024-06-28 11:40:53 -04:00
parent 639446ad63
commit a80af56af7
No known key found for this signature in database
GPG key ID: FD3E106A2CE099B4
4 changed files with 11 additions and 2 deletions

View file

@ -184,6 +184,7 @@ fn one_hop_blinded_path_with_custom_tlv() {
encrypted_tlvs: &blinded_path.blinded_hops()[0].encrypted_payload,
intro_node_blinding_point: Some(blinded_path.blinding_point()),
keysend_preimage: None,
invoice_request: None,
custom_tlvs: &Vec::new()
}.serialized_length();
let max_custom_tlv_len = 1300

View file

@ -1747,6 +1747,7 @@ pub struct FinalOnionHopData {
mod fuzzy_internal_msgs {
use bitcoin::secp256k1::PublicKey;
use crate::blinded_path::payment::{BlindedPaymentPath, PaymentConstraints, PaymentContext, PaymentRelay};
use crate::offers::invoice_request::InvoiceRequest;
use crate::types::payment::{PaymentPreimage, PaymentSecret};
use crate::types::features::{BlindedHopFeatures, Bolt12InvoiceFeatures};
use super::{FinalOnionHopData, TrampolineOnionPacket};
@ -1827,6 +1828,7 @@ mod fuzzy_internal_msgs {
intro_node_blinding_point: Option<PublicKey>, // Set if the introduction node of the blinded path is the final node
keysend_preimage: Option<PaymentPreimage>,
custom_tlvs: &'a Vec<(u64, Vec<u8>)>,
invoice_request: Option<&'a InvoiceRequest>,
}
}
@ -2760,13 +2762,17 @@ impl<'a> Writeable for OutboundOnionPayload<'a> {
},
Self::BlindedReceive {
sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, encrypted_tlvs,
intro_node_blinding_point, keysend_preimage, ref custom_tlvs,
intro_node_blinding_point, keysend_preimage, ref invoice_request, ref custom_tlvs,
} => {
// We need to update [`ln::outbound_payment::RecipientOnionFields::with_custom_tlvs`]
// to reject any reserved types in the experimental range if new ones are ever
// standardized.
let invoice_request_tlv = invoice_request.map(|invreq| (77_777, invreq.encode())); // TODO: update TLV type once the async payments spec is merged
let keysend_tlv = keysend_preimage.map(|preimage| (5482373484, preimage.encode()));
let mut custom_tlvs: Vec<&(u64, Vec<u8>)> = custom_tlvs.iter().chain(keysend_tlv.iter()).collect();
let mut custom_tlvs: Vec<&(u64, Vec<u8>)> = custom_tlvs.iter()
.chain(invoice_request_tlv.iter())
.chain(keysend_tlv.iter())
.collect();
custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ);
_encode_varint_length_prefixed_tlv!(w, {
(2, HighZeroBytesDroppedBigSize(*sender_intended_htlc_amt_msat), required),

View file

@ -262,6 +262,7 @@ where
encrypted_tlvs: &blinded_hop.encrypted_payload,
intro_node_blinding_point: blinding_point.take(),
keysend_preimage: *keysend_preimage,
invoice_request: None,
custom_tlvs: &recipient_onion.custom_tlvs,
},
);

View file

@ -641,6 +641,7 @@ impl RecipientOnionFields {
for (typ, _) in custom_tlvs.iter() {
if *typ < 1 << 16 { return Err(()); }
if *typ == 5482373484 { return Err(()); } // keysend
if *typ == 77_777 { return Err(()); } // invoice requests for async payments
match prev_type {
Some(prev) if prev >= *typ => return Err(()),
_ => {},