Skip to content

Commit 5590bc2

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 62cddb7 commit 5590bc2

File tree

4 files changed

+164
-78
lines changed

4 files changed

+164
-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,
@@ -903,14 +903,15 @@ impl Bolt12Invoice {
903903
pub(crate) fn as_tlv_stream(&self) -> FullInvoiceTlvStreamRef {
904904
let (
905905
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
906-
experimental_offer_tlv_stream,
906+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
907907
) = self.contents.as_tlv_stream();
908908
let signature_tlv_stream = SignatureTlvStreamRef {
909909
signature: Some(&self.signature),
910910
};
911911
(
912912
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
913913
signature_tlv_stream, experimental_offer_tlv_stream,
914+
experimental_invoice_request_tlv_stream,
914915
)
915916
}
916917

@@ -1172,13 +1173,15 @@ impl InvoiceContents {
11721173
}
11731174

11741175
fn as_tlv_stream(&self) -> PartialInvoiceTlvStreamRef {
1175-
let (payer, offer, invoice_request, experimental_offer) = match self {
1176+
let (
1177+
payer, offer, invoice_request, experimental_offer, experimental_invoice_request,
1178+
) = match self {
11761179
InvoiceContents::ForOffer { invoice_request, .. } => invoice_request.as_tlv_stream(),
11771180
InvoiceContents::ForRefund { refund, .. } => refund.as_tlv_stream(),
11781181
};
11791182
let invoice = self.fields().as_tlv_stream();
11801183

1181-
(payer, offer, invoice_request, invoice, experimental_offer)
1184+
(payer, offer, invoice_request, invoice, experimental_offer, experimental_invoice_request)
11821185
}
11831186
}
11841187

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

13401343
type FullInvoiceTlvStream =(
13411344
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream, SignatureTlvStream,
1342-
ExperimentalOfferTlvStream,
1345+
ExperimentalOfferTlvStream, ExperimentalInvoiceRequestTlvStream,
13431346
);
13441347

13451348
type FullInvoiceTlvStreamRef<'a> = (
@@ -1349,6 +1352,7 @@ type FullInvoiceTlvStreamRef<'a> = (
13491352
InvoiceTlvStreamRef<'a>,
13501353
SignatureTlvStreamRef<'a>,
13511354
ExperimentalOfferTlvStreamRef,
1355+
ExperimentalInvoiceRequestTlvStreamRef,
13521356
);
13531357

13541358
impl CursorReadable for FullInvoiceTlvStream {
@@ -1359,14 +1363,20 @@ impl CursorReadable for FullInvoiceTlvStream {
13591363
let invoice = CursorReadable::read(r)?;
13601364
let signature = CursorReadable::read(r)?;
13611365
let experimental_offer = CursorReadable::read(r)?;
1366+
let experimental_invoice_request = CursorReadable::read(r)?;
13621367

1363-
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+
)
13641374
}
13651375
}
13661376

13671377
type PartialInvoiceTlvStream = (
13681378
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream,
1369-
ExperimentalOfferTlvStream,
1379+
ExperimentalOfferTlvStream, ExperimentalInvoiceRequestTlvStream,
13701380
);
13711381

13721382
type PartialInvoiceTlvStreamRef<'a> = (
@@ -1375,6 +1385,7 @@ type PartialInvoiceTlvStreamRef<'a> = (
13751385
InvoiceRequestTlvStreamRef<'a>,
13761386
InvoiceTlvStreamRef<'a>,
13771387
ExperimentalOfferTlvStreamRef,
1388+
ExperimentalInvoiceRequestTlvStreamRef,
13781389
);
13791390

13801391
impl CursorReadable for PartialInvoiceTlvStream {
@@ -1384,8 +1395,14 @@ impl CursorReadable for PartialInvoiceTlvStream {
13841395
let invoice_request = CursorReadable::read(r)?;
13851396
let invoice = CursorReadable::read(r)?;
13861397
let experimental_offer = CursorReadable::read(r)?;
1398+
let experimental_invoice_request = CursorReadable::read(r)?;
13871399

1388-
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+
)
13891406
}
13901407
}
13911408

@@ -1398,11 +1415,12 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
13981415
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
13991416
SignatureTlvStream { signature },
14001417
experimental_offer_tlv_stream,
1418+
experimental_invoice_request_tlv_stream,
14011419
) = tlv_stream;
14021420
let contents = InvoiceContents::try_from(
14031421
(
14041422
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1405-
experimental_offer_tlv_stream,
1423+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
14061424
)
14071425
)?;
14081426

