Skip to content

Commit 41a4803

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 4dbc403 commit 41a4803

File tree

4 files changed

+163
-78
lines changed

4 files changed

+163
-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};
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

@@ -1300,7 +1303,7 @@ impl_writeable!(FallbackAddress, { version, program });
13001303

13011304
type FullInvoiceTlvStream =(
13021305
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream, SignatureTlvStream,
1303-
ExperimentalOfferTlvStream,
1306+
ExperimentalOfferTlvStream, ExperimentalInvoiceRequestTlvStream,
13041307
);
13051308

13061309
type FullInvoiceTlvStreamRef<'a> = (
@@ -1310,6 +1313,7 @@ type FullInvoiceTlvStreamRef<'a> = (
13101313
InvoiceTlvStreamRef<'a>,
13111314
SignatureTlvStreamRef<'a>,
13121315
ExperimentalOfferTlvStreamRef,
1316+
ExperimentalInvoiceRequestTlvStreamRef,
13131317
);
13141318

13151319
impl CursorReadable for FullInvoiceTlvStream {
@@ -1320,14 +1324,20 @@ impl CursorReadable for FullInvoiceTlvStream {
13201324
let invoice = CursorReadable::read(r)?;
13211325
let signature = CursorReadable::read(r)?;
13221326
let experimental_offer = CursorReadable::read(r)?;
1327+
let experimental_invoice_request = CursorReadable::read(r)?;
13231328

1324-
Ok((payer, offer, invoice_request, invoice, signature, experimental_offer))
1329+
Ok(
1330+
(
1331+
payer, offer, invoice_request, invoice, signature, experimental_offer,
1332+
experimental_invoice_request,
1333+
)
1334+
)
13251335
}
13261336
}
13271337

13281338
type PartialInvoiceTlvStream = (
13291339
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream,
1330-
ExperimentalOfferTlvStream,
1340+
ExperimentalOfferTlvStream, ExperimentalInvoiceRequestTlvStream,
13311341
);
13321342

13331343
type PartialInvoiceTlvStreamRef<'a> = (
@@ -1336,6 +1346,7 @@ type PartialInvoiceTlvStreamRef<'a> = (
13361346
InvoiceRequestTlvStreamRef<'a>,
13371347
InvoiceTlvStreamRef<'a>,
13381348
ExperimentalOfferTlvStreamRef,
1349+
ExperimentalInvoiceRequestTlvStreamRef,
13391350
);
13401351

13411352
impl CursorReadable for PartialInvoiceTlvStream {
@@ -1345,8 +1356,14 @@ impl CursorReadable for PartialInvoiceTlvStream {
13451356
let invoice_request = CursorReadable::read(r)?;
13461357
let invoice = CursorReadable::read(r)?;
13471358
let experimental_offer = CursorReadable::read(r)?;
1359+
let experimental_invoice_request = CursorReadable::read(r)?;
13481360

1349-
Ok((payer, offer, invoice_request, invoice, experimental_offer))
1361+
Ok(
1362+
(
1363+
payer, offer, invoice_request, invoice, experimental_offer,
1364+
experimental_invoice_request,
1365+
)
1366+
)
13501367
}
13511368
}
13521369

@@ -1359,11 +1376,12 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
13591376
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
13601377
SignatureTlvStream { signature },
13611378
experimental_offer_tlv_stream,
1379+
experimental_invoice_request_tlv_stream,
13621380
) = tlv_stream;
13631381
let contents = InvoiceContents::try_from(
13641382
(
13651383
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1366-
experimental_offer_tlv_stream,
1384+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
13671385
)
13681386
)?;
13691387

@@ -1391,6 +1409,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
13911409
features, node_id, message_paths,
13921410
},
13931411
experimental_offer_tlv_stream,
1412+
experimental_invoice_request_tlv_stream,
13941413
) = tlv_stream;
13951414

