Skip to content

Commit 7109f19

Browse files
committed
Parse experimental invreq TLV records
The BOLT12 spec defines an experimental TLV range that are allowed in invoice_request messages. Allow this range when parsing an invoice request and include those bytes in any invoice. Also include those bytes when verifying that a Bolt12Invoice is for a valid InvoiceRequest.
1 parent 577aaf7 commit 7109f19

File tree

4 files changed

+165
-78
lines changed

4 files changed

+165
-78
lines changed

lightning/src/offers/invoice.rs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ use crate::ln::msgs::DecodeError;
121121
use crate::offers::invoice_macros::{invoice_accessors_common, invoice_builder_methods_common};
122122
#[cfg(test)]
123123
use crate::offers::invoice_macros::invoice_builder_methods_test;
124-
use crate::offers::invoice_request::{EXPERIMENTAL_INVOICE_REQUEST_TYPES, INVOICE_REQUEST_PAYER_ID_TYPE, INVOICE_REQUEST_TYPES, IV_BYTES as INVOICE_REQUEST_IV_BYTES, InvoiceRequest, InvoiceRequestContents, InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef};
124+
use crate::offers::invoice_request::{EXPERIMENTAL_INVOICE_REQUEST_TYPES, ExperimentalInvoiceRequestTlvStream, ExperimentalInvoiceRequestTlvStreamRef, INVOICE_REQUEST_PAYER_ID_TYPE, INVOICE_REQUEST_TYPES, IV_BYTES as INVOICE_REQUEST_IV_BYTES, InvoiceRequest, InvoiceRequestContents, InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef};
125125
use crate::offers::merkle::{SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, TlvStream, self, SIGNATURE_TLV_RECORD_SIZE};
126126
use crate::offers::nonce::Nonce;
127127
use crate::offers::offer::{Amount, EXPERIMENTAL_OFFER_TYPES, ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, OFFER_TYPES, OfferTlvStream, OfferTlvStreamRef, Quantity};
@@ -497,7 +497,7 @@ impl UnsignedBolt12Invoice {
497497
const EXPERIMENTAL_TYPES: core::ops::Range<u64> =
498498
EXPERIMENTAL_OFFER_TYPES.start..EXPERIMENTAL_INVOICE_REQUEST_TYPES.end;
499499

500-
let (_, _, _, invoice_tlv_stream, _) = contents.as_tlv_stream();
500+
let (_, _, _, invoice_tlv_stream, _, _) = contents.as_tlv_stream();
501501

502502
// Allocate enough space for the invoice, which will include:
503503
// - all TLV records from `invreq_bytes` except signatures,
@@ -893,14 +893,15 @@ impl Bolt12Invoice {
893893
pub(crate) fn as_tlv_stream(&self) -> FullInvoiceTlvStreamRef {
894894
let (
895895
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
896-
experimental_offer_tlv_stream,
896+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
897897
) = self.contents.as_tlv_stream();
898898
let signature_tlv_stream = SignatureTlvStreamRef {
899899
signature: Some(&self.signature),
900900
};
901901
(
902902
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
903903
signature_tlv_stream, experimental_offer_tlv_stream,
904+
experimental_invoice_request_tlv_stream,
904905
)
905906
}
906907

@@ -1162,13 +1163,15 @@ impl InvoiceContents {
11621163
}
11631164

11641165
fn as_tlv_stream(&self) -> PartialInvoiceTlvStreamRef {
1165-
let (payer, offer, invoice_request, experimental_offer) = match self {
1166+
let (
1167+
payer, offer, invoice_request, experimental_offer, experimental_invoice_request,
1168+
) = match self {
11661169
InvoiceContents::ForOffer { invoice_request, .. } => invoice_request.as_tlv_stream(),
11671170
InvoiceContents::ForRefund { refund, .. } => refund.as_tlv_stream(),
11681171
};
11691172
let invoice = self.fields().as_tlv_stream();
11701173

1171-
(payer, offer, invoice_request, invoice, experimental_offer)
1174+
(payer, offer, invoice_request, invoice, experimental_offer, experimental_invoice_request)
11721175
}
11731176
}
11741177

@@ -1329,7 +1332,7 @@ impl_writeable!(FallbackAddress, { version, program });
13291332

13301333
type FullInvoiceTlvStream =(
13311334
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream, SignatureTlvStream,
1332-
ExperimentalOfferTlvStream,
1335+
ExperimentalOfferTlvStream, ExperimentalInvoiceRequestTlvStream,
13331336
);
13341337

13351338
type FullInvoiceTlvStreamRef<'a> = (
@@ -1339,6 +1342,7 @@ type FullInvoiceTlvStreamRef<'a> = (
13391342
InvoiceTlvStreamRef<'a>,
13401343
SignatureTlvStreamRef<'a>,
13411344
ExperimentalOfferTlvStreamRef,
1345+
ExperimentalInvoiceRequestTlvStreamRef,
13421346
);
13431347

13441348
impl CursorReadable for FullInvoiceTlvStream {
@@ -1349,14 +1353,20 @@ impl CursorReadable for FullInvoiceTlvStream {
13491353
let invoice = CursorReadable::read(r)?;
13501354
let signature = CursorReadable::read(r)?;
13511355
let experimental_offer = CursorReadable::read(r)?;
1356+
let experimental_invoice_request = CursorReadable::read(r)?;
13521357

1353-
Ok((payer, offer, invoice_request, invoice, signature, experimental_offer))
1358+
Ok(
1359+
(
1360+
payer, offer, invoice_request, invoice, signature, experimental_offer,
1361+
experimental_invoice_request,
1362+
)
1363+
)
13541364
}
13551365
}
13561366

13571367
type PartialInvoiceTlvStream = (
13581368
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream,
1359-
ExperimentalOfferTlvStream,
1369+
ExperimentalOfferTlvStream, ExperimentalInvoiceRequestTlvStream,
13601370
);
13611371

13621372
type PartialInvoiceTlvStreamRef<'a> = (
@@ -1365,6 +1375,7 @@ type PartialInvoiceTlvStreamRef<'a> = (
13651375
InvoiceRequestTlvStreamRef<'a>,
13661376
InvoiceTlvStreamRef<'a>,
13671377
ExperimentalOfferTlvStreamRef,
1378+
ExperimentalInvoiceRequestTlvStreamRef,
13681379
);
13691380