@@ -1430,6 +1448,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14301448
features, node_id, message_paths,
14311449
},
14321450
experimental_offer_tlv_stream,
1451+
experimental_invoice_request_tlv_stream,
14331452
) = tlv_stream;
14341453

14351454
if message_paths.is_some() { return Err(Bolt12SemanticError::UnexpectedPaths) }
@@ -1464,15 +1483,15 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14641483
let refund = RefundContents::try_from(
14651484
(
14661485
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1467-
experimental_offer_tlv_stream,
1486+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
14681487
)
14691488
)?;
14701489
Ok(InvoiceContents::ForRefund { refund, fields })
14711490
} else {
14721491
let invoice_request = InvoiceRequestContents::try_from(
14731492
(
14741493
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1475-
experimental_offer_tlv_stream,
1494+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
14761495
)
14771496
)?;
14781497
Ok(InvoiceContents::ForOffer { invoice_request, fields })
@@ -1545,7 +1564,7 @@ mod tests {
15451564
use crate::ln::features::{Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures};
15461565
use crate::ln::inbound_payment::ExpandedKey;
15471566
use crate::ln::msgs::DecodeError;
1548-
use crate::offers::invoice_request::InvoiceRequestTlvStreamRef;
1567+
use crate::offers::invoice_request::{ExperimentalInvoiceRequestTlvStreamRef, InvoiceRequestTlvStreamRef};
15491568
use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self};
15501569
use crate::offers::nonce::Nonce;
15511570
use crate::offers::offer::{Amount, ExperimentalOfferTlvStreamRef, OfferTlvStreamRef, Quantity};
@@ -1719,6 +1738,7 @@ mod tests {
17191738
ExperimentalOfferTlvStreamRef {
17201739
experimental_foo: None,
17211740
},
1741+
ExperimentalInvoiceRequestTlvStreamRef {},
17221742
),
17231743
);
17241744

@@ -1815,6 +1835,7 @@ mod tests {
18151835
ExperimentalOfferTlvStreamRef {
18161836
experimental_foo: None,
18171837
},
1838+
ExperimentalInvoiceRequestTlvStreamRef {},
18181839
),
18191840
);
18201841

@@ -2011,7 +2032,7 @@ mod tests {
20112032
.relative_expiry(one_hour.as_secs() as u32)
20122033
.build().unwrap()
20132034
.sign(recipient_sign).unwrap();
2014-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2035+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20152036
#[cfg(feature = "std")]
20162037
assert!(!invoice.is_expired());
20172038
assert_eq!(invoice.relative_expiry(), one_hour);
@@ -2027,7 +2048,7 @@ mod tests {
20272048
.relative_expiry(one_hour.as_secs() as u32 - 1)
20282049
.build().unwrap()
20292050
.sign(recipient_sign).unwrap();
2030-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2051+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20312052
#[cfg(feature = "std")]
20322053
assert!(invoice.is_expired());
20332054
assert_eq!(invoice.relative_expiry(), one_hour - Duration::from_secs(1));
@@ -2046,7 +2067,7 @@ mod tests {
20462067
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
20472068
.build().unwrap()
20482069
.sign(recipient_sign).unwrap();
2049-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2070+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20502071
assert_eq!(invoice.amount_msats(), 1001);
20512072
assert_eq!(tlv_stream.amount, Some(1001));
20522073
}
@@ -2064,7 +2085,7 @@ mod tests {
20642085
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
20652086
.build().unwrap()
20662087
.sign(recipient_sign).unwrap();
2067-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2088+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20682089
assert_eq!(invoice.amount_msats(), 2000);
20692090
assert_eq!(tlv_stream.amount, Some(2000));
20702091

@@ -2102,7 +2123,7 @@ mod tests {
21022123
.fallback_v1_p2tr_tweaked(&tweaked_pubkey)
21032124
.build().unwrap()
21042125
.sign(recipient_sign).unwrap();
2105-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2126+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
21062127
assert_eq!(
21072128
invoice.fallbacks(),
21082129
vec![
@@ -2145,7 +2166,7 @@ mod tests {
21452166
.allow_mpp()
21462167
.build().unwrap()
21472168
.sign(recipient_sign).unwrap();
2148-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2169+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
21492170
assert_eq!(invoice.invoice_features(), &features);
21502171
assert_eq!(tlv_stream.features, Some(&features));
21512172
}

0 commit comments

Comments
 (0)