Skip to content

Commit b12f038

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 653728f commit b12f038

File tree

4 files changed

+165
-80
lines changed

4 files changed

+165
-80
lines changed

lightning/src/offers/invoice.rs

Lines changed: 42 additions & 21 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};
126126
use crate::offers::nonce::Nonce;
127127
use crate::offers::offer::{Amount, EXPERIMENTAL_OFFER_TYPES, ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, OFFER_TYPES, OfferTlvStream, OfferTlvStreamRef, Quantity};
@@ -506,7 +506,7 @@ impl UnsignedBolt12Invoice {
506506
record.write(&mut bytes).unwrap();
507507
}
508508

509-
let (_, _, _, invoice_tlv_stream, _) = contents.as_tlv_stream();
509+
let (_, _, _, invoice_tlv_stream, _, _) = contents.as_tlv_stream();
510510
invoice_tlv_stream.write(&mut bytes).unwrap();
511511

512512
let mut experimental_bytes = Vec::new();
@@ -871,14 +871,15 @@ impl Bolt12Invoice {
871871
pub(crate) fn as_tlv_stream(&self) -> FullInvoiceTlvStreamRef {
872872
let (
873873
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
874-
experimental_offer_tlv_stream,
874+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
875875
) = self.contents.as_tlv_stream();
876876
let signature_tlv_stream = SignatureTlvStreamRef {
877877
signature: Some(&self.signature),
878878
};
879879
(
880880
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
881881
signature_tlv_stream, experimental_offer_tlv_stream,
882+
experimental_invoice_request_tlv_stream,
882883
)
883884
}
884885

@@ -1133,13 +1134,15 @@ impl InvoiceContents {
11331134
}
11341135

11351136
fn as_tlv_stream(&self) -> PartialInvoiceTlvStreamRef {
1136-
let (payer, offer, invoice_request, experimental_offer) = match self {
1137+
let (
1138+
payer, offer, invoice_request, experimental_offer, experimental_invoice_request,
1139+
) = match self {
11371140
InvoiceContents::ForOffer { invoice_request, .. } => invoice_request.as_tlv_stream(),
11381141
InvoiceContents::ForRefund { refund, .. } => refund.as_tlv_stream(),
11391142
};
11401143
let invoice = self.fields().as_tlv_stream();
11411144

1142-
(payer, offer, invoice_request, invoice, experimental_offer)
1145+
(payer, offer, invoice_request, invoice, experimental_offer, experimental_invoice_request)
11431146
}
11441147
}
11451148

@@ -1241,12 +1244,12 @@ impl TryFrom<Vec<u8>> for UnsignedBolt12Invoice {
12411244
let ParsedMessage { mut bytes, tlv_stream } = invoice;
12421245
let (
12431246
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1244-
experimental_offer_tlv_stream,
1247+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
12451248
) = tlv_stream;
12461249
let contents = InvoiceContents::try_from(
12471250
(
12481251
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1249-
experimental_offer_tlv_stream,
1252+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
12501253
)
12511254
)?;
12521255

@@ -1310,7 +1313,7 @@ impl_writeable!(FallbackAddress, { version, program });
13101313

13111314
type FullInvoiceTlvStream =(
13121315
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream, SignatureTlvStream,
1313-
ExperimentalOfferTlvStream,
1316+
ExperimentalOfferTlvStream, ExperimentalInvoiceRequestTlvStream,
13141317
);
13151318

13161319
type FullInvoiceTlvStreamRef<'a> = (
@@ -1320,6 +1323,7 @@ type FullInvoiceTlvStreamRef<'a> = (
13201323
InvoiceTlvStreamRef<'a>,
13211324
SignatureTlvStreamRef<'a>,
13221325
ExperimentalOfferTlvStreamRef,
1326+
ExperimentalInvoiceRequestTlvStreamRef,
13231327
);
13241328

13251329
impl CursorReadable for FullInvoiceTlvStream {
@@ -1330,14 +1334,20 @@ impl CursorReadable for FullInvoiceTlvStream {
13301334
let invoice = CursorReadable::read(r)?;
13311335
let signature = CursorReadable::read(r)?;
13321336
let experimental_offer = CursorReadable::read(r)?;
1337+
let experimental_invoice_request = CursorReadable::read(r)?;
13331338

1334-
Ok((payer, offer, invoice_request, invoice, signature, experimental_offer))
1339+
Ok(
1340+
(
1341+
payer, offer, invoice_request, invoice, signature, experimental_offer,
1342+
experimental_invoice_request,
1343+
)
1344+
)
13351345
}
13361346
}
13371347

13381348
type PartialInvoiceTlvStream = (
13391349
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream,
1340-
ExperimentalOfferTlvStream,
1350+
ExperimentalOfferTlvStream, ExperimentalInvoiceRequestTlvStream,
13411351
);
13421352

13431353
type PartialInvoiceTlvStreamRef<'a> = (
@@ -1346,6 +1356,7 @@ type PartialInvoiceTlvStreamRef<'a> = (
13461356
InvoiceRequestTlvStreamRef<'a>,
13471357
InvoiceTlvStreamRef<'a>,
13481358
ExperimentalOfferTlvStreamRef,
1359+
ExperimentalInvoiceRequestTlvStreamRef,
13491360
);
13501361

