@@ -497,7 +497,8 @@ impl UnsignedBolt12Invoice {
497
497
const EXPERIMENTAL_TYPES : core:: ops:: Range < u64 > =
498
498
EXPERIMENTAL_OFFER_TYPES . start ..EXPERIMENTAL_INVOICE_REQUEST_TYPES . end ;
499
499
500
- let ( _, _, _, invoice_tlv_stream, _, _) = contents. as_tlv_stream ( ) ;
500
+ let ( _, _, _, invoice_tlv_stream, _, _, experimental_invoice_tlv_stream) =
501
+ contents. as_tlv_stream ( ) ;
501
502
502
503
// Allocate enough space for the invoice, which will include:
503
504
// - all TLV records from `invreq_bytes` except signatures,
@@ -510,6 +511,7 @@ impl UnsignedBolt12Invoice {
510
511
invreq_bytes. len ( )
511
512
+ invoice_tlv_stream. serialized_length ( )
512
513
+ if contents. is_for_offer ( ) { 0 } else { SIGNATURE_TLV_RECORD_SIZE }
514
+ + experimental_invoice_tlv_stream. serialized_length ( ) ,
513
515
) ;
514
516
515
517
// Use the invoice_request bytes instead of the invoice_request TLV stream as the latter may
@@ -531,12 +533,15 @@ impl UnsignedBolt12Invoice {
531
533
- experimental_tlv_stream
532
534
. peek ( )
533
535
. map_or ( remaining_bytes. len ( ) , |first_record| first_record. start )
536
+ + experimental_invoice_tlv_stream. serialized_length ( ) ,
534
537
) ;
535
538
536
539
for record in experimental_tlv_stream {
537
540
record. write ( & mut experimental_bytes) . unwrap ( ) ;
538
541
}
539
542
543
+ experimental_invoice_tlv_stream. write ( & mut experimental_bytes) . unwrap ( ) ;
544
+
540
545
let tlv_stream = TlvStream :: new ( & bytes) . chain ( TlvStream :: new ( & experimental_bytes) ) ;
541
546
let tagged_hash = TaggedHash :: from_tlv_stream ( SIGNATURE_TAG , tlv_stream) ;
542
547
@@ -894,14 +899,15 @@ impl Bolt12Invoice {
894
899
let (
895
900
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
896
901
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
902
+ experimental_invoice_tlv_stream,
897
903
) = self . contents . as_tlv_stream ( ) ;
898
904
let signature_tlv_stream = SignatureTlvStreamRef {
899
905
signature : Some ( & self . signature ) ,
900
906
} ;
901
907
(
902
908
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
903
909
signature_tlv_stream, experimental_offer_tlv_stream,
904
- experimental_invoice_request_tlv_stream,
910
+ experimental_invoice_request_tlv_stream, experimental_invoice_tlv_stream ,
905
911
)
906
912
}
907
913
@@ -1169,9 +1175,12 @@ impl InvoiceContents {
1169
1175
InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. as_tlv_stream ( ) ,
1170
1176
InvoiceContents :: ForRefund { refund, .. } => refund. as_tlv_stream ( ) ,
1171
1177
} ;
1172
- let invoice = self . fields ( ) . as_tlv_stream ( ) ;
1178
+ let ( invoice, experimental_invoice ) = self . fields ( ) . as_tlv_stream ( ) ;
1173
1179
1174
- ( payer, offer, invoice_request, invoice, experimental_offer, experimental_invoice_request)
1180
+ (
1181
+ payer, offer, invoice_request, invoice, experimental_offer,
1182
+ experimental_invoice_request, experimental_invoice,
1183
+ )
1175
1184
}
1176
1185
}
1177
1186
@@ -1219,24 +1228,27 @@ pub(super) fn filter_fallbacks(
1219
1228
}
1220
1229
1221
1230
impl InvoiceFields {
1222
- fn as_tlv_stream ( & self ) -> InvoiceTlvStreamRef {
1231
+ fn as_tlv_stream ( & self ) -> ( InvoiceTlvStreamRef , ExperimentalInvoiceTlvStreamRef ) {
1223
1232
let features = {
1224
1233
if self . features == Bolt12InvoiceFeatures :: empty ( ) { None }
1225
1234
else { Some ( & self . features ) }
1226
1235
} ;
1227
1236
1228
- InvoiceTlvStreamRef {
1229
- paths : Some ( Iterable ( self . payment_paths . iter ( ) . map ( |path| path. inner_blinded_path ( ) ) ) ) ,
1230
- blindedpay : Some ( Iterable ( self . payment_paths . iter ( ) . map ( |path| & path. payinfo ) ) ) ,
1231
- created_at : Some ( self . created_at . as_secs ( ) ) ,
1232
- relative_expiry : self . relative_expiry . map ( |duration| duration. as_secs ( ) as u32 ) ,
1233
- payment_hash : Some ( & self . payment_hash ) ,
1234
- amount : Some ( self . amount_msats ) ,
1235
- fallbacks : self . fallbacks . as_ref ( ) ,
1236
- features,
1237
- node_id : Some ( & self . signing_pubkey ) ,
1238
- message_paths : None ,
1239
- }
1237
+ (
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
+ } ,
1250
+ ExperimentalInvoiceTlvStreamRef { } ,
1251
+ )
1240
1252
}
1241
1253
}
1242
1254
@@ -1311,6 +1323,13 @@ tlv_stream!(InvoiceTlvStream, InvoiceTlvStreamRef<'a>, INVOICE_TYPES, {
1311
1323
( 236 , message_paths: ( Vec <BlindedMessagePath >, WithoutLength ) ) ,
1312
1324
} ) ;
1313
1325
1326
+ /// Valid type range for experimental invoice TLV records.
1327
+ const EXPERIMENTAL_INVOICE_TYPES : core:: ops:: RangeFrom < u64 > = 3_000_000_000 ..;
1328
+
1329
+ tlv_stream ! (
1330
+ ExperimentalInvoiceTlvStream , ExperimentalInvoiceTlvStreamRef , EXPERIMENTAL_INVOICE_TYPES , { }
1331
+ ) ;
1332
+
1314
1333
pub ( super ) type BlindedPathIter < ' a > = core:: iter:: Map <
1315
1334
core:: slice:: Iter < ' a , BlindedPaymentPath > ,
1316
1335
for <' r > fn ( & ' r BlindedPaymentPath ) -> & ' r BlindedPath ,
@@ -1332,7 +1351,7 @@ impl_writeable!(FallbackAddress, { version, program });
1332
1351
1333
1352
type FullInvoiceTlvStream =(
1334
1353
PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream , SignatureTlvStream ,
1335
- ExperimentalOfferTlvStream , ExperimentalInvoiceRequestTlvStream ,
1354
+ ExperimentalOfferTlvStream , ExperimentalInvoiceRequestTlvStream , ExperimentalInvoiceTlvStream ,
1336
1355
) ;
1337
1356
1338
1357
type FullInvoiceTlvStreamRef < ' a > = (
@@ -1343,6 +1362,7 @@ type FullInvoiceTlvStreamRef<'a> = (
1343
1362
SignatureTlvStreamRef < ' a > ,
1344
1363
ExperimentalOfferTlvStreamRef ,
1345
1364
ExperimentalInvoiceRequestTlvStreamRef ,
1365
+ ExperimentalInvoiceTlvStreamRef ,
1346
1366
) ;
1347
1367
1348
1368
impl CursorReadable for FullInvoiceTlvStream {
@@ -1354,19 +1374,20 @@ impl CursorReadable for FullInvoiceTlvStream {
1354
1374
let signature = CursorReadable :: read ( r) ?;
1355
1375
let experimental_offer = CursorReadable :: read ( r) ?;
1356
1376
let experimental_invoice_request = CursorReadable :: read ( r) ?;
1377
+ let experimental_invoice = CursorReadable :: read ( r) ?;
1357
1378
1358
1379
Ok (
1359
1380
(
1360
1381
payer, offer, invoice_request, invoice, signature, experimental_offer,
1361
- experimental_invoice_request,
1382
+ experimental_invoice_request, experimental_invoice ,
1362
1383
)
1363
1384
)
1364
1385
}
1365
1386
}
1366
1387
1367
1388
type PartialInvoiceTlvStream = (
1368
1389
PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream ,
1369
- ExperimentalOfferTlvStream , ExperimentalInvoiceRequestTlvStream ,
1390
+ ExperimentalOfferTlvStream , ExperimentalInvoiceRequestTlvStream , ExperimentalInvoiceTlvStream ,
1370
1391
) ;
1371
1392
1372
1393
type PartialInvoiceTlvStreamRef < ' a > = (
@@ -1376,6 +1397,7 @@ type PartialInvoiceTlvStreamRef<'a> = (
1376
1397
InvoiceTlvStreamRef < ' a > ,
1377
1398
ExperimentalOfferTlvStreamRef ,
1378
1399
ExperimentalInvoiceRequestTlvStreamRef ,
1400
+ ExperimentalInvoiceTlvStreamRef ,
1379
1401
) ;
1380
1402
1381
1403
impl CursorReadable for PartialInvoiceTlvStream {
@@ -1386,11 +1408,12 @@ impl CursorReadable for PartialInvoiceTlvStream {
1386
1408
let invoice = CursorReadable :: read ( r) ?;
1387
1409
let experimental_offer = CursorReadable :: read ( r) ?;
1388
1410
let experimental_invoice_request = CursorReadable :: read ( r) ?;
1411
+ let experimental_invoice = CursorReadable :: read ( r) ?;
1389
1412
1390
1413
Ok (
1391
1414
(
1392
1415
payer, offer, invoice_request, invoice, experimental_offer,
1393
- experimental_invoice_request,
1416
+ experimental_invoice_request, experimental_invoice ,
1394
1417
)
1395
1418
)
1396
1419
}
@@ -1406,11 +1429,13 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
1406
1429
SignatureTlvStream { signature } ,
1407
1430
experimental_offer_tlv_stream,
1408
1431
experimental_invoice_request_tlv_stream,
1432
+ experimental_invoice_tlv_stream,
1409
1433
) = tlv_stream;
1410
1434
let contents = InvoiceContents :: try_from (
1411
1435
(
1412
1436
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1413
1437
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
1438
+ experimental_invoice_tlv_stream,
1414
1439
)
1415
1440
) ?;
1416
1441
@@ -1439,6 +1464,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
1439
1464
} ,
1440
1465
experimental_offer_tlv_stream,
1441
1466
experimental_invoice_request_tlv_stream,
1467
+ ExperimentalInvoiceTlvStream { } ,
1442
1468
) = tlv_stream;
1443
1469
1444
1470
if message_paths. is_some ( ) { return Err ( Bolt12SemanticError :: UnexpectedPaths ) }
@@ -1535,7 +1561,7 @@ pub(super) fn check_invoice_signing_pubkey(
1535
1561
1536
1562
#[ cfg( test) ]
1537
1563
mod tests {
1538
- use super :: { Bolt12Invoice , DEFAULT_RELATIVE_EXPIRY , FallbackAddress , FullInvoiceTlvStreamRef , INVOICE_TYPES , InvoiceTlvStreamRef , SIGNATURE_TAG , UnsignedBolt12Invoice } ;
1564
+ use super :: { Bolt12Invoice , DEFAULT_RELATIVE_EXPIRY , ExperimentalInvoiceTlvStreamRef , FallbackAddress , FullInvoiceTlvStreamRef , INVOICE_TYPES , InvoiceTlvStreamRef , SIGNATURE_TAG , UnsignedBolt12Invoice } ;
1539
1565
1540
1566
use bitcoin:: { CompressedPublicKey , WitnessProgram , WitnessVersion } ;
1541
1567
use bitcoin:: constants:: ChainHash ;
@@ -1731,6 +1757,7 @@ mod tests {
1731
1757
ExperimentalInvoiceRequestTlvStreamRef {
1732
1758
experimental_bar: None ,
1733
1759
} ,
1760
+ ExperimentalInvoiceTlvStreamRef { } ,
1734
1761
) ,
1735
1762
) ;
1736
1763
@@ -1830,6 +1857,7 @@ mod tests {
1830
1857
ExperimentalInvoiceRequestTlvStreamRef {
1831
1858
experimental_bar: None ,
1832
1859
} ,
1860
+ ExperimentalInvoiceTlvStreamRef { } ,
1833
1861
) ,
1834
1862
) ;
1835
1863
@@ -2026,7 +2054,7 @@ mod tests {
2026
2054
. relative_expiry ( one_hour. as_secs ( ) as u32 )
2027
2055
. build ( ) . unwrap ( )
2028
2056
. sign ( recipient_sign) . unwrap ( ) ;
2029
- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2057
+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
2030
2058
#[ cfg( feature = "std" ) ]
2031
2059
assert ! ( !invoice. is_expired( ) ) ;
2032
2060
assert_eq ! ( invoice. relative_expiry( ) , one_hour) ;
@@ -2042,7 +2070,7 @@ mod tests {
2042
2070
. relative_expiry ( one_hour. as_secs ( ) as u32 - 1 )
2043
2071
. build ( ) . unwrap ( )
2044
2072
. sign ( recipient_sign) . unwrap ( ) ;
2045
- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2073
+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
2046
2074
#[ cfg( feature = "std" ) ]
2047
2075
assert ! ( invoice. is_expired( ) ) ;
2048
2076
assert_eq ! ( invoice. relative_expiry( ) , one_hour - Duration :: from_secs( 1 ) ) ;
@@ -2061,7 +2089,7 @@ mod tests {
2061
2089
. respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
2062
2090
. build ( ) . unwrap ( )
2063
2091
. sign ( recipient_sign) . unwrap ( ) ;
2064
- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2092
+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
2065
2093
assert_eq ! ( invoice. amount_msats( ) , 1001 ) ;
2066
2094
assert_eq ! ( tlv_stream. amount, Some ( 1001 ) ) ;
2067
2095
}
@@ -2079,7 +2107,7 @@ mod tests {
2079
2107
. respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
2080
2108
. build ( ) . unwrap ( )
2081
2109
. sign ( recipient_sign) . unwrap ( ) ;
2082
- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2110
+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
2083
2111
assert_eq ! ( invoice. amount_msats( ) , 2000 ) ;
2084
2112
assert_eq ! ( tlv_stream. amount, Some ( 2000 ) ) ;
2085
2113
@@ -2117,7 +2145,7 @@ mod tests {
2117
2145
. fallback_v1_p2tr_tweaked ( & tweaked_pubkey)
2118
2146
. build ( ) . unwrap ( )
2119
2147
. sign ( recipient_sign) . unwrap ( ) ;
2120
- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2148
+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
2121
2149
assert_eq ! (
2122
2150
invoice. fallbacks( ) ,
2123
2151
vec![
@@ -2160,7 +2188,7 @@ mod tests {
2160
2188
. allow_mpp ( )
2161
2189
. build ( ) . unwrap ( )
2162
2190
. sign ( recipient_sign) . unwrap ( ) ;
2163
- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2191
+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
2164
2192
assert_eq ! ( invoice. invoice_features( ) , & features) ;
2165
2193
assert_eq ! ( tlv_stream. features, Some ( & features) ) ;
2166
2194
}
0 commit comments