@@ -497,7 +497,8 @@ 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, _, _, experimental_invoice_tlv_stream) =
501+ contents. as_tlv_stream ( ) ;
501502
502503 // Allocate enough space for the invoice, which will include:
503504 // - all TLV records from `invreq_bytes` except signatures,
@@ -510,6 +511,7 @@ impl UnsignedBolt12Invoice {
510511 invreq_bytes. len ( )
511512 + invoice_tlv_stream. serialized_length ( )
512513 + if contents. is_for_offer ( ) { 0 } else { SIGNATURE_TLV_RECORD_SIZE }
514+ + experimental_invoice_tlv_stream. serialized_length ( ) ,
513515 ) ;
514516
515517 // Use the invoice_request bytes instead of the invoice_request TLV stream as the latter may
@@ -531,12 +533,14 @@ impl UnsignedBolt12Invoice {
531533 - experimental_tlv_stream
532534 . peek ( )
533535 . map_or ( remaining_bytes. len ( ) , |first_record| first_record. start )
536+ + experimental_invoice_tlv_stream. serialized_length ( ) ,
534537 ) ;
535538
536539 for record in experimental_tlv_stream {
537540 record. write ( & mut experimental_bytes) . unwrap ( ) ;
538541 }
539542
543+ experimental_invoice_tlv_stream. write ( & mut experimental_bytes) . unwrap ( ) ;
540544 debug_assert_eq ! ( experimental_bytes. len( ) , experimental_bytes. capacity( ) ) ;
541545
542546 let tlv_stream = TlvStream :: new ( & bytes) . chain ( TlvStream :: new ( & experimental_bytes) ) ;
@@ -904,14 +908,15 @@ impl Bolt12Invoice {
904908 let (
905909 payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
906910 experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
911+ experimental_invoice_tlv_stream,
907912 ) = self . contents . as_tlv_stream ( ) ;
908913 let signature_tlv_stream = SignatureTlvStreamRef {
909914 signature : Some ( & self . signature ) ,
910915 } ;
911916 (
912917 payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
913918 signature_tlv_stream, experimental_offer_tlv_stream,
914- experimental_invoice_request_tlv_stream,
919+ experimental_invoice_request_tlv_stream, experimental_invoice_tlv_stream ,
915920 )
916921 }
917922
@@ -1179,9 +1184,12 @@ impl InvoiceContents {
11791184 InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. as_tlv_stream ( ) ,
11801185 InvoiceContents :: ForRefund { refund, .. } => refund. as_tlv_stream ( ) ,
11811186 } ;
1182- let invoice = self . fields ( ) . as_tlv_stream ( ) ;
1187+ let ( invoice, experimental_invoice ) = self . fields ( ) . as_tlv_stream ( ) ;
11831188
1184- ( payer, offer, invoice_request, invoice, experimental_offer, experimental_invoice_request)
1189+ (
1190+ payer, offer, invoice_request, invoice, experimental_offer,
1191+ experimental_invoice_request, experimental_invoice,
1192+ )
11851193 }
11861194}
11871195
@@ -1229,24 +1237,27 @@ pub(super) fn filter_fallbacks(
12291237}
12301238
12311239impl InvoiceFields {
1232- fn as_tlv_stream ( & self ) -> InvoiceTlvStreamRef {
1240+ fn as_tlv_stream ( & self ) -> ( InvoiceTlvStreamRef , ExperimentalInvoiceTlvStreamRef ) {
12331241 let features = {
12341242 if self . features == Bolt12InvoiceFeatures :: empty ( ) { None }
12351243 else { Some ( & self . features ) }
12361244 } ;
12371245
1238- InvoiceTlvStreamRef {
1239- paths : Some ( Iterable ( self . payment_paths . iter ( ) . map ( |path| path. inner_blinded_path ( ) ) ) ) ,
1240- blindedpay : Some ( Iterable ( self . payment_paths . iter ( ) . map ( |path| & path. payinfo ) ) ) ,
1241- created_at : Some ( self . created_at . as_secs ( ) ) ,
1242- relative_expiry : self . relative_expiry . map ( |duration| duration. as_secs ( ) as u32 ) ,
1243- payment_hash : Some ( & self . payment_hash ) ,
1244- amount : Some ( self . amount_msats ) ,
1245- fallbacks : self . fallbacks . as_ref ( ) ,
1246- features,
1247- node_id : Some ( & self . signing_pubkey ) ,
1248- message_paths : None ,
1249- }
1246+ (
1247+ InvoiceTlvStreamRef {
1248+ paths : Some ( Iterable ( self . payment_paths . iter ( ) . map ( |path| path. inner_blinded_path ( ) ) ) ) ,
1249+ blindedpay : Some ( Iterable ( self . payment_paths . iter ( ) . map ( |path| & path. payinfo ) ) ) ,
1250+ created_at : Some ( self . created_at . as_secs ( ) ) ,
1251+ relative_expiry : self . relative_expiry . map ( |duration| duration. as_secs ( ) as u32 ) ,
1252+ payment_hash : Some ( & self . payment_hash ) ,
1253+ amount : Some ( self . amount_msats ) ,
1254+ fallbacks : self . fallbacks . as_ref ( ) ,
1255+ features,
1256+ node_id : Some ( & self . signing_pubkey ) ,
1257+ message_paths : None ,
1258+ } ,
1259+ ExperimentalInvoiceTlvStreamRef { } ,
1260+ )
12501261 }
12511262}
12521263
@@ -1321,6 +1332,13 @@ tlv_stream!(InvoiceTlvStream, InvoiceTlvStreamRef<'a>, INVOICE_TYPES, {
13211332 ( 236 , message_paths: ( Vec <BlindedMessagePath >, WithoutLength ) ) ,
13221333} ) ;
13231334
1335+ /// Valid type range for experimental invoice TLV records.
1336+ const EXPERIMENTAL_INVOICE_TYPES : core:: ops:: RangeFrom < u64 > = 3_000_000_000 ..;
1337+
1338+ tlv_stream ! (
1339+ ExperimentalInvoiceTlvStream , ExperimentalInvoiceTlvStreamRef , EXPERIMENTAL_INVOICE_TYPES , { }
1340+ ) ;
1341+
13241342pub ( super ) type BlindedPathIter < ' a > = core:: iter:: Map <
13251343 core:: slice:: Iter < ' a , BlindedPaymentPath > ,
13261344 for <' r > fn ( & ' r BlindedPaymentPath ) -> & ' r BlindedPath ,
@@ -1342,7 +1360,7 @@ impl_writeable!(FallbackAddress, { version, program });
13421360
13431361type FullInvoiceTlvStream =(
13441362 PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream , SignatureTlvStream ,
1345- ExperimentalOfferTlvStream , ExperimentalInvoiceRequestTlvStream ,
1363+ ExperimentalOfferTlvStream , ExperimentalInvoiceRequestTlvStream , ExperimentalInvoiceTlvStream ,
13461364) ;
13471365
13481366type FullInvoiceTlvStreamRef < ' a > = (
@@ -1353,6 +1371,7 @@ type FullInvoiceTlvStreamRef<'a> = (
13531371 SignatureTlvStreamRef < ' a > ,
13541372 ExperimentalOfferTlvStreamRef ,
13551373 ExperimentalInvoiceRequestTlvStreamRef ,
1374+ ExperimentalInvoiceTlvStreamRef ,
13561375) ;
13571376
13581377impl CursorReadable for FullInvoiceTlvStream {
@@ -1364,19 +1383,20 @@ impl CursorReadable for FullInvoiceTlvStream {
13641383 let signature = CursorReadable :: read ( r) ?;
13651384 let experimental_offer = CursorReadable :: read ( r) ?;
13661385 let experimental_invoice_request = CursorReadable :: read ( r) ?;
1386+ let experimental_invoice = CursorReadable :: read ( r) ?;
13671387
13681388 Ok (
13691389 (
13701390 payer, offer, invoice_request, invoice, signature, experimental_offer,
1371- experimental_invoice_request,
1391+ experimental_invoice_request, experimental_invoice ,
13721392 )
13731393 )
13741394 }
13751395}
13761396
13771397type PartialInvoiceTlvStream = (
13781398 PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream ,
1379- ExperimentalOfferTlvStream , ExperimentalInvoiceRequestTlvStream ,
1399+ ExperimentalOfferTlvStream , ExperimentalInvoiceRequestTlvStream , ExperimentalInvoiceTlvStream ,
13801400) ;
13811401
13821402type PartialInvoiceTlvStreamRef < ' a > = (
@@ -1386,6 +1406,7 @@ type PartialInvoiceTlvStreamRef<'a> = (
13861406 InvoiceTlvStreamRef < ' a > ,
13871407 ExperimentalOfferTlvStreamRef ,
13881408 ExperimentalInvoiceRequestTlvStreamRef ,
1409+ ExperimentalInvoiceTlvStreamRef ,
13891410) ;
13901411
13911412impl CursorReadable for PartialInvoiceTlvStream {
@@ -1396,11 +1417,12 @@ impl CursorReadable for PartialInvoiceTlvStream {
13961417 let invoice = CursorReadable :: read ( r) ?;
13971418 let experimental_offer = CursorReadable :: read ( r) ?;
13981419 let experimental_invoice_request = CursorReadable :: read ( r) ?;
1420+ let experimental_invoice = CursorReadable :: read ( r) ?;
13991421
14001422 Ok (
14011423 (
14021424 payer, offer, invoice_request, invoice, experimental_offer,
1403- experimental_invoice_request,
1425+ experimental_invoice_request, experimental_invoice ,
14041426 )
14051427 )
14061428 }
@@ -1416,11 +1438,13 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
14161438 SignatureTlvStream { signature } ,
14171439 experimental_offer_tlv_stream,
14181440 experimental_invoice_request_tlv_stream,
1441+ experimental_invoice_tlv_stream,
14191442 ) = tlv_stream;
14201443 let contents = InvoiceContents :: try_from (
14211444 (
14221445 payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
14231446 experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
1447+ experimental_invoice_tlv_stream,
14241448 )
14251449 ) ?;
14261450
@@ -1449,6 +1473,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14491473 } ,
14501474 experimental_offer_tlv_stream,
14511475 experimental_invoice_request_tlv_stream,
1476+ ExperimentalInvoiceTlvStream { } ,
14521477 ) = tlv_stream;
14531478
14541479 if message_paths. is_some ( ) { return Err ( Bolt12SemanticError :: UnexpectedPaths ) }
@@ -1545,7 +1570,7 @@ pub(super) fn check_invoice_signing_pubkey(
15451570
15461571#[ cfg( test) ]
15471572mod tests {
1548- use super :: { Bolt12Invoice , DEFAULT_RELATIVE_EXPIRY , FallbackAddress , FullInvoiceTlvStreamRef , INVOICE_TYPES , InvoiceTlvStreamRef , SIGNATURE_TAG , UnsignedBolt12Invoice } ;
1573+ use super :: { Bolt12Invoice , DEFAULT_RELATIVE_EXPIRY , ExperimentalInvoiceTlvStreamRef , FallbackAddress , FullInvoiceTlvStreamRef , INVOICE_TYPES , InvoiceTlvStreamRef , SIGNATURE_TAG , UnsignedBolt12Invoice } ;
15491574
15501575 use bitcoin:: { CompressedPublicKey , WitnessProgram , WitnessVersion } ;
15511576 use bitcoin:: constants:: ChainHash ;
@@ -1741,6 +1766,7 @@ mod tests {
17411766 ExperimentalInvoiceRequestTlvStreamRef {
17421767 experimental_bar: None ,
17431768 } ,
1769+ ExperimentalInvoiceTlvStreamRef { } ,
17441770 ) ,
17451771 ) ;
17461772
@@ -1840,6 +1866,7 @@ mod tests {
18401866 ExperimentalInvoiceRequestTlvStreamRef {
18411867 experimental_bar: None ,
18421868 } ,
1869+ ExperimentalInvoiceTlvStreamRef { } ,
18431870 ) ,
18441871 ) ;
18451872
@@ -2036,7 +2063,7 @@ mod tests {
20362063 . relative_expiry ( one_hour. as_secs ( ) as u32 )
20372064 . build ( ) . unwrap ( )
20382065 . sign ( recipient_sign) . unwrap ( ) ;
2039- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2066+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
20402067 #[ cfg( feature = "std" ) ]
20412068 assert ! ( !invoice. is_expired( ) ) ;
20422069 assert_eq ! ( invoice. relative_expiry( ) , one_hour) ;
@@ -2052,7 +2079,7 @@ mod tests {
20522079 . relative_expiry ( one_hour. as_secs ( ) as u32 - 1 )
20532080 . build ( ) . unwrap ( )
20542081 . sign ( recipient_sign) . unwrap ( ) ;
2055- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2082+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
20562083 #[ cfg( feature = "std" ) ]
20572084 assert ! ( invoice. is_expired( ) ) ;
20582085 assert_eq ! ( invoice. relative_expiry( ) , one_hour - Duration :: from_secs( 1 ) ) ;
@@ -2071,7 +2098,7 @@ mod tests {
20712098 . respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
20722099 . build ( ) . unwrap ( )
20732100 . sign ( recipient_sign) . unwrap ( ) ;
2074- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2101+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
20752102 assert_eq ! ( invoice. amount_msats( ) , 1001 ) ;
20762103 assert_eq ! ( tlv_stream. amount, Some ( 1001 ) ) ;
20772104 }
@@ -2089,7 +2116,7 @@ mod tests {
20892116 . respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
20902117 . build ( ) . unwrap ( )
20912118 . sign ( recipient_sign) . unwrap ( ) ;
2092- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2119+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
20932120 assert_eq ! ( invoice. amount_msats( ) , 2000 ) ;
20942121 assert_eq ! ( tlv_stream. amount, Some ( 2000 ) ) ;
20952122
@@ -2127,7 +2154,7 @@ mod tests {
21272154 . fallback_v1_p2tr_tweaked ( & tweaked_pubkey)
21282155 . build ( ) . unwrap ( )
21292156 . sign ( recipient_sign) . unwrap ( ) ;
2130- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2157+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
21312158 assert_eq ! (
21322159 invoice. fallbacks( ) ,
21332160 vec![
@@ -2170,7 +2197,7 @@ mod tests {
21702197 . allow_mpp ( )
21712198 . build ( ) . unwrap ( )
21722199 . sign ( recipient_sign) . unwrap ( ) ;
2173- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2200+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
21742201 assert_eq ! ( invoice. invoice_features( ) , & features) ;
21752202 assert_eq ! ( tlv_stream. features, Some ( & features) ) ;
21762203 }
0 commit comments