Skip to content

Commit de2956e

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 7f17b9f commit de2956e

File tree

4 files changed

+173
-82
lines changed

4 files changed

+173
-82
lines changed

lightning/src/offers/invoice.rs

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures, InvoiceRequ
117117
use crate::ln::inbound_payment::{ExpandedKey, IV_LEN};
118118
use crate::ln::msgs::DecodeError;
119119
use crate::offers::invoice_macros::{invoice_accessors_common, invoice_builder_methods_common};
120-
use crate::offers::invoice_request::{INVOICE_REQUEST_PAYER_ID_TYPE, INVOICE_REQUEST_TYPES, IV_BYTES as INVOICE_REQUEST_IV_BYTES, InvoiceRequest, InvoiceRequestContents, InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef};
120+
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};
121121
use crate::offers::merkle::{SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, TlvStream, self};
122122
use crate::offers::nonce::Nonce;
123123
use crate::offers::offer::{Amount, EXPERIMENTAL_OFFER_TYPES, ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, OFFER_TYPES, OfferTlvStream, OfferTlvStreamRef, Quantity};
@@ -484,7 +484,8 @@ where
484484
impl UnsignedBolt12Invoice {
485485
fn new(invreq_bytes: &[u8], contents: InvoiceContents) -> Self {
486486
const NON_EXPERIMENTAL_TYPES: core::ops::Range<u64> = 0..INVOICE_REQUEST_TYPES.end;
487-
const EXPERIMENTAL_TYPES: core::ops::Range<u64> = EXPERIMENTAL_OFFER_TYPES;
487+
const EXPERIMENTAL_TYPES: core::ops::Range<u64> =
488+
EXPERIMENTAL_OFFER_TYPES.start..EXPERIMENTAL_INVOICE_REQUEST_TYPES.end;
488489

489490
let mut bytes = Vec::new();
490491

@@ -495,7 +496,7 @@ impl UnsignedBolt12Invoice {
495496
record.write(&mut bytes).unwrap();
496497
}
497498

498-
let (_, _, _, invoice_tlv_stream, _) = contents.as_tlv_stream();
499+
let (_, _, _, invoice_tlv_stream, _, _) = contents.as_tlv_stream();
499500
invoice_tlv_stream.write(&mut bytes).unwrap();
500501

501502
let mut experimental_bytes = Vec::new();
@@ -860,14 +861,15 @@ impl Bolt12Invoice {
860861
pub(crate) fn as_tlv_stream(&self) -> FullInvoiceTlvStreamRef {
861862
let (
862863
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
863-
experimental_offer_tlv_stream,
864+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
864865
) = self.contents.as_tlv_stream();
865866
let signature_tlv_stream = SignatureTlvStreamRef {
866867
signature: Some(&self.signature),
867868
};
868869
(
869870
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
870871
signature_tlv_stream, experimental_offer_tlv_stream,
872+
experimental_invoice_request_tlv_stream,
871873
)
872874
}
873875

@@ -1101,7 +1103,8 @@ impl InvoiceContents {
11011103
&self, bytes: &[u8], metadata: &Metadata, key: &ExpandedKey, iv_bytes: &[u8; IV_LEN],
11021104
secp_ctx: &Secp256k1<T>,
11031105
) -> Result<PaymentId, ()> {
1104-
const EXPERIMENTAL_TYPES: core::ops::Range<u64> = EXPERIMENTAL_OFFER_TYPES;
1106+
const EXPERIMENTAL_TYPES: core::ops::Range<u64> =
1107+
EXPERIMENTAL_OFFER_TYPES.start..EXPERIMENTAL_INVOICE_REQUEST_TYPES.end;
11051108

11061109
let offer_records = TlvStream::new(bytes).range(OFFER_TYPES);
11071110
let invreq_records = TlvStream::new(bytes).range(INVOICE_REQUEST_TYPES).filter(|record| {
@@ -1121,13 +1124,15 @@ impl InvoiceContents {
11211124
}
11221125

11231126
fn as_tlv_stream(&self) -> PartialInvoiceTlvStreamRef {
1124-
let (payer, offer, invoice_request, experimental_offer) = match self {
1127+
let (
1128+
payer, offer, invoice_request, experimental_offer, experimental_invoice_request,
1129+
) = match self {
11251130
InvoiceContents::ForOffer { invoice_request, .. } => invoice_request.as_tlv_stream(),
11261131
InvoiceContents::ForRefund { refund, .. } => refund.as_tlv_stream(),
11271132
};
11281133
let invoice = self.fields().as_tlv_stream();
11291134

1130-
(payer, offer, invoice_request, invoice, experimental_offer)
1135+
(payer, offer, invoice_request, invoice, experimental_offer, experimental_invoice_request)
11311136
}
11321137
}
11331138

@@ -1230,12 +1235,12 @@ impl TryFrom<Vec<u8>> for UnsignedBolt12Invoice {
12301235
let ParsedMessage { mut bytes, tlv_stream } = invoice;
12311236
let (
12321237
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1233-
experimental_offer_tlv_stream,
1238+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
12341239
) = tlv_stream;
12351240
let contents = InvoiceContents::try_from(
12361241
(
12371242
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1238-
experimental_offer_tlv_stream,
1243+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
12391244
)
12401245
)?;
12411246

@@ -1337,7 +1342,7 @@ impl_writeable!(FallbackAddress, { version, program });
13371342

13381343
type FullInvoiceTlvStream =(
13391344
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream, SignatureTlvStream,
1340-
ExperimentalOfferTlvStream,
1345+
ExperimentalOfferTlvStream, ExperimentalInvoiceRequestTlvStream,
13411346
);
13421347

13431348
type FullInvoiceTlvStreamRef<'a> = (
@@ -1347,6 +1352,7 @@ type FullInvoiceTlvStreamRef<'a> = (
13471352
InvoiceTlvStreamRef<'a>,
13481353
SignatureTlvStreamRef<'a>,
13491354
ExperimentalOfferTlvStreamRef,
1355+
ExperimentalInvoiceRequestTlvStreamRef,
13501356
);
13511357

13521358
impl SeekReadable for FullInvoiceTlvStream {
@@ -1357,14 +1363,20 @@ impl SeekReadable for FullInvoiceTlvStream {
13571363
let invoice = SeekReadable::read(r)?;
13581364
let signature = SeekReadable::read(r)?;
13591365
let experimental_offer = SeekReadable::read(r)?;
1366+
let experimental_invoice_request = SeekReadable::read(r)?;
13601367

1361-
Ok((payer, offer, invoice_request, invoice, signature, experimental_offer))
1368+
Ok(
1369+
(
1370+
payer, offer, invoice_request, invoice, signature, experimental_offer,
1371+
experimental_invoice_request,
1372+
)
1373+
)
13621374
}
13631375
}
13641376

13651377
type PartialInvoiceTlvStream = (
13661378
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream,
1367-
ExperimentalOfferTlvStream,
1379+
ExperimentalOfferTlvStream, ExperimentalInvoiceRequestTlvStream,
13681380
);
13691381

13701382
type PartialInvoiceTlvStreamRef<'a> = (
@@ -1373,6 +1385,7 @@ type PartialInvoiceTlvStreamRef<'a> = (
13731385
InvoiceRequestTlvStreamRef<'a>,
13741386
InvoiceTlvStreamRef<'a>,
13751387
ExperimentalOfferTlvStreamRef,
1388+
ExperimentalInvoiceRequestTlvStreamRef,
13761389
);
13771390

13781391
impl SeekReadable for PartialInvoiceTlvStream {
@@ -1382,8 +1395,14 @@ impl SeekReadable for PartialInvoiceTlvStream {
13821395
let invoice_request = SeekReadable::read(r)?;
13831396
let invoice = SeekReadable::read(r)?;
13841397
let experimental_offer = SeekReadable::read(r)?;
1398+
let experimental_invoice_request = SeekReadable::read(r)?;
13851399

1386-
Ok((payer, offer, invoice_request, invoice, experimental_offer))
1400+
Ok(
1401+
(
1402+
payer, offer, invoice_request, invoice, experimental_offer,
1403+
experimental_invoice_request,
1404+
)
1405+
)
13871406
}
13881407
}
13891408

@@ -1396,11 +1415,12 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
13961415
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
13971416
SignatureTlvStream { signature },
13981417
experimental_offer_tlv_stream,
1418+
experimental_invoice_request_tlv_stream,
13991419
) = tlv_stream;
14001420
let contents = InvoiceContents::try_from(
14011421
(
14021422
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1403-
experimental_offer_tlv_stream,
1423+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
14041424
)
14051425
)?;
14061426

@@ -1428,6 +1448,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14281448
features, node_id, message_paths,
14291449
},
14301450
experimental_offer_tlv_stream,
1451+
experimental_invoice_request_tlv_stream,
14311452
) = tlv_stream;
14321453

14331454
if message_paths.is_some() { return Err(Bolt12SemanticError::UnexpectedPaths) }
@@ -1462,15 +1483,15 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14621483
let refund = RefundContents::try_from(
14631484
(
14641485
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1465-
experimental_offer_tlv_stream,
1486+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
14661487
)
14671488
)?;
14681489
Ok(InvoiceContents::ForRefund { refund, fields })
14691490
} else {
14701491
let invoice_request = InvoiceRequestContents::try_from(
14711492
(
14721493
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1473-
experimental_offer_tlv_stream,
1494+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
14741495
)
14751496
)?;
14761497
Ok(InvoiceContents::ForOffer { invoice_request, fields })
@@ -1537,7 +1558,7 @@ mod tests {
15371558
use crate::ln::features::{Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures};
15381559
use crate::ln::inbound_payment::ExpandedKey;
15391560
use crate::ln::msgs::DecodeError;
1540-
use crate::offers::invoice_request::InvoiceRequestTlvStreamRef;
1561+
use crate::offers::invoice_request::{ExperimentalInvoiceRequestTlvStreamRef, InvoiceRequestTlvStreamRef};
15411562
use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self};
15421563
use crate::offers::nonce::Nonce;
15431564
use crate::offers::offer::{Amount, ExperimentalOfferTlvStreamRef, OfferTlvStreamRef, Quantity};
@@ -1711,6 +1732,7 @@ mod tests {
17111732
ExperimentalOfferTlvStreamRef {
17121733
experimental_foo: None,
17131734
},
1735+
ExperimentalInvoiceRequestTlvStreamRef {},
17141736
),
17151737
);
17161738

@@ -1807,6 +1829,7 @@ mod tests {
18071829
ExperimentalOfferTlvStreamRef {
18081830
experimental_foo: None,
18091831
},
1832+
ExperimentalInvoiceRequestTlvStreamRef {},
18101833
),
18111834
);
18121835

