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.
This commit is contained in:
Jeffrey Czyz 2024-08-08 11:44:03 -05:00
parent 62cddb7d3a
commit 5590bc2fa8
No known key found for this signature in database
GPG key ID: 912EF12EA67705F5
4 changed files with 164 additions and 78 deletions

View file

@ -121,7 +121,7 @@ use crate::ln::msgs::DecodeError;
use crate::offers::invoice_macros::{invoice_accessors_common, invoice_builder_methods_common}; use crate::offers::invoice_macros::{invoice_accessors_common, invoice_builder_methods_common};
#[cfg(test)] #[cfg(test)]
use crate::offers::invoice_macros::invoice_builder_methods_test; use crate::offers::invoice_macros::invoice_builder_methods_test;
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}; 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};
use crate::offers::merkle::{SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, TlvStream, self, SIGNATURE_TLV_RECORD_SIZE}; use crate::offers::merkle::{SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, TlvStream, self, SIGNATURE_TLV_RECORD_SIZE};
use crate::offers::nonce::Nonce; use crate::offers::nonce::Nonce;
use crate::offers::offer::{Amount, EXPERIMENTAL_OFFER_TYPES, ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, OFFER_TYPES, OfferTlvStream, OfferTlvStreamRef, Quantity}; use crate::offers::offer::{Amount, EXPERIMENTAL_OFFER_TYPES, ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, OFFER_TYPES, OfferTlvStream, OfferTlvStreamRef, Quantity};
@ -497,7 +497,7 @@ impl UnsignedBolt12Invoice {
const EXPERIMENTAL_TYPES: core::ops::Range<u64> = const EXPERIMENTAL_TYPES: core::ops::Range<u64> =
EXPERIMENTAL_OFFER_TYPES.start..EXPERIMENTAL_INVOICE_REQUEST_TYPES.end; EXPERIMENTAL_OFFER_TYPES.start..EXPERIMENTAL_INVOICE_REQUEST_TYPES.end;
let (_, _, _, invoice_tlv_stream, _) = contents.as_tlv_stream(); let (_, _, _, invoice_tlv_stream, _, _) = contents.as_tlv_stream();
// Allocate enough space for the invoice, which will include: // Allocate enough space for the invoice, which will include:
// - all TLV records from `invreq_bytes` except signatures, // - all TLV records from `invreq_bytes` except signatures,
@ -903,7 +903,7 @@ impl Bolt12Invoice {
pub(crate) fn as_tlv_stream(&self) -> FullInvoiceTlvStreamRef { pub(crate) fn as_tlv_stream(&self) -> FullInvoiceTlvStreamRef {
let ( let (
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream, payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
experimental_offer_tlv_stream, experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
) = self.contents.as_tlv_stream(); ) = self.contents.as_tlv_stream();
let signature_tlv_stream = SignatureTlvStreamRef { let signature_tlv_stream = SignatureTlvStreamRef {
signature: Some(&self.signature), signature: Some(&self.signature),
@ -911,6 +911,7 @@ impl Bolt12Invoice {
( (
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream, payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
signature_tlv_stream, experimental_offer_tlv_stream, signature_tlv_stream, experimental_offer_tlv_stream,
experimental_invoice_request_tlv_stream,
) )
} }
@ -1172,13 +1173,15 @@ impl InvoiceContents {
} }
fn as_tlv_stream(&self) -> PartialInvoiceTlvStreamRef { fn as_tlv_stream(&self) -> PartialInvoiceTlvStreamRef {
let (payer, offer, invoice_request, experimental_offer) = match self { let (
payer, offer, invoice_request, experimental_offer, experimental_invoice_request,
) = match self {
InvoiceContents::ForOffer { invoice_request, .. } => invoice_request.as_tlv_stream(), InvoiceContents::ForOffer { invoice_request, .. } => invoice_request.as_tlv_stream(),
InvoiceContents::ForRefund { refund, .. } => refund.as_tlv_stream(), InvoiceContents::ForRefund { refund, .. } => refund.as_tlv_stream(),
}; };
let invoice = self.fields().as_tlv_stream(); let invoice = self.fields().as_tlv_stream();
(payer, offer, invoice_request, invoice, experimental_offer) (payer, offer, invoice_request, invoice, experimental_offer, experimental_invoice_request)
} }
} }
@ -1339,7 +1342,7 @@ impl_writeable!(FallbackAddress, { version, program });
type FullInvoiceTlvStream =( type FullInvoiceTlvStream =(
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream, SignatureTlvStream, PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream, SignatureTlvStream,
ExperimentalOfferTlvStream, ExperimentalOfferTlvStream, ExperimentalInvoiceRequestTlvStream,
); );
type FullInvoiceTlvStreamRef<'a> = ( type FullInvoiceTlvStreamRef<'a> = (
@ -1349,6 +1352,7 @@ type FullInvoiceTlvStreamRef<'a> = (
InvoiceTlvStreamRef<'a>, InvoiceTlvStreamRef<'a>,
SignatureTlvStreamRef<'a>, SignatureTlvStreamRef<'a>,
ExperimentalOfferTlvStreamRef, ExperimentalOfferTlvStreamRef,
ExperimentalInvoiceRequestTlvStreamRef,
); );
impl CursorReadable for FullInvoiceTlvStream { impl CursorReadable for FullInvoiceTlvStream {
@ -1359,14 +1363,20 @@ impl CursorReadable for FullInvoiceTlvStream {
let invoice = CursorReadable::read(r)?; let invoice = CursorReadable::read(r)?;
let signature = CursorReadable::read(r)?; let signature = CursorReadable::read(r)?;
let experimental_offer = CursorReadable::read(r)?; let experimental_offer = CursorReadable::read(r)?;
let experimental_invoice_request = CursorReadable::read(r)?;
Ok((payer, offer, invoice_request, invoice, signature, experimental_offer)) Ok(
(
payer, offer, invoice_request, invoice, signature, experimental_offer,
experimental_invoice_request,
)
)
} }
} }
type PartialInvoiceTlvStream = ( type PartialInvoiceTlvStream = (
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream, PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream,
ExperimentalOfferTlvStream, ExperimentalOfferTlvStream, ExperimentalInvoiceRequestTlvStream,
); );
type PartialInvoiceTlvStreamRef<'a> = ( type PartialInvoiceTlvStreamRef<'a> = (
@ -1375,6 +1385,7 @@ type PartialInvoiceTlvStreamRef<'a> = (
InvoiceRequestTlvStreamRef<'a>, InvoiceRequestTlvStreamRef<'a>,
InvoiceTlvStreamRef<'a>, InvoiceTlvStreamRef<'a>,
ExperimentalOfferTlvStreamRef, ExperimentalOfferTlvStreamRef,
ExperimentalInvoiceRequestTlvStreamRef,
); );
impl CursorReadable for PartialInvoiceTlvStream { impl CursorReadable for PartialInvoiceTlvStream {
@ -1384,8 +1395,14 @@ impl CursorReadable for PartialInvoiceTlvStream {
let invoice_request = CursorReadable::read(r)?; let invoice_request = CursorReadable::read(r)?;
let invoice = CursorReadable::read(r)?; let invoice = CursorReadable::read(r)?;
let experimental_offer = CursorReadable::read(r)?; let experimental_offer = CursorReadable::read(r)?;
let experimental_invoice_request = CursorReadable::read(r)?;
Ok((payer, offer, invoice_request, invoice, experimental_offer)) Ok(
(
payer, offer, invoice_request, invoice, experimental_offer,
experimental_invoice_request,
)
)
} }
} }
@ -1398,11 +1415,12 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream, payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
SignatureTlvStream { signature }, SignatureTlvStream { signature },
experimental_offer_tlv_stream, experimental_offer_tlv_stream,
experimental_invoice_request_tlv_stream,
) = tlv_stream; ) = tlv_stream;
let contents = InvoiceContents::try_from( let contents = InvoiceContents::try_from(
( (
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream, payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
experimental_offer_tlv_stream, experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
) )
)?; )?;
@ -1430,6 +1448,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
features, node_id, message_paths, features, node_id, message_paths,
}, },
experimental_offer_tlv_stream, experimental_offer_tlv_stream,
experimental_invoice_request_tlv_stream,
) = tlv_stream; ) = tlv_stream;
if message_paths.is_some() { return Err(Bolt12SemanticError::UnexpectedPaths) } if message_paths.is_some() { return Err(Bolt12SemanticError::UnexpectedPaths) }
@ -1464,7 +1483,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
let refund = RefundContents::try_from( let refund = RefundContents::try_from(
( (
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
experimental_offer_tlv_stream, experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
) )
)?; )?;
Ok(InvoiceContents::ForRefund { refund, fields }) Ok(InvoiceContents::ForRefund { refund, fields })
@ -1472,7 +1491,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
let invoice_request = InvoiceRequestContents::try_from( let invoice_request = InvoiceRequestContents::try_from(
( (
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
experimental_offer_tlv_stream, experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
) )
)?; )?;
Ok(InvoiceContents::ForOffer { invoice_request, fields }) Ok(InvoiceContents::ForOffer { invoice_request, fields })
@ -1545,7 +1564,7 @@ mod tests {
use crate::ln::features::{Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures}; use crate::ln::features::{Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures};
use crate::ln::inbound_payment::ExpandedKey; use crate::ln::inbound_payment::ExpandedKey;
use crate::ln::msgs::DecodeError; use crate::ln::msgs::DecodeError;
use crate::offers::invoice_request::InvoiceRequestTlvStreamRef; use crate::offers::invoice_request::{ExperimentalInvoiceRequestTlvStreamRef, InvoiceRequestTlvStreamRef};
use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self}; use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self};
use crate::offers::nonce::Nonce; use crate::offers::nonce::Nonce;
use crate::offers::offer::{Amount, ExperimentalOfferTlvStreamRef, OfferTlvStreamRef, Quantity}; use crate::offers::offer::{Amount, ExperimentalOfferTlvStreamRef, OfferTlvStreamRef, Quantity};
@ -1719,6 +1738,7 @@ mod tests {
ExperimentalOfferTlvStreamRef { ExperimentalOfferTlvStreamRef {
experimental_foo: None, experimental_foo: None,
}, },
ExperimentalInvoiceRequestTlvStreamRef {},
), ),
); );
@ -1815,6 +1835,7 @@ mod tests {
ExperimentalOfferTlvStreamRef { ExperimentalOfferTlvStreamRef {
experimental_foo: None, experimental_foo: None,
}, },
ExperimentalInvoiceRequestTlvStreamRef {},
), ),
); );
@ -2011,7 +2032,7 @@ mod tests {
.relative_expiry(one_hour.as_secs() as u32) .relative_expiry(one_hour.as_secs() as u32)
.build().unwrap() .build().unwrap()
.sign(recipient_sign).unwrap(); .sign(recipient_sign).unwrap();
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream(); let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
#[cfg(feature = "std")] #[cfg(feature = "std")]
assert!(!invoice.is_expired()); assert!(!invoice.is_expired());
assert_eq!(invoice.relative_expiry(), one_hour); assert_eq!(invoice.relative_expiry(), one_hour);
@ -2027,7 +2048,7 @@ mod tests {
.relative_expiry(one_hour.as_secs() as u32 - 1) .relative_expiry(one_hour.as_secs() as u32 - 1)
.build().unwrap() .build().unwrap()
.sign(recipient_sign).unwrap(); .sign(recipient_sign).unwrap();
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream(); let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
#[cfg(feature = "std")] #[cfg(feature = "std")]
assert!(invoice.is_expired()); assert!(invoice.is_expired());
assert_eq!(invoice.relative_expiry(), one_hour - Duration::from_secs(1)); assert_eq!(invoice.relative_expiry(), one_hour - Duration::from_secs(1));
@ -2046,7 +2067,7 @@ mod tests {
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap() .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
.build().unwrap() .build().unwrap()
.sign(recipient_sign).unwrap(); .sign(recipient_sign).unwrap();
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream(); let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
assert_eq!(invoice.amount_msats(), 1001); assert_eq!(invoice.amount_msats(), 1001);
assert_eq!(tlv_stream.amount, Some(1001)); assert_eq!(tlv_stream.amount, Some(1001));
} }
@ -2064,7 +2085,7 @@ mod tests {
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap() .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
.build().unwrap() .build().unwrap()
.sign(recipient_sign).unwrap(); .sign(recipient_sign).unwrap();
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream(); let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
assert_eq!(invoice.amount_msats(), 2000); assert_eq!(invoice.amount_msats(), 2000);
assert_eq!(tlv_stream.amount, Some(2000)); assert_eq!(tlv_stream.amount, Some(2000));
@ -2102,7 +2123,7 @@ mod tests {
.fallback_v1_p2tr_tweaked(&tweaked_pubkey) .fallback_v1_p2tr_tweaked(&tweaked_pubkey)
.build().unwrap() .build().unwrap()
.sign(recipient_sign).unwrap(); .sign(recipient_sign).unwrap();
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream(); let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
assert_eq!( assert_eq!(
invoice.fallbacks(), invoice.fallbacks(),
vec![ vec![
@ -2145,7 +2166,7 @@ mod tests {
.allow_mpp() .allow_mpp()
.build().unwrap() .build().unwrap()
.sign(recipient_sign).unwrap(); .sign(recipient_sign).unwrap();
let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream(); let (_, _, _, tlv_stream, _, _, _) = invoice.as_tlv_stream();
assert_eq!(invoice.invoice_features(), &features); assert_eq!(invoice.invoice_features(), &features);
assert_eq!(tlv_stream.features, Some(&features)); assert_eq!(tlv_stream.features, Some(&features));
} }

View file

@ -523,7 +523,7 @@ impl UnsignedInvoiceRequest {
// unknown TLV records, which are not stored in `OfferContents`. // unknown TLV records, which are not stored in `OfferContents`.
let ( let (
payer_tlv_stream, _offer_tlv_stream, invoice_request_tlv_stream, payer_tlv_stream, _offer_tlv_stream, invoice_request_tlv_stream,
_experimental_offer_tlv_stream, _experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
) = contents.as_tlv_stream(); ) = contents.as_tlv_stream();
// Allocate enough space for the invoice_request, which will include: // Allocate enough space for the invoice_request, which will include:
@ -535,6 +535,7 @@ impl UnsignedInvoiceRequest {
+ payer_tlv_stream.serialized_length() + payer_tlv_stream.serialized_length()
+ invoice_request_tlv_stream.serialized_length() + invoice_request_tlv_stream.serialized_length()
+ SIGNATURE_TLV_RECORD_SIZE + SIGNATURE_TLV_RECORD_SIZE
+ experimental_invoice_request_tlv_stream.serialized_length(),
); );
payer_tlv_stream.write(&mut bytes).unwrap(); payer_tlv_stream.write(&mut bytes).unwrap();
@ -555,12 +556,14 @@ impl UnsignedInvoiceRequest {
- experimental_tlv_stream - experimental_tlv_stream
.peek() .peek()
.map_or(remaining_bytes.len(), |first_record| first_record.start) .map_or(remaining_bytes.len(), |first_record| first_record.start)
+ experimental_invoice_request_tlv_stream.serialized_length(),
); );
for record in experimental_tlv_stream { for record in experimental_tlv_stream {
record.write(&mut experimental_bytes).unwrap(); record.write(&mut experimental_bytes).unwrap();
} }
experimental_invoice_request_tlv_stream.write(&mut experimental_bytes).unwrap();
debug_assert_eq!(experimental_bytes.len(), experimental_bytes.capacity()); debug_assert_eq!(experimental_bytes.len(), experimental_bytes.capacity());
let tlv_stream = TlvStream::new(&bytes).chain(TlvStream::new(&experimental_bytes)); let tlv_stream = TlvStream::new(&bytes).chain(TlvStream::new(&experimental_bytes));
@ -910,7 +913,7 @@ impl InvoiceRequest {
pub(crate) fn as_tlv_stream(&self) -> FullInvoiceRequestTlvStreamRef { pub(crate) fn as_tlv_stream(&self) -> FullInvoiceRequestTlvStreamRef {
let ( let (
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
experimental_offer_tlv_stream, experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
) = self.contents.as_tlv_stream(); ) = self.contents.as_tlv_stream();
let signature_tlv_stream = SignatureTlvStreamRef { let signature_tlv_stream = SignatureTlvStreamRef {
signature: Some(&self.signature), signature: Some(&self.signature),
@ -918,6 +921,7 @@ impl InvoiceRequest {
( (
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
signature_tlv_stream, experimental_offer_tlv_stream, signature_tlv_stream, experimental_offer_tlv_stream,
experimental_invoice_request_tlv_stream,
) )
} }
} }
@ -1034,9 +1038,10 @@ impl InvoiceRequestContents {
} }
pub(super) fn as_tlv_stream(&self) -> PartialInvoiceRequestTlvStreamRef { pub(super) fn as_tlv_stream(&self) -> PartialInvoiceRequestTlvStreamRef {
let (payer, offer, mut invoice_request, experimental_offer) = self.inner.as_tlv_stream(); let (payer, offer, mut invoice_request, experimental_offer, experimental_invoice_request) =
self.inner.as_tlv_stream();
invoice_request.payer_id = Some(&self.payer_signing_pubkey); invoice_request.payer_id = Some(&self.payer_signing_pubkey);
(payer, offer, invoice_request, experimental_offer) (payer, offer, invoice_request, experimental_offer, experimental_invoice_request)
} }
} }
@ -1071,7 +1076,9 @@ impl InvoiceRequestContentsWithoutPayerSigningPubkey {
paths: None, paths: None,
}; };
(payer, offer, invoice_request, experimental_offer) let experimental_invoice_request = ExperimentalInvoiceRequestTlvStreamRef {};
(payer, offer, invoice_request, experimental_offer, experimental_invoice_request)
} }
} }
@ -1126,9 +1133,14 @@ tlv_stream!(InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef<'a>, INVOICE_REQ
pub(super) const EXPERIMENTAL_INVOICE_REQUEST_TYPES: core::ops::Range<u64> = pub(super) const EXPERIMENTAL_INVOICE_REQUEST_TYPES: core::ops::Range<u64> =
2_000_000_000..3_000_000_000; 2_000_000_000..3_000_000_000;
tlv_stream!(
ExperimentalInvoiceRequestTlvStream, ExperimentalInvoiceRequestTlvStreamRef,
EXPERIMENTAL_INVOICE_REQUEST_TYPES, {}
);
type FullInvoiceRequestTlvStream = ( type FullInvoiceRequestTlvStream = (
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, SignatureTlvStream, PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, SignatureTlvStream,
ExperimentalOfferTlvStream, ExperimentalOfferTlvStream, ExperimentalInvoiceRequestTlvStream,
); );
type FullInvoiceRequestTlvStreamRef<'a> = ( type FullInvoiceRequestTlvStreamRef<'a> = (
@ -1137,6 +1149,7 @@ type FullInvoiceRequestTlvStreamRef<'a> = (
InvoiceRequestTlvStreamRef<'a>, InvoiceRequestTlvStreamRef<'a>,
SignatureTlvStreamRef<'a>, SignatureTlvStreamRef<'a>,
ExperimentalOfferTlvStreamRef, ExperimentalOfferTlvStreamRef,
ExperimentalInvoiceRequestTlvStreamRef,
); );
impl CursorReadable for FullInvoiceRequestTlvStream { impl CursorReadable for FullInvoiceRequestTlvStream {
@ -1146,13 +1159,20 @@ impl CursorReadable for FullInvoiceRequestTlvStream {
let invoice_request = CursorReadable::read(r)?; let invoice_request = CursorReadable::read(r)?;
let signature = CursorReadable::read(r)?; let signature = CursorReadable::read(r)?;
let experimental_offer = CursorReadable::read(r)?; let experimental_offer = CursorReadable::read(r)?;
let experimental_invoice_request = CursorReadable::read(r)?;
Ok((payer, offer, invoice_request, signature, experimental_offer)) Ok(
(
payer, offer, invoice_request, signature, experimental_offer,
experimental_invoice_request,
)
)
} }
} }
type PartialInvoiceRequestTlvStream = ( type PartialInvoiceRequestTlvStream = (
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, ExperimentalOfferTlvStream, PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, ExperimentalOfferTlvStream,
ExperimentalInvoiceRequestTlvStream,
); );
type PartialInvoiceRequestTlvStreamRef<'a> = ( type PartialInvoiceRequestTlvStreamRef<'a> = (
@ -1160,6 +1180,7 @@ type PartialInvoiceRequestTlvStreamRef<'a> = (
OfferTlvStreamRef<'a>, OfferTlvStreamRef<'a>,
InvoiceRequestTlvStreamRef<'a>, InvoiceRequestTlvStreamRef<'a>,
ExperimentalOfferTlvStreamRef, ExperimentalOfferTlvStreamRef,
ExperimentalInvoiceRequestTlvStreamRef,
); );
impl TryFrom<Vec<u8>> for UnsignedInvoiceRequest { impl TryFrom<Vec<u8>> for UnsignedInvoiceRequest {
@ -1192,11 +1213,12 @@ impl TryFrom<Vec<u8>> for InvoiceRequest {
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
SignatureTlvStream { signature }, SignatureTlvStream { signature },
experimental_offer_tlv_stream, experimental_offer_tlv_stream,
experimental_invoice_request_tlv_stream,
) = tlv_stream; ) = tlv_stream;
let contents = InvoiceRequestContents::try_from( let contents = InvoiceRequestContents::try_from(
( (
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
experimental_offer_tlv_stream, experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
) )
)?; )?;
@ -1222,6 +1244,7 @@ impl TryFrom<PartialInvoiceRequestTlvStream> for InvoiceRequestContents {
chain, amount, features, quantity, payer_id, payer_note, paths, chain, amount, features, quantity, payer_id, payer_note, paths,
}, },
experimental_offer_tlv_stream, experimental_offer_tlv_stream,
ExperimentalInvoiceRequestTlvStream {},
) = tlv_stream; ) = tlv_stream;
let payer = match metadata { let payer = match metadata {
@ -1309,7 +1332,7 @@ impl Readable for InvoiceRequestFields {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{INVOICE_REQUEST_TYPES, InvoiceRequest, InvoiceRequestFields, InvoiceRequestTlvStreamRef, PAYER_NOTE_LIMIT, SIGNATURE_TAG, UnsignedInvoiceRequest}; use super::{ExperimentalInvoiceRequestTlvStreamRef, INVOICE_REQUEST_TYPES, InvoiceRequest, InvoiceRequestFields, InvoiceRequestTlvStreamRef, PAYER_NOTE_LIMIT, SIGNATURE_TAG, UnsignedInvoiceRequest};
use bitcoin::constants::ChainHash; use bitcoin::constants::ChainHash;
use bitcoin::network::Network; use bitcoin::network::Network;
@ -1437,6 +1460,7 @@ mod tests {
ExperimentalOfferTlvStreamRef { ExperimentalOfferTlvStreamRef {
experimental_foo: None, experimental_foo: None,
}, },
ExperimentalInvoiceRequestTlvStreamRef {},
), ),
); );
@ -1509,24 +1533,27 @@ mod tests {
let ( let (
payer_tlv_stream, offer_tlv_stream, mut invoice_request_tlv_stream, payer_tlv_stream, offer_tlv_stream, mut invoice_request_tlv_stream,
mut invoice_tlv_stream, mut signature_tlv_stream, experimental_offer_tlv_stream, mut invoice_tlv_stream, mut signature_tlv_stream, experimental_offer_tlv_stream,
experimental_invoice_request_tlv_stream,
) = invoice.as_tlv_stream(); ) = invoice.as_tlv_stream();
invoice_request_tlv_stream.amount = Some(2000); invoice_request_tlv_stream.amount = Some(2000);
invoice_tlv_stream.amount = Some(2000); invoice_tlv_stream.amount = Some(2000);
let tlv_stream = let tlv_stream =
(payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream); (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream);
let experimental_tlv_stream = (
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
);
let mut bytes = Vec::new(); let mut bytes = Vec::new();
tlv_stream.write(&mut bytes).unwrap(); (&tlv_stream, &experimental_tlv_stream).write(&mut bytes).unwrap();
experimental_offer_tlv_stream.write(&mut bytes).unwrap();
let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes); let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes);
let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap(); let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap();
signature_tlv_stream.signature = Some(&signature); signature_tlv_stream.signature = Some(&signature);
let mut encoded_invoice = Vec::new(); let mut encoded_invoice = Vec::new();
tlv_stream.write(&mut encoded_invoice).unwrap(); (tlv_stream, signature_tlv_stream, experimental_tlv_stream)
signature_tlv_stream.write(&mut encoded_invoice).unwrap(); .write(&mut encoded_invoice)
experimental_offer_tlv_stream.write(&mut encoded_invoice).unwrap(); .unwrap();
let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap(); let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
assert!(invoice.verify_using_metadata(&expanded_key, &secp_ctx).is_err()); assert!(invoice.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
@ -1535,24 +1562,27 @@ mod tests {
let ( let (
mut payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream, mut payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
mut signature_tlv_stream, experimental_offer_tlv_stream, mut signature_tlv_stream, experimental_offer_tlv_stream,
experimental_invoice_request_tlv_stream,
) = invoice.as_tlv_stream(); ) = invoice.as_tlv_stream();
let metadata = payer_tlv_stream.metadata.unwrap().iter().copied().rev().collect(); let metadata = payer_tlv_stream.metadata.unwrap().iter().copied().rev().collect();
payer_tlv_stream.metadata = Some(&metadata); payer_tlv_stream.metadata = Some(&metadata);
let tlv_stream = let tlv_stream =
(payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream); (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream);
let experimental_tlv_stream = (
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
);
let mut bytes = Vec::new(); let mut bytes = Vec::new();
tlv_stream.write(&mut bytes).unwrap(); (&tlv_stream, &experimental_tlv_stream).write(&mut bytes).unwrap();
experimental_offer_tlv_stream.write(&mut bytes).unwrap();
let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes); let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes);
let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap(); let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap();
signature_tlv_stream.signature = Some(&signature); signature_tlv_stream.signature = Some(&signature);
let mut encoded_invoice = Vec::new(); let mut encoded_invoice = Vec::new();
tlv_stream.write(&mut encoded_invoice).unwrap(); (tlv_stream, signature_tlv_stream, experimental_tlv_stream)
signature_tlv_stream.write(&mut encoded_invoice).unwrap(); .write(&mut encoded_invoice)
experimental_offer_tlv_stream.write(&mut encoded_invoice).unwrap(); .unwrap();
let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap(); let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
assert!(invoice.verify_using_metadata(&expanded_key, &secp_ctx).is_err()); assert!(invoice.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
@ -1589,24 +1619,27 @@ mod tests {
let ( let (
payer_tlv_stream, offer_tlv_stream, mut invoice_request_tlv_stream, payer_tlv_stream, offer_tlv_stream, mut invoice_request_tlv_stream,
mut invoice_tlv_stream, mut signature_tlv_stream, experimental_offer_tlv_stream, mut invoice_tlv_stream, mut signature_tlv_stream, experimental_offer_tlv_stream,
experimental_invoice_request_tlv_stream,
) = invoice.as_tlv_stream(); ) = invoice.as_tlv_stream();
invoice_request_tlv_stream.amount = Some(2000); invoice_request_tlv_stream.amount = Some(2000);
invoice_tlv_stream.amount = Some(2000); invoice_tlv_stream.amount = Some(2000);
let tlv_stream = let tlv_stream =
(payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream); (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream);
let experimental_tlv_stream = (
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
);
let mut bytes = Vec::new(); let mut bytes = Vec::new();
tlv_stream.write(&mut bytes).unwrap(); (&tlv_stream, &experimental_tlv_stream).write(&mut bytes).unwrap();
experimental_offer_tlv_stream.write(&mut bytes).unwrap();
let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes); let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes);
let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap(); let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap();
signature_tlv_stream.signature = Some(&signature); signature_tlv_stream.signature = Some(&signature);
let mut encoded_invoice = Vec::new(); let mut encoded_invoice = Vec::new();
tlv_stream.write(&mut encoded_invoice).unwrap(); (tlv_stream, signature_tlv_stream, experimental_tlv_stream)
signature_tlv_stream.write(&mut encoded_invoice).unwrap(); .write(&mut encoded_invoice)
experimental_offer_tlv_stream.write(&mut encoded_invoice).unwrap(); .unwrap();
let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap(); let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
assert!( assert!(
@ -1617,24 +1650,27 @@ mod tests {
let ( let (
payer_tlv_stream, offer_tlv_stream, mut invoice_request_tlv_stream, invoice_tlv_stream, payer_tlv_stream, offer_tlv_stream, mut invoice_request_tlv_stream, invoice_tlv_stream,
mut signature_tlv_stream, experimental_offer_tlv_stream, mut signature_tlv_stream, experimental_offer_tlv_stream,
experimental_invoice_request_tlv_stream,
) = invoice.as_tlv_stream(); ) = invoice.as_tlv_stream();
let payer_id = pubkey(1); let payer_id = pubkey(1);
invoice_request_tlv_stream.payer_id = Some(&payer_id); invoice_request_tlv_stream.payer_id = Some(&payer_id);
let tlv_stream = let tlv_stream =
(payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream); (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream);
let experimental_tlv_stream = (
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
);
let mut bytes = Vec::new(); let mut bytes = Vec::new();
tlv_stream.write(&mut bytes).unwrap(); (&tlv_stream, &experimental_tlv_stream).write(&mut bytes).unwrap();
experimental_offer_tlv_stream.write(&mut bytes).unwrap();
let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes); let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes);
let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap(); let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap();
signature_tlv_stream.signature = Some(&signature); signature_tlv_stream.signature = Some(&signature);
let mut encoded_invoice = Vec::new(); let mut encoded_invoice = Vec::new();
tlv_stream.write(&mut encoded_invoice).unwrap(); (tlv_stream, signature_tlv_stream, experimental_tlv_stream)
signature_tlv_stream.write(&mut encoded_invoice).unwrap(); .write(&mut encoded_invoice)
experimental_offer_tlv_stream.write(&mut encoded_invoice).unwrap(); .unwrap();
let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap(); let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
assert!( assert!(
@ -1654,7 +1690,7 @@ mod tests {
.chain(Network::Bitcoin).unwrap() .chain(Network::Bitcoin).unwrap()
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.chain(), mainnet); assert_eq!(invoice_request.chain(), mainnet);
assert_eq!(tlv_stream.chain, None); assert_eq!(tlv_stream.chain, None);
@ -1666,7 +1702,7 @@ mod tests {
.chain(Network::Testnet).unwrap() .chain(Network::Testnet).unwrap()
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.chain(), testnet); assert_eq!(invoice_request.chain(), testnet);
assert_eq!(tlv_stream.chain, Some(&testnet)); assert_eq!(tlv_stream.chain, Some(&testnet));
@ -1679,7 +1715,7 @@ mod tests {
.chain(Network::Bitcoin).unwrap() .chain(Network::Bitcoin).unwrap()
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.chain(), mainnet); assert_eq!(invoice_request.chain(), mainnet);
assert_eq!(tlv_stream.chain, None); assert_eq!(tlv_stream.chain, None);
@ -1693,7 +1729,7 @@ mod tests {
.chain(Network::Testnet).unwrap() .chain(Network::Testnet).unwrap()
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.chain(), testnet); assert_eq!(invoice_request.chain(), testnet);
assert_eq!(tlv_stream.chain, Some(&testnet)); assert_eq!(tlv_stream.chain, Some(&testnet));
@ -1729,7 +1765,7 @@ mod tests {
.amount_msats(1000).unwrap() .amount_msats(1000).unwrap()
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.amount_msats(), Some(1000)); assert_eq!(invoice_request.amount_msats(), Some(1000));
assert_eq!(tlv_stream.amount, Some(1000)); assert_eq!(tlv_stream.amount, Some(1000));
@ -1741,7 +1777,7 @@ mod tests {
.amount_msats(1000).unwrap() .amount_msats(1000).unwrap()
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.amount_msats(), Some(1000)); assert_eq!(invoice_request.amount_msats(), Some(1000));
assert_eq!(tlv_stream.amount, Some(1000)); assert_eq!(tlv_stream.amount, Some(1000));
@ -1752,7 +1788,7 @@ mod tests {
.amount_msats(1001).unwrap() .amount_msats(1001).unwrap()
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.amount_msats(), Some(1001)); assert_eq!(invoice_request.amount_msats(), Some(1001));
assert_eq!(tlv_stream.amount, Some(1001)); assert_eq!(tlv_stream.amount, Some(1001));
@ -1832,7 +1868,7 @@ mod tests {
.features_unchecked(InvoiceRequestFeatures::unknown()) .features_unchecked(InvoiceRequestFeatures::unknown())
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.invoice_request_features(), &InvoiceRequestFeatures::unknown()); assert_eq!(invoice_request.invoice_request_features(), &InvoiceRequestFeatures::unknown());
assert_eq!(tlv_stream.features, Some(&InvoiceRequestFeatures::unknown())); assert_eq!(tlv_stream.features, Some(&InvoiceRequestFeatures::unknown()));
@ -1844,7 +1880,7 @@ mod tests {
.features_unchecked(InvoiceRequestFeatures::empty()) .features_unchecked(InvoiceRequestFeatures::empty())
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.invoice_request_features(), &InvoiceRequestFeatures::empty()); assert_eq!(invoice_request.invoice_request_features(), &InvoiceRequestFeatures::empty());
assert_eq!(tlv_stream.features, None); assert_eq!(tlv_stream.features, None);
} }
@ -1861,7 +1897,7 @@ mod tests {
.request_invoice(vec![1; 32], payer_pubkey()).unwrap() .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.quantity(), None); assert_eq!(invoice_request.quantity(), None);
assert_eq!(tlv_stream.quantity, None); assert_eq!(tlv_stream.quantity, None);
@ -1886,7 +1922,7 @@ mod tests {
.quantity(10).unwrap() .quantity(10).unwrap()
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.amount_msats(), Some(10_000)); assert_eq!(invoice_request.amount_msats(), Some(10_000));
assert_eq!(tlv_stream.amount, Some(10_000)); assert_eq!(tlv_stream.amount, Some(10_000));
@ -1911,7 +1947,7 @@ mod tests {
.quantity(2).unwrap() .quantity(2).unwrap()
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.amount_msats(), Some(2_000)); assert_eq!(invoice_request.amount_msats(), Some(2_000));
assert_eq!(tlv_stream.amount, Some(2_000)); assert_eq!(tlv_stream.amount, Some(2_000));
@ -1947,7 +1983,7 @@ mod tests {
.payer_note("bar".into()) .payer_note("bar".into())
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.payer_note(), Some(PrintableString("bar"))); assert_eq!(invoice_request.payer_note(), Some(PrintableString("bar")));
assert_eq!(tlv_stream.payer_note, Some(&String::from("bar"))); assert_eq!(tlv_stream.payer_note, Some(&String::from("bar")));
@ -1959,7 +1995,7 @@ mod tests {
.payer_note("baz".into()) .payer_note("baz".into())
.build().unwrap() .build().unwrap()
.sign(payer_sign).unwrap(); .sign(payer_sign).unwrap();
let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream(); let (_, _, tlv_stream, _, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.payer_note(), Some(PrintableString("baz"))); assert_eq!(invoice_request.payer_note(), Some(PrintableString("baz")));
assert_eq!(tlv_stream.payer_note, Some(&String::from("baz"))); assert_eq!(tlv_stream.payer_note, Some(&String::from("baz")));
} }