13961415
if message_paths.is_some() { return Err(Bolt12SemanticError::UnexpectedPaths) }
@@ -1425,15 +1444,15 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14251444
let refund = RefundContents::try_from(
14261445
(
14271446
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1428-
experimental_offer_tlv_stream,
1447+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
14291448
)
14301449
)?;
14311450
Ok(InvoiceContents::ForRefund { refund, fields })
14321451
} else {
14331452
let invoice_request = InvoiceRequestContents::try_from(
14341453
(
14351454
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1436-
experimental_offer_tlv_stream,
1455+
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
14371456
)
14381457
)?;
14391458
Ok(InvoiceContents::ForOffer { invoice_request, fields })
@@ -1506,7 +1525,7 @@ mod tests {
15061525
use crate::ln::features::{Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures};
15071526
use crate::ln::inbound_payment::ExpandedKey;
15081527
use crate::ln::msgs::DecodeError;
1509-
use crate::offers::invoice_request::InvoiceRequestTlvStreamRef;
1528+
use crate::offers::invoice_request::{ExperimentalInvoiceRequestTlvStreamRef, InvoiceRequestTlvStreamRef};
15101529
use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self};
15111530
use crate::offers::nonce::Nonce;
15121531
use crate::offers::offer::{Amount, ExperimentalOfferTlvStreamRef, OfferTlvStreamRef, Quantity};
@@ -1680,6 +1699,7 @@ mod tests {
16801699
ExperimentalOfferTlvStreamRef {
16811700
experimental_foo: None,
16821701
},
1702+
ExperimentalInvoiceRequestTlvStreamRef {},
16831703
),
16841704
);
16851705

@@ -1776,6 +1796,7 @@ mod tests {
17761796
ExperimentalOfferTlvStreamRef {
17771797
experimental_foo: None,
17781798
},
1799+
ExperimentalInvoiceRequestTlvStreamRef {},
17791800
),
17801801
);
17811802

@@ -1972,7 +1993,7 @@ mod tests {
19721993
.relative_expiry(one_hour.as_secs() as u32)
19731994
.build().unwrap()
19741995
.sign(recipient_sign).unwrap();
1975-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
1996+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
19761997
#[cfg(feature = "std")]
19771998
assert!(!invoice.is_expired());
19781999
assert_eq!(invoice.relative_expiry(), one_hour);
@@ -1988,7 +2009,7 @@ mod tests {
19882009
.relative_expiry(one_hour.as_secs() as u32 - 1)
19892010
.build().unwrap()
19902011
.sign(recipient_sign).unwrap();
1991-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2012+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
19922013
#[cfg(feature = "std")]
19932014
assert!(invoice.is_expired());
19942015
assert_eq!(invoice.relative_expiry(), one_hour - Duration::from_secs(1));
@@ -2007,7 +2028,7 @@ mod tests {
20072028
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
20082029
.build().unwrap()
20092030
.sign(recipient_sign).unwrap();
2010-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2031+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20112032
assert_eq!(invoice.amount_msats(), 1001);
20122033
assert_eq!(tlv_stream.amount, Some(1001));
20132034
}
@@ -2025,7 +2046,7 @@ mod tests {
20252046
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
20262047
.build().unwrap()
20272048
.sign(recipient_sign).unwrap();
2028-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2049+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20292050
assert_eq!(invoice.amount_msats(), 2000);
20302051
assert_eq!(tlv_stream.amount, Some(2000));
20312052

@@ -2063,7 +2084,7 @@ mod tests {
20632084
.fallback_v1_p2tr_tweaked(&tweaked_pubkey)
20642085
.build().unwrap()
20652086
.sign(recipient_sign).unwrap();
2066-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2087+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
20672088
assert_eq!(
20682089
invoice.fallbacks(),
20692090
vec![
@@ -2106,7 +2127,7 @@ mod tests {
21062127
.allow_mpp()
21072128
.build().unwrap()
21082129
.sign(recipient_sign).unwrap();
2109-
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
2130+
let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
21102131
assert_eq!(invoice.invoice_features(), &features);
21112132
assert_eq!(tlv_stream.features, Some(&features));
21122133
}

0 commit comments

Comments
 (0)