@@ -122,9 +122,9 @@ use crate::offers::invoice_macros::{invoice_accessors_common, invoice_builder_me
122
122
#[ cfg( test) ]
123
123
use crate :: offers:: invoice_macros:: invoice_builder_methods_test;
124
124
use crate :: offers:: invoice_request:: { INVOICE_REQUEST_PAYER_ID_TYPE , INVOICE_REQUEST_TYPES , IV_BYTES as INVOICE_REQUEST_IV_BYTES , InvoiceRequest , InvoiceRequestContents , InvoiceRequestTlvStream , InvoiceRequestTlvStreamRef } ;
125
- use crate :: offers:: merkle:: { SignError , SignFn , SignatureTlvStream , SignatureTlvStreamRef , TaggedHash , TlvStream , WithoutSignatures , self } ;
125
+ use crate :: offers:: merkle:: { SignError , SignFn , SignatureTlvStream , SignatureTlvStreamRef , TaggedHash , TlvStream , self } ;
126
126
use crate :: offers:: nonce:: Nonce ;
127
- use crate :: offers:: offer:: { Amount , OFFER_TYPES , OfferTlvStream , OfferTlvStreamRef , Quantity } ;
127
+ use crate :: offers:: offer:: { Amount , EXPERIMENTAL_OFFER_TYPES , ExperimentalOfferTlvStream , ExperimentalOfferTlvStreamRef , OFFER_TYPES , OfferTlvStream , OfferTlvStreamRef , Quantity } ;
128
128
use crate :: offers:: parse:: { Bolt12ParseError , Bolt12SemanticError , ParsedMessage } ;
129
129
use crate :: offers:: payer:: { PAYER_METADATA_TYPE , PayerTlvStream , PayerTlvStreamRef } ;
130
130
use crate :: offers:: refund:: { IV_BYTES_WITH_METADATA as REFUND_IV_BYTES_WITH_METADATA , IV_BYTES_WITHOUT_METADATA as REFUND_IV_BYTES_WITHOUT_METADATA , Refund , RefundContents } ;
@@ -492,17 +492,26 @@ where
492
492
493
493
impl UnsignedBolt12Invoice {
494
494
fn new ( invreq_bytes : & [ u8 ] , contents : InvoiceContents ) -> Self {
495
+ const NON_EXPERIMENTAL_TYPES : core:: ops:: Range < u64 > = 0 ..INVOICE_REQUEST_TYPES . end ;
496
+ const EXPERIMENTAL_TYPES : core:: ops:: Range < u64 > = EXPERIMENTAL_OFFER_TYPES ;
497
+
498
+ let mut bytes = Vec :: new ( ) ;
499
+
495
500
// Use the invoice_request bytes instead of the invoice_request TLV stream as the latter may
496
501
// have contained unknown TLV records, which are not stored in `InvoiceRequestContents` or
497
502
// `RefundContents`.
498
- let ( _ , _ , _ , invoice_tlv_stream ) = contents . as_tlv_stream ( ) ;
499
- let invoice_request_bytes = WithoutSignatures ( invreq_bytes ) ;
500
- let unsigned_tlv_stream = ( invoice_request_bytes , invoice_tlv_stream ) ;
503
+ for record in TlvStream :: new ( invreq_bytes ) . range ( NON_EXPERIMENTAL_TYPES ) {
504
+ record . write ( & mut bytes ) . unwrap ( ) ;
505
+ }
501
506
502
- let mut bytes = Vec :: new ( ) ;
503
- unsigned_tlv_stream . write ( & mut bytes) . unwrap ( ) ;
507
+ let ( _ , _ , _ , invoice_tlv_stream , _ ) = contents . as_tlv_stream ( ) ;
508
+ invoice_tlv_stream . write ( & mut bytes) . unwrap ( ) ;
504
509
505
- let experimental_bytes = Vec :: new ( ) ;
510
+ let mut experimental_bytes = Vec :: new ( ) ;
511
+
512
+ for record in TlvStream :: new ( invreq_bytes) . range ( EXPERIMENTAL_TYPES ) {
513
+ record. write ( & mut experimental_bytes) . unwrap ( ) ;
514
+ }
506
515
507
516
let tlv_stream = TlvStream :: new ( & bytes) . chain ( TlvStream :: new ( & experimental_bytes) ) ;
508
517
let tagged_hash = TaggedHash :: from_tlv_stream ( SIGNATURE_TAG , tlv_stream) ;
@@ -858,13 +867,17 @@ impl Bolt12Invoice {
858
867
}
859
868
860
869
pub ( crate ) fn as_tlv_stream ( & self ) -> FullInvoiceTlvStreamRef {
861
- let ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream) =
862
- self . contents . as_tlv_stream ( ) ;
870
+ let (
871
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
872
+ experimental_offer_tlv_stream,
873
+ ) = self . contents . as_tlv_stream ( ) ;
863
874
let signature_tlv_stream = SignatureTlvStreamRef {
864
875
signature : Some ( & self . signature ) ,
865
876
} ;
866
- ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
867
- signature_tlv_stream)
877
+ (
878
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
879
+ signature_tlv_stream, experimental_offer_tlv_stream,
880
+ )
868
881
}
869
882
870
883
pub ( crate ) fn is_for_refund_without_paths ( & self ) -> bool {
@@ -1095,8 +1108,10 @@ impl InvoiceContents {
1095
1108
1096
1109
fn verify < T : secp256k1:: Signing > (
1097
1110
& self , bytes : & [ u8 ] , metadata : & Metadata , key : & ExpandedKey , iv_bytes : & [ u8 ; IV_LEN ] ,
1098
- secp_ctx : & Secp256k1 < T >
1111
+ secp_ctx : & Secp256k1 < T > ,
1099
1112
) -> Result < PaymentId , ( ) > {
1113
+ const EXPERIMENTAL_TYPES : core:: ops:: Range < u64 > = EXPERIMENTAL_OFFER_TYPES ;
1114
+
1100
1115
let offer_records = TlvStream :: new ( bytes) . range ( OFFER_TYPES ) ;
1101
1116
let invreq_records = TlvStream :: new ( bytes) . range ( INVOICE_REQUEST_TYPES ) . filter ( |record| {
1102
1117
match record. r#type {
@@ -1105,7 +1120,8 @@ impl InvoiceContents {
1105
1120
_ => true ,
1106
1121
}
1107
1122
} ) ;
1108
- let tlv_stream = offer_records. chain ( invreq_records) ;
1123
+ let experimental_records = TlvStream :: new ( bytes) . range ( EXPERIMENTAL_TYPES ) ;
1124
+ let tlv_stream = offer_records. chain ( invreq_records) . chain ( experimental_records) ;
1109
1125
1110
1126
let signing_pubkey = self . payer_signing_pubkey ( ) ;
1111
1127
signer:: verify_payer_metadata (
@@ -1114,13 +1130,13 @@ impl InvoiceContents {
1114
1130
}
1115
1131
1116
1132
fn as_tlv_stream ( & self ) -> PartialInvoiceTlvStreamRef {
1117
- let ( payer, offer, invoice_request) = match self {
1133
+ let ( payer, offer, invoice_request, experimental_offer ) = match self {
1118
1134
InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. as_tlv_stream ( ) ,
1119
1135
InvoiceContents :: ForRefund { refund, .. } => refund. as_tlv_stream ( ) ,
1120
1136
} ;
1121
1137
let invoice = self . fields ( ) . as_tlv_stream ( ) ;
1122
1138
1123
- ( payer, offer, invoice_request, invoice)
1139
+ ( payer, offer, invoice_request, invoice, experimental_offer )
1124
1140
}
1125
1141
}
1126
1142
@@ -1222,9 +1238,13 @@ impl TryFrom<Vec<u8>> for UnsignedBolt12Invoice {
1222
1238
let ParsedMessage { mut bytes, tlv_stream } = invoice;
1223
1239
let (
1224
1240
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1241
+ experimental_offer_tlv_stream,
1225
1242
) = tlv_stream;
1226
1243
let contents = InvoiceContents :: try_from (
1227
- ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream)
1244
+ (
1245
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1246
+ experimental_offer_tlv_stream,
1247
+ )
1228
1248
) ?;
1229
1249
1230
1250
let tagged_hash = TaggedHash :: from_valid_tlv_stream_bytes ( SIGNATURE_TAG , & bytes) ;
@@ -1285,15 +1305,18 @@ pub(super) struct FallbackAddress {
1285
1305
1286
1306
impl_writeable ! ( FallbackAddress , { version, program } ) ;
1287
1307
1288
- type FullInvoiceTlvStream =
1289
- ( PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream , SignatureTlvStream ) ;
1308
+ type FullInvoiceTlvStream =(
1309
+ PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream , SignatureTlvStream ,
1310
+ ExperimentalOfferTlvStream ,
1311
+ ) ;
1290
1312
1291
1313
type FullInvoiceTlvStreamRef < ' a > = (
1292
1314
PayerTlvStreamRef < ' a > ,
1293
1315
OfferTlvStreamRef < ' a > ,
1294
1316
InvoiceRequestTlvStreamRef < ' a > ,
1295
1317
InvoiceTlvStreamRef < ' a > ,
1296
1318
SignatureTlvStreamRef < ' a > ,
1319
+ ExperimentalOfferTlvStreamRef ,
1297
1320
) ;
1298
1321
1299
1322
impl CursorReadable for FullInvoiceTlvStream {
@@ -1303,19 +1326,23 @@ impl CursorReadable for FullInvoiceTlvStream {
1303
1326
let invoice_request = CursorReadable :: read ( r) ?;
1304
1327
let invoice = CursorReadable :: read ( r) ?;
1305
1328
let signature = CursorReadable :: read ( r) ?;
1329
+ let experimental_offer = CursorReadable :: read ( r) ?;
1306
1330
1307
- Ok ( ( payer, offer, invoice_request, invoice, signature) )
1331
+ Ok ( ( payer, offer, invoice_request, invoice, signature, experimental_offer ) )
1308
1332
}
1309
1333
}
1310
1334
1311
- type PartialInvoiceTlvStream =
1312
- ( PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream ) ;
1335
+ type PartialInvoiceTlvStream = (
1336
+ PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream ,
1337
+ ExperimentalOfferTlvStream ,
1338
+ ) ;
1313
1339
1314
1340
type PartialInvoiceTlvStreamRef < ' a > = (
1315
1341
PayerTlvStreamRef < ' a > ,
1316
1342
OfferTlvStreamRef < ' a > ,
1317
1343
InvoiceRequestTlvStreamRef < ' a > ,
1318
1344
InvoiceTlvStreamRef < ' a > ,
1345
+ ExperimentalOfferTlvStreamRef ,
1319
1346
) ;
1320
1347
1321
1348
impl CursorReadable for PartialInvoiceTlvStream {
@@ -1324,8 +1351,9 @@ impl CursorReadable for PartialInvoiceTlvStream {
1324
1351
let offer = CursorReadable :: read ( r) ?;
1325
1352
let invoice_request = CursorReadable :: read ( r) ?;
1326
1353
let invoice = CursorReadable :: read ( r) ?;
1354
+ let experimental_offer = CursorReadable :: read ( r) ?;
1327
1355
1328
- Ok ( ( payer, offer, invoice_request, invoice) )
1356
+ Ok ( ( payer, offer, invoice_request, invoice, experimental_offer ) )
1329
1357
}
1330
1358
}
1331
1359
@@ -1337,9 +1365,13 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
1337
1365
let (
1338
1366
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1339
1367
SignatureTlvStream { signature } ,
1368
+ experimental_offer_tlv_stream,
1340
1369
) = tlv_stream;
1341
1370
let contents = InvoiceContents :: try_from (
1342
- ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream)
1371
+ (
1372
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1373
+ experimental_offer_tlv_stream,
1374
+ )
1343
1375
) ?;
1344
1376
1345
1377
let signature = signature. ok_or (
@@ -1365,6 +1397,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
1365
1397
paths, blindedpay, created_at, relative_expiry, payment_hash, amount, fallbacks,
1366
1398
features, node_id, message_paths,
1367
1399
} ,
1400
+ experimental_offer_tlv_stream,
1368
1401
) = tlv_stream;
1369
1402
1370
1403
if message_paths. is_some ( ) { return Err ( Bolt12SemanticError :: UnexpectedPaths ) }
@@ -1397,12 +1430,18 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
1397
1430
1398
1431
if offer_tlv_stream. issuer_id . is_none ( ) && offer_tlv_stream. paths . is_none ( ) {
1399
1432
let refund = RefundContents :: try_from (
1400
- ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
1433
+ (
1434
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1435
+ experimental_offer_tlv_stream,
1436
+ )
1401
1437
) ?;
1402
1438
Ok ( InvoiceContents :: ForRefund { refund, fields } )
1403
1439
} else {
1404
1440
let invoice_request = InvoiceRequestContents :: try_from (
1405
- ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
1441
+ (
1442
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1443
+ experimental_offer_tlv_stream,
1444
+ )
1406
1445
) ?;
1407
1446
Ok ( InvoiceContents :: ForOffer { invoice_request, fields } )
1408
1447
}
@@ -1477,7 +1516,7 @@ mod tests {
1477
1516
use crate :: offers:: invoice_request:: InvoiceRequestTlvStreamRef ;
1478
1517
use crate :: offers:: merkle:: { SignError , SignatureTlvStreamRef , TaggedHash , self } ;
1479
1518
use crate :: offers:: nonce:: Nonce ;
1480
- use crate :: offers:: offer:: { Amount , OfferTlvStreamRef , Quantity } ;
1519
+ use crate :: offers:: offer:: { Amount , ExperimentalOfferTlvStreamRef , OfferTlvStreamRef , Quantity } ;
1481
1520
use crate :: prelude:: * ;
1482
1521
#[ cfg( not( c_bindings) ) ]
1483
1522
use {
@@ -1645,6 +1684,7 @@ mod tests {
1645
1684
message_paths: None ,
1646
1685
} ,
1647
1686
SignatureTlvStreamRef { signature: Some ( & invoice. signature( ) ) } ,
1687
+ ExperimentalOfferTlvStreamRef { } ,
1648
1688
) ,
1649
1689
) ;
1650
1690
@@ -1738,6 +1778,7 @@ mod tests {
1738
1778
message_paths: None ,
1739
1779
} ,
1740
1780
SignatureTlvStreamRef { signature: Some ( & invoice. signature( ) ) } ,
1781
+ ExperimentalOfferTlvStreamRef { } ,
1741
1782
) ,
1742
1783
) ;
1743
1784
@@ -1931,7 +1972,7 @@ mod tests {
1931
1972
. relative_expiry ( one_hour. as_secs ( ) as u32 )
1932
1973
. build ( ) . unwrap ( )
1933
1974
. sign ( recipient_sign) . unwrap ( ) ;
1934
- let ( _, _, _, tlv_stream, _) = invoice. as_tlv_stream ( ) ;
1975
+ let ( _, _, _, tlv_stream, _, _ ) = invoice. as_tlv_stream ( ) ;
1935
1976
#[ cfg( feature = "std" ) ]
1936
1977
assert ! ( !invoice. is_expired( ) ) ;
1937
1978
assert_eq ! ( invoice. relative_expiry( ) , one_hour) ;
@@ -1947,7 +1988,7 @@ mod tests {
1947
1988
. relative_expiry ( one_hour. as_secs ( ) as u32 - 1 )
1948
1989
. build ( ) . unwrap ( )
1949
1990
. sign ( recipient_sign) . unwrap ( ) ;
1950
- let ( _, _, _, tlv_stream, _) = invoice. as_tlv_stream ( ) ;
1991
+ let ( _, _, _, tlv_stream, _, _ ) = invoice. as_tlv_stream ( ) ;
1951
1992
#[ cfg( feature = "std" ) ]
1952
1993
assert ! ( invoice. is_expired( ) ) ;
1953
1994
assert_eq ! ( invoice. relative_expiry( ) , one_hour - Duration :: from_secs( 1 ) ) ;
@@ -1966,7 +2007,7 @@ mod tests {
1966
2007
. respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
1967
2008
. build ( ) . unwrap ( )
1968
2009
. sign ( recipient_sign) . unwrap ( ) ;
1969
- let ( _, _, _, tlv_stream, _) = invoice. as_tlv_stream ( ) ;
2010
+ let ( _, _, _, tlv_stream, _, _ ) = invoice. as_tlv_stream ( ) ;
1970
2011
assert_eq ! ( invoice. amount_msats( ) , 1001 ) ;
1971
2012
assert_eq ! ( tlv_stream. amount, Some ( 1001 ) ) ;
1972
2013
}
@@ -1984,7 +2025,7 @@ mod tests {
1984
2025
. respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
1985
2026
. build ( ) . unwrap ( )
1986
2027
. sign ( recipient_sign) . unwrap ( ) ;
1987
- let ( _, _, _, tlv_stream, _) = invoice. as_tlv_stream ( ) ;
2028
+ let ( _, _, _, tlv_stream, _, _ ) = invoice. as_tlv_stream ( ) ;
1988
2029
assert_eq ! ( invoice. amount_msats( ) , 2000 ) ;
1989
2030
assert_eq ! ( tlv_stream. amount, Some ( 2000 ) ) ;
1990
2031
@@ -2022,7 +2063,7 @@ mod tests {
2022
2063
. fallback_v1_p2tr_tweaked ( & tweaked_pubkey)
2023
2064
. build ( ) . unwrap ( )
2024
2065
. sign ( recipient_sign) . unwrap ( ) ;
2025
- let ( _, _, _, tlv_stream, _) = invoice. as_tlv_stream ( ) ;
2066
+ let ( _, _, _, tlv_stream, _, _ ) = invoice. as_tlv_stream ( ) ;
2026
2067
assert_eq ! (
2027
2068
invoice. fallbacks( ) ,
2028
2069
vec![
@@ -2065,7 +2106,7 @@ mod tests {
2065
2106
. allow_mpp ( )
2066
2107
. build ( ) . unwrap ( )
2067
2108
. sign ( recipient_sign) . unwrap ( ) ;
2068
- let ( _, _, _, tlv_stream, _) = invoice. as_tlv_stream ( ) ;
2109
+ let ( _, _, _, tlv_stream, _, _ ) = invoice. as_tlv_stream ( ) ;
2069
2110
assert_eq ! ( invoice. invoice_features( ) , & features) ;
2070
2111
assert_eq ! ( tlv_stream. features, Some ( & features) ) ;
2071
2112
}
0 commit comments