13701381
impl CursorReadable for PartialInvoiceTlvStream {
@@ -1374,8 +1385,14 @@ impl CursorReadable for PartialInvoiceTlvStream {
13741385
let invoice_request = CursorReadable::read(r)?;
13751386
let invoice = CursorReadable::read(r)?;
13761387
let experimental_offer = CursorReadable::read(r)?;
1388+
let experimental_invoice_request = CursorReadable::read(r)?;
13771389

1378-
Ok((payer, offer, invoice_request, invoice, experimental_offer))
1390+
Ok(
1391+
(
1392+
payer, offer, invoice_request, invoice, experimental_offer,
1393+
experimental_invoice_request,
1394+
)
1395+
)
13791396
}
13801397
}
13811398

@@ -1388,11 +1405,12 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
13881405
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
13891406
SignatureTlvStream { signature },
13901407
experimental_offer_tlv_stream,
1408+
experimental_invoice_request_tlv_stream,
13911409
) = tlv_stream;
13921410
let contents = InvoiceContents::try_from(
13931411
(
13941412
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1395-
experimental_offer_tlv_stream,
1413+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
13961414
)
13971415
)?;
13981416

@@ -1420,6 +1438,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14201438
features, node_id, message_paths,
14211439
},
14221440
experimental_offer_tlv_stream,
1441+
experimental_invoice_request_tlv_stream,
14231442
) = tlv_stream;
14241443