13511362
impl CursorReadable for PartialInvoiceTlvStream {
@@ -1355,8 +1366,14 @@ impl CursorReadable for PartialInvoiceTlvStream {
13551366
let invoice_request = CursorReadable::read(r)?;
13561367
let invoice = CursorReadable::read(r)?;
13571368
let experimental_offer = CursorReadable::read(r)?;
1369+
let experimental_invoice_request = CursorReadable::read(r)?;
13581370

1359-
Ok((payer, offer, invoice_request, invoice, experimental_offer))
1371+
Ok(
1372+
(
1373+
payer, offer, invoice_request, invoice, experimental_offer,
1374+
experimental_invoice_request,
1375+
)
1376+
)
13601377
}
13611378
}
13621379

@@ -1369,11 +1386,12 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
13691386
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
13701387
SignatureTlvStream { signature },
13711388
experimental_offer_tlv_stream,
1389+
experimental_invoice_request_tlv_stream,
13721390
) = tlv_stream;
13731391
let contents = InvoiceContents::try_from(
13741392
(
13751393
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1376-
experimental_offer_tlv_stream,
1394+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
13771395
)
13781396
)?;
13791397

@@ -1401,6 +1419,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14011419
features, node_id, message_paths,
14021420
},
14031421
experimental_offer_tlv_stream,
1422+
experimental_invoice_request_tlv_stream,
14041423
) = tlv_stream;
14051424

14061425
if message_paths.is_some() { return Err(Bolt12SemanticError::UnexpectedPaths) }
@@ -1435,15 +1454,15 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14351454
let refund = RefundContents::try_from(
14361455
(
14371456
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1438-
experimental_offer_tlv_stream,
1457+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
14391458
)
14401459
)?;
14411460
Ok(InvoiceContents::ForRefund { refund, fields })
14421461
} else {
14431462
let invoice_request = InvoiceRequestContents::try_from(
14441463
(
14451464
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1446-
experimental_offer_tlv_stream,
1465+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
14471466
)
14481467
)?;
14491468
Ok(InvoiceContents::ForOffer { invoice_request, fields })
@@ -1516,7 +1535,7 @@ mod tests {
15161535
use crate::ln::features::{Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures};
15171536
use crate::ln::inbound_payment::ExpandedKey;
15181537
use crate::ln::msgs::DecodeError;
1519-
use crate::offers::invoice_request::InvoiceRequestTlvStreamRef;
1538+
use crate::offers::invoice_request::{ExperimentalInvoiceRequestTlvStreamRef, InvoiceRequestTlvStreamRef};
15201539
use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self};
15211540
use crate::offers::nonce::Nonce;
15221541
use crate::offers::offer::{Amount, ExperimentalOfferTlvStreamRef, OfferTlvStreamRef, Quantity};
@@ -1690,6 +1709,7 @@ mod tests {
16901709
ExperimentalOfferTlvStreamRef {
16911710
experimental_foo: None,
16921711
},
1712+
ExperimentalInvoiceRequestTlvStreamRef {},
16931713
),
16941714
);
16951715

@@ -1786,6 +1806,7 @@ mod tests {
17861806
ExperimentalOfferTlvStreamRef {
17871807
experimental_foo: None,
17881808
},
1809+
ExperimentalInvoiceRequestTlvStreamRef {},
17891810
),
17901811
);
17911812

@@ -1982,7 +2003,7 @@ mod tests {
19822003
.relative_expiry(one_hour.as_secs() as u32)
19832004
.build().unwrap()
19842005
.sign(recipient_sign).unwrap();
1985-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2006+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
19862007
#[cfg(feature = "std")]
19872008
assert!(!invoice.is_expired());
19882009
assert_eq!(invoice.relative_expiry(), one_hour);
@@ -1998,7 +2019,7 @@ mod tests {
19982019
.relative_expiry(one_hour.as_secs() as u32 - 1)
19992020
.build().unwrap()
20002021
.sign(recipient_sign).unwrap();
2001-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2022+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20022023
#[cfg(feature = "std")]
20032024
assert!(invoice.is_expired());
20042025
assert_eq!(invoice.relative_expiry(), one_hour - Duration::from_secs(1));
@@ -2017,7 +2038,7 @@ mod tests {
20172038
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
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
assert_eq!(invoice.amount_msats(), 1001);
20222043
assert_eq!(tlv_stream.amount, Some(1001));
20232044
}
@@ -2035,7 +2056,7 @@ mod tests {
20352056
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
20362057
.build().unwrap()
20372058
.sign(recipient_sign).unwrap();
2038-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2059+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20392060
assert_eq!(invoice.amount_msats(), 2000);
20402061
assert_eq!(tlv_stream.amount, Some(2000));
20412062

@@ -2073,7 +2094,7 @@ mod tests {
20732094
.fallback_v1_p2tr_tweaked(&tweaked_pubkey)
20742095
.build().unwrap()
20752096
.sign(recipient_sign).unwrap();
2076-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2097+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20772098
assert_eq!(
20782099
invoice.fallbacks(),
20792100
vec![
@@ -2116,7 +2137,7 @@ mod tests {
21162137
.allow_mpp()
21172138
.build().unwrap()
21182139
.sign(recipient_sign).unwrap();
2119-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2140+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
21202141
assert_eq!(invoice.invoice_features(), &features);
21212142
assert_eq!(tlv_stream.features, Some(&features));
21222143
}

0 commit comments

Comments
 (0)