@@ -118,9 +118,9 @@ use crate::ln::inbound_payment::{ExpandedKey, IV_LEN};
118
118
use crate :: ln:: msgs:: DecodeError ;
119
119
use crate :: offers:: invoice_macros:: { invoice_accessors_common, invoice_builder_methods_common} ;
120
120
use crate :: offers:: invoice_request:: { INVOICE_REQUEST_PAYER_ID_TYPE , INVOICE_REQUEST_TYPES , IV_BYTES as INVOICE_REQUEST_IV_BYTES , InvoiceRequest , InvoiceRequestContents , InvoiceRequestTlvStream , InvoiceRequestTlvStreamRef } ;
121
- use crate :: offers:: merkle:: { SignError , SignFn , SignatureTlvStream , SignatureTlvStreamRef , TaggedHash , TlvStream , WithoutSignatures , self } ;
121
+ use crate :: offers:: merkle:: { SignError , SignFn , SignatureTlvStream , SignatureTlvStreamRef , TaggedHash , TlvStream , self } ;
122
122
use crate :: offers:: nonce:: Nonce ;
123
- use crate :: offers:: offer:: { Amount , OFFER_TYPES , OfferTlvStream , OfferTlvStreamRef , Quantity } ;
123
+ use crate :: offers:: offer:: { Amount , EXPERIMENTAL_OFFER_TYPES , ExperimentalOfferTlvStream , ExperimentalOfferTlvStreamRef , OFFER_TYPES , OfferTlvStream , OfferTlvStreamRef , Quantity } ;
124
124
use crate :: offers:: parse:: { Bolt12ParseError , Bolt12SemanticError , ParsedMessage } ;
125
125
use crate :: offers:: payer:: { PAYER_METADATA_TYPE , PayerTlvStream , PayerTlvStreamRef } ;
126
126
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 } ;
@@ -483,17 +483,26 @@ where
483
483
484
484
impl UnsignedBolt12Invoice {
485
485
fn new ( invreq_bytes : & [ u8 ] , contents : InvoiceContents ) -> Self {
486
+ const NON_EXPERIMENTAL_TYPES : core:: ops:: Range < u64 > = 0 ..INVOICE_REQUEST_TYPES . end ;
487
+ const EXPERIMENTAL_TYPES : core:: ops:: Range < u64 > = EXPERIMENTAL_OFFER_TYPES ;
488
+
489
+ let mut bytes = Vec :: new ( ) ;
490
+
486
491
// Use the invoice_request bytes instead of the invoice_request TLV stream as the latter may
487
492
// have contained unknown TLV records, which are not stored in `InvoiceRequestContents` or
488
493
// `RefundContents`.
489
- let ( _ , _ , _ , invoice_tlv_stream ) = contents . as_tlv_stream ( ) ;
490
- let invoice_request_bytes = WithoutSignatures ( invreq_bytes ) ;
491
- let unsigned_tlv_stream = ( invoice_request_bytes , invoice_tlv_stream ) ;
494
+ for record in TlvStream :: new ( invreq_bytes ) . range ( NON_EXPERIMENTAL_TYPES ) {
495
+ record . write ( & mut bytes ) . unwrap ( ) ;
496
+ }
492
497
493
- let mut bytes = Vec :: new ( ) ;
494
- unsigned_tlv_stream . write ( & mut bytes) . unwrap ( ) ;
498
+ let ( _ , _ , _ , invoice_tlv_stream , _ ) = contents . as_tlv_stream ( ) ;
499
+ invoice_tlv_stream . write ( & mut bytes) . unwrap ( ) ;
495
500
496
- let experimental_bytes = Vec :: new ( ) ;
501
+ let mut experimental_bytes = Vec :: new ( ) ;
502
+
503
+ for record in TlvStream :: new ( invreq_bytes) . range ( EXPERIMENTAL_TYPES ) {
504
+ record. write ( & mut experimental_bytes) . unwrap ( ) ;
505
+ }
497
506
498
507
let tlv_stream = TlvStream :: new ( & bytes) . chain ( TlvStream :: new ( & experimental_bytes) ) ;
499
508
let tagged_hash = TaggedHash :: from_tlv_stream ( SIGNATURE_TAG , tlv_stream) ;
@@ -826,7 +835,7 @@ impl Bolt12Invoice {
826
835
( & refund. payer . 0 , REFUND_IV_BYTES_WITH_METADATA )
827
836
} ,
828
837
} ;
829
- self . contents . verify ( TlvStream :: new ( & self . bytes ) , metadata, key, iv_bytes, secp_ctx)
838
+ self . contents . verify ( & self . bytes , metadata, key, iv_bytes, secp_ctx)
830
839
}
831
840
832
841
/// Verifies that the invoice was for a request or refund created using the given key by
@@ -840,21 +849,26 @@ impl Bolt12Invoice {
840
849
InvoiceContents :: ForOffer { .. } => INVOICE_REQUEST_IV_BYTES ,
841
850
InvoiceContents :: ForRefund { .. } => REFUND_IV_BYTES_WITHOUT_METADATA ,
842
851
} ;
843
- self . contents . verify ( TlvStream :: new ( & self . bytes ) , & metadata, key, iv_bytes, secp_ctx)
852
+ self . contents
853
+ . verify ( & self . bytes , & metadata, key, iv_bytes, secp_ctx)
844
854
. and_then ( |extracted_payment_id| ( payment_id == extracted_payment_id)
845
855
. then ( || payment_id)
846
856
. ok_or ( ( ) )
847
857
)
848
858
}
849
859
850
860
pub ( crate ) fn as_tlv_stream ( & self ) -> FullInvoiceTlvStreamRef {
851
- let ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream) =
852
- self . contents . as_tlv_stream ( ) ;
861
+ let (
862
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
863
+ experimental_offer_tlv_stream,
864
+ ) = self . contents . as_tlv_stream ( ) ;
853
865
let signature_tlv_stream = SignatureTlvStreamRef {
854
866
signature : Some ( & self . signature ) ,
855
867
} ;
856
- ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
857
- signature_tlv_stream)
868
+ (
869
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
870
+ signature_tlv_stream, experimental_offer_tlv_stream,
871
+ )
858
872
}
859
873
860
874
pub ( crate ) fn is_for_refund_without_paths ( & self ) -> bool {
@@ -1084,18 +1098,21 @@ impl InvoiceContents {
1084
1098
}
1085
1099
1086
1100
fn verify < T : secp256k1:: Signing > (
1087
- & self , tlv_stream : TlvStream < ' _ > , metadata : & Metadata , key : & ExpandedKey ,
1088
- iv_bytes : & [ u8 ; IV_LEN ] , secp_ctx : & Secp256k1 < T >
1101
+ & self , bytes : & [ u8 ] , metadata : & Metadata , key : & ExpandedKey , iv_bytes : & [ u8 ; IV_LEN ] ,
1102
+ secp_ctx : & Secp256k1 < T > ,
1089
1103
) -> Result < PaymentId , ( ) > {
1090
- let offer_records = tlv_stream. clone ( ) . range ( OFFER_TYPES ) ;
1091
- let invreq_records = tlv_stream. range ( INVOICE_REQUEST_TYPES ) . filter ( |record| {
1104
+ const EXPERIMENTAL_TYPES : core:: ops:: Range < u64 > = EXPERIMENTAL_OFFER_TYPES ;
1105
+
1106
+ let offer_records = TlvStream :: new ( bytes) . range ( OFFER_TYPES ) ;
1107
+ let invreq_records = TlvStream :: new ( bytes) . range ( INVOICE_REQUEST_TYPES ) . filter ( |record| {
1092
1108
match record. r#type {
1093
1109
PAYER_METADATA_TYPE => false , // Should be outside range
1094
1110
INVOICE_REQUEST_PAYER_ID_TYPE => !metadata. derives_payer_keys ( ) ,
1095
1111
_ => true ,
1096
1112
}
1097
1113
} ) ;
1098
- let tlv_stream = offer_records. chain ( invreq_records) ;
1114
+ let experimental_records = TlvStream :: new ( bytes) . range ( EXPERIMENTAL_TYPES ) ;
1115
+ let tlv_stream = offer_records. chain ( invreq_records) . chain ( experimental_records) ;
1099
1116
1100
1117
let signing_pubkey = self . payer_signing_pubkey ( ) ;
1101
1118
signer:: verify_payer_metadata (
@@ -1104,13 +1121,13 @@ impl InvoiceContents {
1104
1121
}
1105
1122
1106
1123
fn as_tlv_stream ( & self ) -> PartialInvoiceTlvStreamRef {
1107
- let ( payer, offer, invoice_request) = match self {
1124
+ let ( payer, offer, invoice_request, experimental_offer ) = match self {
1108
1125
InvoiceContents :: ForOffer { invoice_request, .. } => invoice_request. as_tlv_stream ( ) ,
1109
1126
InvoiceContents :: ForRefund { refund, .. } => refund. as_tlv_stream ( ) ,
1110
1127
} ;
1111
1128
let invoice = self . fields ( ) . as_tlv_stream ( ) ;
1112
1129
1113
- ( payer, offer, invoice_request, invoice)
1130
+ ( payer, offer, invoice_request, invoice, experimental_offer )
1114
1131
}
1115
1132
}
1116
1133
@@ -1213,9 +1230,13 @@ impl TryFrom<Vec<u8>> for UnsignedBolt12Invoice {
1213
1230
let ParsedMessage { mut bytes, tlv_stream } = invoice;
1214
1231
let (
1215
1232
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1233
+ experimental_offer_tlv_stream,
1216
1234
) = tlv_stream;
1217
1235
let contents = InvoiceContents :: try_from (
1218
- ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream)
1236
+ (
1237
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1238
+ experimental_offer_tlv_stream,
1239
+ )
1219
1240
) ?;
1220
1241
1221
1242
let tagged_hash = TaggedHash :: from_valid_tlv_stream_bytes ( SIGNATURE_TAG , & bytes) ;
@@ -1314,15 +1335,18 @@ pub(super) struct FallbackAddress {
1314
1335
1315
1336
impl_writeable ! ( FallbackAddress , { version, program } ) ;
1316
1337
1317
- type FullInvoiceTlvStream =
1318
- ( PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream , SignatureTlvStream ) ;
1338
+ type FullInvoiceTlvStream =(
1339
+ PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream , SignatureTlvStream ,
1340
+ ExperimentalOfferTlvStream ,
1341
+ ) ;
1319
1342
1320
1343
type FullInvoiceTlvStreamRef < ' a > = (
1321
1344
PayerTlvStreamRef < ' a > ,
1322
1345
OfferTlvStreamRef < ' a > ,
1323
1346
InvoiceRequestTlvStreamRef < ' a > ,
1324
1347
InvoiceTlvStreamRef < ' a > ,
1325
1348
SignatureTlvStreamRef < ' a > ,
1349
+ ExperimentalOfferTlvStreamRef ,
1326
1350
) ;
1327
1351
1328
1352
impl SeekReadable for FullInvoiceTlvStream {
@@ -1332,19 +1356,23 @@ impl SeekReadable for FullInvoiceTlvStream {
1332
1356
let invoice_request = SeekReadable :: read ( r) ?;
1333
1357
let invoice = SeekReadable :: read ( r) ?;
1334
1358
let signature = SeekReadable :: read ( r) ?;
1359
+ let experimental_offer = SeekReadable :: read ( r) ?;
1335
1360
1336
- Ok ( ( payer, offer, invoice_request, invoice, signature) )
1361
+ Ok ( ( payer, offer, invoice_request, invoice, signature, experimental_offer ) )
1337
1362
}
1338
1363
}
1339
1364
1340
- type PartialInvoiceTlvStream =
1341
- ( PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream ) ;
1365
+ type PartialInvoiceTlvStream = (
1366
+ PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , InvoiceTlvStream ,
1367
+ ExperimentalOfferTlvStream ,
1368
+ ) ;
1342
1369
1343
1370
type PartialInvoiceTlvStreamRef < ' a > = (
1344
1371
PayerTlvStreamRef < ' a > ,
1345
1372
OfferTlvStreamRef < ' a > ,
1346
1373
InvoiceRequestTlvStreamRef < ' a > ,
1347
1374
InvoiceTlvStreamRef < ' a > ,
1375
+ ExperimentalOfferTlvStreamRef ,
1348
1376
) ;
1349
1377
1350
1378
impl SeekReadable for PartialInvoiceTlvStream {
@@ -1353,8 +1381,9 @@ impl SeekReadable for PartialInvoiceTlvStream {
1353
1381
let offer = SeekReadable :: read ( r) ?;
1354
1382
let invoice_request = SeekReadable :: read ( r) ?;
1355
1383
let invoice = SeekReadable :: read ( r) ?;
1384
+ let experimental_offer = SeekReadable :: read ( r) ?;
1356
1385
1357
- Ok ( ( payer, offer, invoice_request, invoice) )
1386
+ Ok ( ( payer, offer, invoice_request, invoice, experimental_offer ) )
1358
1387
}
1359
1388
}
1360
1389
@@ -1366,9 +1395,13 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Bolt12Invoice {
1366
1395
let (
1367
1396
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1368
1397
SignatureTlvStream { signature } ,
1398
+ experimental_offer_tlv_stream,
1369
1399
) = tlv_stream;
1370
1400
let contents = InvoiceContents :: try_from (
1371
- ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream)
1401
+ (
1402
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
1403
+ experimental_offer_tlv_stream,
1404
+ )
1372
1405
) ?;
1373
1406
1374
1407
let signature = signature. ok_or (
@@ -1394,6 +1427,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
1394
1427
paths, blindedpay, created_at, relative_expiry, payment_hash, amount, fallbacks,
1395
1428
features, node_id, message_paths,
1396
1429
} ,
1430
+ experimental_offer_tlv_stream,
1397
1431
) = tlv_stream;
1398
1432
1399
1433
if message_paths. is_some ( ) { return Err ( Bolt12SemanticError :: UnexpectedPaths ) }
@@ -1426,12 +1460,18 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
1426
1460
1427
1461
if offer_tlv_stream. issuer_id . is_none ( ) && offer_tlv_stream. paths . is_none ( ) {
1428
1462
let refund = RefundContents :: try_from (
1429
- ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
1463
+ (
1464
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1465
+ experimental_offer_tlv_stream,
1466
+ )
1430
1467
) ?;
1431
1468
Ok ( InvoiceContents :: ForRefund { refund, fields } )
1432
1469
} else {
1433
1470
let invoice_request = InvoiceRequestContents :: try_from (
1434
- ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
1471
+ (
1472
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
1473
+ experimental_offer_tlv_stream,
1474
+ )
1435
1475
) ?;
1436
1476
Ok ( InvoiceContents :: ForOffer { invoice_request, fields } )
1437
1477
}
@@ -1500,7 +1540,7 @@ mod tests {
1500
1540
use crate :: offers:: invoice_request:: InvoiceRequestTlvStreamRef ;
1501
1541
use crate :: offers:: merkle:: { SignError , SignatureTlvStreamRef , TaggedHash , self } ;
1502
1542
use crate :: offers:: nonce:: Nonce ;
1503
- use crate :: offers:: offer:: { Amount , OfferTlvStreamRef , Quantity } ;
1543
+ use crate :: offers:: offer:: { Amount , ExperimentalOfferTlvStreamRef , OfferTlvStreamRef , Quantity } ;
1504
1544
use crate :: prelude:: * ;
1505
1545
#[ cfg( not( c_bindings) ) ]
1506
1546
use {
@@ -1668,6 +1708,7 @@ mod tests {
1668
1708
message_paths: None ,
1669
1709
} ,
1670
1710
SignatureTlvStreamRef { signature: Some ( & invoice. signature( ) ) } ,
1711
+ ExperimentalOfferTlvStreamRef { } ,
1671
1712
) ,
1672
1713
) ;
1673
1714
@@ -1761,6 +1802,7 @@ mod tests {
1761
1802
message_paths: None ,
1762
1803
} ,
1763
1804
SignatureTlvStreamRef { signature: Some ( & invoice. signature( ) ) } ,
1805
+ ExperimentalOfferTlvStreamRef { } ,
1764
1806
) ,
1765
1807
) ;
1766
1808
@@ -1956,7 +1998,7 @@ mod tests {
1956
1998
. relative_expiry ( one_hour. as_secs ( ) as u32 )
1957
1999
. build ( ) . unwrap ( )
1958
2000
. sign ( recipient_sign) . unwrap ( ) ;
1959
- let ( _, _, _, tlv_stream, _) = invoice. as_tlv_stream ( ) ;
2001
+ let ( _, _, _, tlv_stream, _, _ ) = invoice. as_tlv_stream ( ) ;
1960
2002
#[ cfg( feature = "std" ) ]
1961
2003
assert ! ( !invoice. is_expired( ) ) ;
1962
2004
assert_eq ! ( invoice. relative_expiry( ) , one_hour) ;
@@ -1972,7 +2014,7 @@ mod tests {
1972
2014
. relative_expiry ( one_hour. as_secs ( ) as u32 - 1 )
1973
2015
. build ( ) . unwrap ( )
1974
2016
. sign ( recipient_sign) . unwrap ( ) ;
1975
- let ( _, _, _, tlv_stream, _) = invoice. as_tlv_stream ( ) ;
2017
+ let ( _, _, _, tlv_stream, _, _ ) = invoice. as_tlv_stream ( ) ;
1976
2018
#[ cfg( feature = "std" ) ]
1977
2019
assert ! ( invoice. is_expired( ) ) ;
1978
2020
assert_eq ! ( invoice. relative_expiry( ) , one_hour - Duration :: from_secs( 1 ) ) ;
@@ -1991,7 +2033,7 @@ mod tests {
1991
2033
. respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
1992
2034
. build ( ) . unwrap ( )
1993
2035
. sign ( recipient_sign) . unwrap ( ) ;
1994
- let ( _, _, _, tlv_stream, _) = invoice. as_tlv_stream ( ) ;
2036
+ let ( _, _, _, tlv_stream, _, _ ) = invoice. as_tlv_stream ( ) ;
1995
2037
assert_eq ! ( invoice. amount_msats( ) , 1001 ) ;
1996
2038
assert_eq ! ( tlv_stream. amount, Some ( 1001 ) ) ;
1997
2039
}
@@ -2009,7 +2051,7 @@ mod tests {
2009
2051
. respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
2010
2052
. build ( ) . unwrap ( )
2011
2053
. sign ( recipient_sign) . unwrap ( ) ;
2012
- let ( _, _, _, tlv_stream, _) = invoice. as_tlv_stream ( ) ;
2054
+ let ( _, _, _, tlv_stream, _, _ ) = invoice. as_tlv_stream ( ) ;
2013
2055
assert_eq ! ( invoice. amount_msats( ) , 2000 ) ;
2014
2056
assert_eq ! ( tlv_stream. amount, Some ( 2000 ) ) ;
2015
2057
@@ -2047,7 +2089,7 @@ mod tests {
2047
2089
. fallback_v1_p2tr_tweaked ( & tweaked_pubkey)
2048
2090
. build ( ) . unwrap ( )
2049
2091
. sign ( recipient_sign) . unwrap ( ) ;
2050
- let ( _, _, _, tlv_stream, _) = invoice. as_tlv_stream ( ) ;
2092
+ let ( _, _, _, tlv_stream, _, _ ) = invoice. as_tlv_stream ( ) ;
2051
2093
assert_eq ! (
2052
2094
invoice. fallbacks( ) ,
2053
2095
vec![
@@ -2090,7 +2132,7 @@ mod tests {
2090
2132
. allow_mpp ( )
2091
2133
. build ( ) . unwrap ( )
2092
2134
. sign ( recipient_sign) . unwrap ( ) ;
2093
- let ( _, _, _, tlv_stream, _) = invoice. as_tlv_stream ( ) ;
2135
+ let ( _, _, _, tlv_stream, _, _ ) = invoice. as_tlv_stream ( ) ;
2094
2136
assert_eq ! ( invoice. invoice_features( ) , & features) ;
2095
2137
assert_eq ! ( tlv_stream. features, Some ( & features) ) ;
2096
2138
}
0 commit comments