14251444
if message_paths.is_some() { return Err(Bolt12SemanticError::UnexpectedPaths) }
@@ -1454,15 +1473,15 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14541473
let refund = RefundContents::try_from(
14551474
(
14561475
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1457-
experimental_offer_tlv_stream,
1476+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
14581477
)
14591478
)?;
14601479
Ok(InvoiceContents::ForRefund { refund, fields })
14611480
} else {
14621481
let invoice_request = InvoiceRequestContents::try_from(
14631482
(
14641483
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1465-
experimental_offer_tlv_stream,
1484+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
14661485
)
14671486
)?;
14681487
Ok(InvoiceContents::ForOffer { invoice_request, fields })
@@ -1535,7 +1554,7 @@ mod tests {
15351554
use crate::ln::features::{Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures};
15361555
use crate::ln::inbound_payment::ExpandedKey;
15371556
use crate::ln::msgs::DecodeError;
1538-
use crate::offers::invoice_request::InvoiceRequestTlvStreamRef;
1557+
use crate::offers::invoice_request::{ExperimentalInvoiceRequestTlvStreamRef, InvoiceRequestTlvStreamRef};
15391558
use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self};
15401559
use crate::offers::nonce::Nonce;
15411560
use crate::offers::offer::{Amount, ExperimentalOfferTlvStreamRef, OfferTlvStreamRef, Quantity};
@@ -1709,6 +1728,7 @@ mod tests {
17091728
ExperimentalOfferTlvStreamRef {
17101729
experimental_foo: None,
17111730
},
1731+
ExperimentalInvoiceRequestTlvStreamRef {},
17121732
),
17131733
);
17141734

@@ -1805,6 +1825,7 @@ mod tests {
18051825
ExperimentalOfferTlvStreamRef {
18061826
experimental_foo: None,
18071827
},
1828+
ExperimentalInvoiceRequestTlvStreamRef {},
18081829
),
18091830
);
18101831

@@ -2001,7 +2022,7 @@ mod tests {
20012022
.relative_expiry(one_hour.as_secs() as u32)
20022023
.build().unwrap()
20032024
.sign(recipient_sign).unwrap();
2004-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2025+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20052026
#[cfg(feature = "std")]
20062027
assert!(!invoice.is_expired());
20072028
assert_eq!(invoice.relative_expiry(), one_hour);
@@ -2017,7 +2038,7 @@ mod tests {
20172038
.relative_expiry(one_hour.as_secs() as u32 - 1)
20182039
.build().unwrap()
20192040
.sign(recipient_sign).unwrap();
2020-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2041+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20212042
#[cfg(feature = "std")]
20222043
assert!(invoice.is_expired());
20232044
assert_eq!(invoice.relative_expiry(), one_hour - Duration::from_secs(1));
@@ -2036,7 +2057,7 @@ mod tests {
20362057
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
20372058
.build().unwrap()
20382059
.sign(recipient_sign).unwrap();
2039-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2060+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20402061
assert_eq!(invoice.amount_msats(), 1001);
20412062
assert_eq!(tlv_stream.amount, Some(1001));
20422063
}
@@ -2054,7 +2075,7 @@ mod tests {
20542075
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
20552076
.build().unwrap()
20562077
.sign(recipient_sign).unwrap();
2057-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2078+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20582079
assert_eq!(invoice.amount_msats(), 2000);
20592080
assert_eq!(tlv_stream.amount, Some(2000));
20602081

@@ -2092,7 +2113,7 @@ mod tests {
20922113
.fallback_v1_p2tr_tweaked(&tweaked_pubkey)
20932114
.build().unwrap()
20942115
.sign(recipient_sign).unwrap();
2095-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2116+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20962117
assert_eq!(
20972118
invoice.fallbacks(),
20982119
vec![
@@ -2135,7 +2156,7 @@ mod tests {
21352156
.allow_mpp()
21362157
.build().unwrap()
21372158
.sign(recipient_sign).unwrap();
2138-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2159+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
21392160
assert_eq!(invoice.invoice_features(), &features);
21402161
assert_eq!(tlv_stream.features, Some(&features));
21412162
}

0 commit comments

Comments
 (0)