@@ -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,14 @@ 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 ( ) ;
540
544
debug_assert_eq ! ( experimental_bytes. len( ) , experimental_bytes. capacity( ) ) ;
541
545
542
546
let tlv_stream = TlvStream :: new ( & bytes) . chain ( TlvStream :: new ( & experimental_bytes) ) ;
@@ -904,14 +908,15 @@ impl Bolt12Invoice {
904
908
let (
905
909
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
906
910
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
911
+ experimental_invoice_tlv_stream,
907
912
) = self . contents . as_tlv_stream ( ) ;
908
913
let signature_tlv_stream = SignatureTlvStreamRef {
909
914
signature : Some ( & self . signature ) ,
910
915
} ;
911
916
(
912
917
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
913
918
signature_tlv_stream, experimental_offer_tlv_stream,
914
- experimental_invoice_request_tlv_stream,
919
+ experimental_invoice_request_tlv_stream, experimental_invoice_tlv_stream ,
915
920
)
916
921
}
917
922
@@ -1179,9 +1184,12 @@ impl InvoiceContents {
1179
1184
InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. as_tlv_stream ( ) ,
1180
1185
InvoiceContents :: ForRefund { refund, .. } => refund. as_tlv_stream ( ) ,
1181
1186
} ;
1182
- let invoice = self . fields ( ) . as_tlv_stream ( ) ;
1187
+ let ( invoice, experimental_invoice ) = self . fields ( ) . as_tlv_stream ( ) ;
1183
1188
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
+ )
1185
1193
}
1186
1194
}
1187
1195
@@ -1229,24 +1237,27 @@ pub(super) fn filter_fallbacks(
1229
1237
}
1230
1238
1231
1239
impl InvoiceFields {
1232
- fn as_tlv_stream ( & self ) -> InvoiceTlvStreamRef {
1240
+ fn as_tlv_stream ( & self ) -> ( InvoiceTlvStreamRef , ExperimentalInvoiceTlvStreamRef ) {
1233
1241
let features = {
1234
1242
if self . features == Bolt12InvoiceFeatures :: empty ( ) { None }
1235
1243
else { Some ( & self . features ) }
1236
1244
} ;
1237
1245
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
+ )
1250
1261
}
1251
1262
}
1252
1263
@@ -1321,6 +1332,13 @@ tlv_stream!(InvoiceTlvStream, InvoiceTlvStreamRef<'a>, INVOICE_TYPES, {
1321
1332
( 236 , message_paths: ( Vec <BlindedMessagePath >, WithoutLength ) ) ,
1322
1333
} ) ;
1323
1334
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
+
1324
1342
pub ( super ) type BlindedPathIter < ' a > = core:: iter:: Map <
1325
1343
core:: slice:: Iter < ' a , BlindedPaymentPath > ,
1326
1344
for <' r > fn ( & ' r BlindedPaymentPath ) -> & ' r BlindedPath ,
@@ -1342,7 +1360,7 @@ impl_writeable!(FallbackAddress, { version, program });
1342
1360
1343
1361
type FullInvoiceTlvStream =(
1344
1362
PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream , SignatureTlvStream ,
1345
- ExperimentalOfferTlvStream , ExperimentalInvoiceRequestTlvStream ,
1363
+ ExperimentalOfferTlvStream , ExperimentalInvoiceRequestTlvStream , ExperimentalInvoiceTlvStream ,
1346
1364
) ;
1347
1365
1348
1366
type FullInvoiceTlvStreamRef < ' a > = (
@@ -1353,6 +1371,7 @@ type FullInvoiceTlvStreamRef<'a> = (
1353
1371
SignatureTlvStreamRef < ' a > ,
1354
1372
ExperimentalOfferTlvStreamRef ,
1355
1373
ExperimentalInvoiceRequestTlvStreamRef ,
1374
+ ExperimentalInvoiceTlvStreamRef ,
1356
1375
) ;
1357
1376
1358
1377
impl CursorReadable for FullInvoiceTlvStream {
@@ -1364,19 +1383,20 @@ impl CursorReadable for FullInvoiceTlvStream {
1364
1383
let signature = CursorReadable :: read ( r) ?;
1365
1384
let experimental_offer = CursorReadable :: read ( r) ?;
1366
1385
let experimental_invoice_request = CursorReadable :: read ( r) ?;
1386
+ let experimental_invoice = CursorReadable :: read ( r) ?;
1367
1387
1368
1388
Ok (
1369
1389
(
1370
1390
payer, offer, invoice_request, invoice, signature, experimental_offer,
1371
- experimental_invoice_request,
1391
+ experimental_invoice_request, experimental_invoice ,
1372
1392
)
1373
1393
)
1374
1394
}
1375
1395
}
1376
1396
1377
1397
type PartialInvoiceTlvStream = (
1378
1398
PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream ,
1379
- ExperimentalOfferTlvStream , ExperimentalInvoiceRequestTlvStream ,
1399
+ ExperimentalOfferTlvStream , ExperimentalInvoiceRequestTlvStream , ExperimentalInvoiceTlvStream ,
1380
1400
) ;
1381
1401
1382
1402
type PartialInvoiceTlvStreamRef < ' a > = (
@@ -1386,6 +1406,7 @@ type PartialInvoiceTlvStreamRef<'a> = (
1386
1406
InvoiceTlvStreamRef < ' a > ,
1387
1407
ExperimentalOfferTlvStreamRef ,
1388
1408
ExperimentalInvoiceRequestTlvStreamRef ,
1409
+ ExperimentalInvoiceTlvStreamRef ,
1389
1410
) ;
1390
1411
1391
1412
impl CursorReadable for PartialInvoiceTlvStream {
@@ -1396,11 +1417,12 @@ impl CursorReadable for PartialInvoiceTlvStream {
1396
1417
let invoice = CursorReadable :: read ( r) ?;
1397
1418
let experimental_offer = CursorReadable :: read ( r) ?;
1398
1419
let experimental_invoice_request = CursorReadable :: read ( r) ?;
1420
+ let experimental_invoice = CursorReadable :: read ( r) ?;
1399
1421
1400
1422
Ok (
1401
1423
(
1402
1424
payer, offer, invoice_request, invoice, experimental_offer,
1403
- experimental_invoice_request,
1425
+ experimental_invoice_request, experimental_invoice ,
1404
1426
)
1405
1427
)
1406
1428
}
@@ -1416,11 +1438,13 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
1416
1438
SignatureTlvStream { signature } ,
1417
1439
experimental_offer_tlv_stream,
1418
1440
experimental_invoice_request_tlv_stream,
1441
+ experimental_invoice_tlv_stream,
1419
1442
) = tlv_stream;
1420
1443
let contents = InvoiceContents :: try_from (
1421
1444
(
1422
1445
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1423
1446
experimental_offer_tlv_stream, experimental_invoice_request_tlv_stream,
1447
+ experimental_invoice_tlv_stream,
1424
1448
)
1425
1449
) ?;
1426
1450
@@ -1449,6 +1473,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
1449
1473
} ,
1450
1474
experimental_offer_tlv_stream,
1451
1475
experimental_invoice_request_tlv_stream,
1476
+ ExperimentalInvoiceTlvStream { } ,
1452
1477
) = tlv_stream;
1453
1478
1454
1479
if message_paths. is_some ( ) { return Err ( Bolt12SemanticError :: UnexpectedPaths ) }
@@ -1545,7 +1570,7 @@ pub(super) fn check_invoice_signing_pubkey(
1545
1570
1546
1571
#[ cfg( test) ]
1547
1572
mod 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 } ;
1549
1574
1550
1575
use bitcoin:: { CompressedPublicKey , WitnessProgram , WitnessVersion } ;
1551
1576
use bitcoin:: constants:: ChainHash ;
@@ -1741,6 +1766,7 @@ mod tests {
1741
1766
ExperimentalInvoiceRequestTlvStreamRef {
1742
1767
experimental_bar: None ,
1743
1768
} ,
1769
+ ExperimentalInvoiceTlvStreamRef { } ,
1744
1770
) ,
1745
1771
) ;
1746
1772
@@ -1840,6 +1866,7 @@ mod tests {
1840
1866
ExperimentalInvoiceRequestTlvStreamRef {
1841
1867
experimental_bar: None ,
1842
1868
} ,
1869
+ ExperimentalInvoiceTlvStreamRef { } ,
1843
1870
) ,
1844
1871
) ;
1845
1872
@@ -2036,7 +2063,7 @@ mod tests {
2036
2063
. relative_expiry ( one_hour. as_secs ( ) as u32 )
2037
2064
. build ( ) . unwrap ( )
2038
2065
. sign ( recipient_sign) . unwrap ( ) ;
2039
- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2066
+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
2040
2067
#[ cfg( feature = "std" ) ]
2041
2068
assert ! ( !invoice. is_expired( ) ) ;
2042
2069
assert_eq ! ( invoice. relative_expiry( ) , one_hour) ;
@@ -2052,7 +2079,7 @@ mod tests {
2052
2079
. relative_expiry ( one_hour. as_secs ( ) as u32 - 1 )
2053
2080
. build ( ) . unwrap ( )
2054
2081
. sign ( recipient_sign) . unwrap ( ) ;
2055
- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2082
+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
2056
2083
#[ cfg( feature = "std" ) ]
2057
2084
assert ! ( invoice. is_expired( ) ) ;
2058
2085
assert_eq ! ( invoice. relative_expiry( ) , one_hour - Duration :: from_secs( 1 ) ) ;
@@ -2071,7 +2098,7 @@ mod tests {
2071
2098
. respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
2072
2099
. build ( ) . unwrap ( )
2073
2100
. sign ( recipient_sign) . unwrap ( ) ;
2074
- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2101
+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
2075
2102
assert_eq ! ( invoice. amount_msats( ) , 1001 ) ;
2076
2103
assert_eq ! ( tlv_stream. amount, Some ( 1001 ) ) ;
2077
2104
}
@@ -2089,7 +2116,7 @@ mod tests {
2089
2116
. respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
2090
2117
. build ( ) . unwrap ( )
2091
2118
. sign ( recipient_sign) . unwrap ( ) ;
2092
- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2119
+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
2093
2120
assert_eq ! ( invoice. amount_msats( ) , 2000 ) ;
2094
2121
assert_eq ! ( tlv_stream. amount, Some ( 2000 ) ) ;
2095
2122
@@ -2127,7 +2154,7 @@ mod tests {
2127
2154
. fallback_v1_p2tr_tweaked ( & tweaked_pubkey)
2128
2155
. build ( ) . unwrap ( )
2129
2156
. sign ( recipient_sign) . unwrap ( ) ;
2130
- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2157
+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
2131
2158
assert_eq ! (
2132
2159
invoice. fallbacks( ) ,
2133
2160
vec![
@@ -2170,7 +2197,7 @@ mod tests {
2170
2197
. allow_mpp ( )
2171
2198
. build ( ) . unwrap ( )
2172
2199
. sign ( recipient_sign) . unwrap ( ) ;
2173
- let ( _, _, _, tlv_stream, _, _, _) = invoice. as_tlv_stream ( ) ;
2200
+ let ( _, _, _, tlv_stream, _, _, _, _ ) = invoice. as_tlv_stream ( ) ;
2174
2201
assert_eq ! ( invoice. invoice_features( ) , & features) ;
2175
2202
assert_eq ! ( tlv_stream. features, Some ( & features) ) ;
2176
2203
}
0 commit comments