View file

@ -98,7 +98,7 @@ use crate::ln::channelmanager::PaymentId;
use crate::ln::features::InvoiceRequestFeatures; use crate::ln::features::InvoiceRequestFeatures;
use crate::ln::inbound_payment::{ExpandedKey, IV_LEN}; use crate::ln::inbound_payment::{ExpandedKey, IV_LEN};
use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT}; use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
use crate::offers::invoice_request::{InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef}; use crate::offers::invoice_request::{ExperimentalInvoiceRequestTlvStream, ExperimentalInvoiceRequestTlvStreamRef, InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef};
use crate::offers::nonce::Nonce; use crate::offers::nonce::Nonce;
use crate::offers::offer::{ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, OfferTlvStream, OfferTlvStreamRef}; use crate::offers::offer::{ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, OfferTlvStream, OfferTlvStreamRef};
use crate::offers::parse::{Bech32Encode, Bolt12ParseError, Bolt12SemanticError, ParsedMessage}; use crate::offers::parse::{Bech32Encode, Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
@ -787,7 +787,9 @@ impl RefundContents {
experimental_foo: self.experimental_foo, experimental_foo: self.experimental_foo,
}; };
(payer, offer, invoice_request, experimental_offer) let experimental_invoice_request = ExperimentalInvoiceRequestTlvStreamRef {};
(payer, offer, invoice_request, experimental_offer, experimental_invoice_request)
} }
} }
@ -812,6 +814,7 @@ impl Writeable for RefundContents {
type RefundTlvStream = ( type RefundTlvStream = (
PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, ExperimentalOfferTlvStream, PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, ExperimentalOfferTlvStream,
ExperimentalInvoiceRequestTlvStream,
); );
type RefundTlvStreamRef<'a> = ( type RefundTlvStreamRef<'a> = (
@ -819,6 +822,7 @@ type RefundTlvStreamRef<'a> = (
OfferTlvStreamRef<'a>, OfferTlvStreamRef<'a>,
InvoiceRequestTlvStreamRef<'a>, InvoiceRequestTlvStreamRef<'a>,
ExperimentalOfferTlvStreamRef, ExperimentalOfferTlvStreamRef,
ExperimentalInvoiceRequestTlvStreamRef,
); );
impl CursorReadable for RefundTlvStream { impl CursorReadable for RefundTlvStream {
@ -827,8 +831,9 @@ impl CursorReadable for RefundTlvStream {
let offer = CursorReadable::read(r)?; let offer = CursorReadable::read(r)?;
let invoice_request = CursorReadable::read(r)?; let invoice_request = CursorReadable::read(r)?;
let experimental_offer = CursorReadable::read(r)?; let experimental_offer = CursorReadable::read(r)?;
let experimental_invoice_request = CursorReadable::read(r)?;
Ok((payer, offer, invoice_request, experimental_offer)) Ok((payer, offer, invoice_request, experimental_offer, experimental_invoice_request))
} }
} }
@ -874,6 +879,7 @@ impl TryFrom<RefundTlvStream> for RefundContents {
#[cfg(test)] #[cfg(test)]
experimental_foo, experimental_foo,
}, },
ExperimentalInvoiceRequestTlvStream {},
) = tlv_stream; ) = tlv_stream;
let payer = match payer_metadata { let payer = match payer_metadata {
@ -971,7 +977,7 @@ mod tests {
use crate::ln::features::{InvoiceRequestFeatures, OfferFeatures}; use crate::ln::features::{InvoiceRequestFeatures, OfferFeatures};
use crate::ln::inbound_payment::ExpandedKey; use crate::ln::inbound_payment::ExpandedKey;
use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT}; use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
use crate::offers::invoice_request::{INVOICE_REQUEST_TYPES, InvoiceRequestTlvStreamRef}; use crate::offers::invoice_request::{ExperimentalInvoiceRequestTlvStreamRef, INVOICE_REQUEST_TYPES, InvoiceRequestTlvStreamRef};
use crate::offers::nonce::Nonce; use crate::offers::nonce::Nonce;
use crate::offers::offer::{ExperimentalOfferTlvStreamRef, OfferTlvStreamRef}; use crate::offers::offer::{ExperimentalOfferTlvStreamRef, OfferTlvStreamRef};
use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError}; use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError};
@ -1044,6 +1050,7 @@ mod tests {
ExperimentalOfferTlvStreamRef { ExperimentalOfferTlvStreamRef {
experimental_foo: None, experimental_foo: None,
}, },
ExperimentalInvoiceRequestTlvStreamRef {},
), ),
); );
@ -1198,7 +1205,7 @@ mod tests {
.absolute_expiry(future_expiry) .absolute_expiry(future_expiry)
.build() .build()
.unwrap(); .unwrap();
let (_, tlv_stream, _, _) = refund.as_tlv_stream(); let (_, tlv_stream, _, _, _) = refund.as_tlv_stream();
#[cfg(feature = "std")] #[cfg(feature = "std")]
assert!(!refund.is_expired()); assert!(!refund.is_expired());
assert!(!refund.is_expired_no_std(now)); assert!(!refund.is_expired_no_std(now));
@ -1210,7 +1217,7 @@ mod tests {
.absolute_expiry(past_expiry) .absolute_expiry(past_expiry)
.build() .build()
.unwrap(); .unwrap();
let (_, tlv_stream, _, _) = refund.as_tlv_stream(); let (_, tlv_stream, _, _, _) = refund.as_tlv_stream();
#[cfg(feature = "std")] #[cfg(feature = "std")]
assert!(refund.is_expired()); assert!(refund.is_expired());
assert!(refund.is_expired_no_std(now)); assert!(refund.is_expired_no_std(now));
@ -1242,7 +1249,7 @@ mod tests {
.path(paths[1].clone()) .path(paths[1].clone())
.build() .build()
.unwrap(); .unwrap();
let (_, _, invoice_request_tlv_stream, _) = refund.as_tlv_stream(); let (_, _, invoice_request_tlv_stream, _, _) = refund.as_tlv_stream();
assert_eq!(refund.payer_signing_pubkey(), pubkey(42)); assert_eq!(refund.payer_signing_pubkey(), pubkey(42));
assert_eq!(refund.paths(), paths.as_slice()); assert_eq!(refund.paths(), paths.as_slice());
assert_ne!(pubkey(42), pubkey(44)); assert_ne!(pubkey(42), pubkey(44));
@ -1256,7 +1263,7 @@ mod tests {
.issuer("bar".into()) .issuer("bar".into())
.build() .build()
.unwrap(); .unwrap();
let (_, tlv_stream, _, _) = refund.as_tlv_stream(); let (_, tlv_stream, _, _, _) = refund.as_tlv_stream();
assert_eq!(refund.issuer(), Some(PrintableString("bar"))); assert_eq!(refund.issuer(), Some(PrintableString("bar")));
assert_eq!(tlv_stream.issuer, Some(&String::from("bar"))); assert_eq!(tlv_stream.issuer, Some(&String::from("bar")));
@ -1265,7 +1272,7 @@ mod tests {
.issuer("baz".into()) .issuer("baz".into())
.build() .build()
.unwrap(); .unwrap();
let (_, tlv_stream, _, _) = refund.as_tlv_stream(); let (_, tlv_stream, _, _, _) = refund.as_tlv_stream();
assert_eq!(refund.issuer(), Some(PrintableString("baz"))); assert_eq!(refund.issuer(), Some(PrintableString("baz")));
assert_eq!(tlv_stream.issuer, Some(&String::from("baz"))); assert_eq!(tlv_stream.issuer, Some(&String::from("baz")));
} }
@ -1278,14 +1285,14 @@ mod tests {
let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap() let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap()
.chain(Network::Bitcoin) .chain(Network::Bitcoin)
.build().unwrap(); .build().unwrap();
let (_, _, tlv_stream, _) = refund.as_tlv_stream(); let (_, _, tlv_stream, _, _) = refund.as_tlv_stream();
assert_eq!(refund.chain(), mainnet); assert_eq!(refund.chain(), mainnet);
assert_eq!(tlv_stream.chain, None); assert_eq!(tlv_stream.chain, None);
let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap() let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap()
.chain(Network::Testnet) .chain(Network::Testnet)
.build().unwrap(); .build().unwrap();
let (_, _, tlv_stream, _) = refund.as_tlv_stream(); let (_, _, tlv_stream, _, _) = refund.as_tlv_stream();
assert_eq!(refund.chain(), testnet); assert_eq!(refund.chain(), testnet);
assert_eq!(tlv_stream.chain, Some(&testnet)); assert_eq!(tlv_stream.chain, Some(&testnet));
@ -1293,7 +1300,7 @@ mod tests {
.chain(Network::Regtest) .chain(Network::Regtest)
.chain(Network::Testnet) .chain(Network::Testnet)
.build().unwrap(); .build().unwrap();
let (_, _, tlv_stream, _) = refund.as_tlv_stream(); let (_, _, tlv_stream, _, _) = refund.as_tlv_stream();
assert_eq!(refund.chain(), testnet); assert_eq!(refund.chain(), testnet);
assert_eq!(tlv_stream.chain, Some(&testnet)); assert_eq!(tlv_stream.chain, Some(&testnet));
} }
@ -1303,7 +1310,7 @@ mod tests {
let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap() let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap()
.quantity(10) .quantity(10)
.build().unwrap(); .build().unwrap();
let (_, _, tlv_stream, _) = refund.as_tlv_stream(); let (_, _, tlv_stream, _, _) = refund.as_tlv_stream();
assert_eq!(refund.quantity(), Some(10)); assert_eq!(refund.quantity(), Some(10));
assert_eq!(tlv_stream.quantity, Some(10)); assert_eq!(tlv_stream.quantity, Some(10));
@ -1311,7 +1318,7 @@ mod tests {
.quantity(10) .quantity(10)
.quantity(1) .quantity(1)
.build().unwrap(); .build().unwrap();
let (_, _, tlv_stream, _) = refund.as_tlv_stream(); let (_, _, tlv_stream, _, _) = refund.as_tlv_stream();
assert_eq!(refund.quantity(), Some(1)); assert_eq!(refund.quantity(), Some(1));
assert_eq!(tlv_stream.quantity, Some(1)); assert_eq!(tlv_stream.quantity, Some(1));
} }
@ -1321,7 +1328,7 @@ mod tests {
let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap() let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap()
.payer_note("bar".into()) .payer_note("bar".into())
.build().unwrap(); .build().unwrap();
let (_, _, tlv_stream, _) = refund.as_tlv_stream(); let (_, _, tlv_stream, _, _) = refund.as_tlv_stream();
assert_eq!(refund.payer_note(), Some(PrintableString("bar"))); assert_eq!(refund.payer_note(), Some(PrintableString("bar")));
assert_eq!(tlv_stream.payer_note, Some(&String::from("bar"))); assert_eq!(tlv_stream.payer_note, Some(&String::from("bar")));
@ -1329,7 +1336,7 @@ mod tests {
.payer_note("bar".into()) .payer_note("bar".into())
.payer_note("baz".into()) .payer_note("baz".into())
.build().unwrap(); .build().unwrap();
let (_, _, tlv_stream, _) = refund.as_tlv_stream(); let (_, _, tlv_stream, _, _) = refund.as_tlv_stream();
assert_eq!(refund.payer_note(), Some(PrintableString("baz"))); assert_eq!(refund.payer_note(), Some(PrintableString("baz")));
assert_eq!(tlv_stream.payer_note, Some(&String::from("baz"))); assert_eq!(tlv_stream.payer_note, Some(&String::from("baz")));
} }

View file

@ -1466,6 +1466,28 @@ impl<A: Writeable, B: Writeable, C: Writeable, D: Writeable, E: Writeable> Write
} }
} }
impl<A: Readable, B: Readable, C: Readable, D: Readable, E: Readable, F: Readable> Readable for (A, B, C, D, E, F) {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let a: A = Readable::read(r)?;
let b: B = Readable::read(r)?;
let c: C = Readable::read(r)?;
let d: D = Readable::read(r)?;
let e: E = Readable::read(r)?;
let f: F = Readable::read(r)?;
Ok((a, b, c, d, e, f))
}
}
impl<A: Writeable, B: Writeable, C: Writeable, D: Writeable, E: Writeable, F: Writeable> Writeable for (A, B, C, D, E, F) {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
self.0.write(w)?;
self.1.write(w)?;
self.2.write(w)?;
self.3.write(w)?;
self.4.write(w)?;
self.5.write(w)
}
}
impl Writeable for () { impl Writeable for () {
fn write<W: Writer>(&self, _: &mut W) -> Result<(), io::Error> { fn write<W: Writer>(&self, _: &mut W) -> Result<(), io::Error> {
Ok(()) Ok(())