@@ -2005,7 +2028,7 @@ mod tests {
20052028
.relative_expiry(one_hour.as_secs() as u32)
20062029
.build().unwrap()
20072030
.sign(recipient_sign).unwrap();
2008-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2031+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20092032
#[cfg(feature = "std")]
20102033
assert!(!invoice.is_expired());
20112034
assert_eq!(invoice.relative_expiry(), one_hour);
@@ -2021,7 +2044,7 @@ mod tests {
20212044
.relative_expiry(one_hour.as_secs() as u32 - 1)
20222045
.build().unwrap()
20232046
.sign(recipient_sign).unwrap();
2024-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2047+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20252048
#[cfg(feature = "std")]
20262049
assert!(invoice.is_expired());
20272050
assert_eq!(invoice.relative_expiry(), one_hour - Duration::from_secs(1));
@@ -2040,7 +2063,7 @@ mod tests {
20402063
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
20412064
.build().unwrap()
20422065
.sign(recipient_sign).unwrap();
2043-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2066+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20442067
assert_eq!(invoice.amount_msats(), 1001);
20452068
assert_eq!(tlv_stream.amount, Some(1001));
20462069
}
@@ -2058,7 +2081,7 @@ mod tests {
20582081
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
20592082
.build().unwrap()
20602083
.sign(recipient_sign).unwrap();
2061-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2084+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20622085
assert_eq!(invoice.amount_msats(), 2000);
20632086
assert_eq!(tlv_stream.amount, Some(2000));
20642087

@@ -2096,7 +2119,7 @@ mod tests {
20962119
.fallback_v1_p2tr_tweaked(&tweaked_pubkey)
20972120
.build().unwrap()
20982121
.sign(recipient_sign).unwrap();
2099-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2122+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
21002123
assert_eq!(
21012124
invoice.fallbacks(),
21022125
vec![
@@ -2139,7 +2162,7 @@ mod tests {
21392162
.allow_mpp()
21402163
.build().unwrap()
21412164
.sign(recipient_sign).unwrap();
2142-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2165+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
21432166
assert_eq!(invoice.invoice_features(), &features);
21442167
assert_eq!(tlv_stream.features, Some(&features));
21452168
}

0 commit comments

Comments
 (0)