@@ -363,6 +363,8 @@ macro_rules! invoice_builder_methods { (
363
363
InvoiceFields {
364
364
payment_paths, created_at, relative_expiry: None , payment_hash, amount_msats,
365
365
fallbacks: None , features: Bolt12InvoiceFeatures :: empty( ) , signing_pubkey,
366
+ #[ cfg( test) ]
367
+ experimental_baz: None ,
366
368
}
367
369
}
368
370
@@ -657,6 +659,8 @@ struct InvoiceFields {
657
659
fallbacks : Option < Vec < FallbackAddress > > ,
658
660
features : Bolt12InvoiceFeatures ,
659
661
signing_pubkey : PublicKey ,
662
+ #[ cfg( test) ]
663
+ experimental_baz : Option < u64 > ,
660
664
}
661
665
662
666
macro_rules! invoice_accessors { ( $self: ident, $contents: expr) => {
@@ -1247,7 +1251,10 @@ impl InvoiceFields {
1247
1251
node_id : Some ( & self . signing_pubkey ) ,
1248
1252
message_paths : None ,
1249
1253
} ,
1250
- ExperimentalInvoiceTlvStreamRef { } ,
1254
+ ExperimentalInvoiceTlvStreamRef {
1255
+ #[ cfg( test) ]
1256
+ experimental_baz : self . experimental_baz ,
1257
+ } ,
1251
1258
)
1252
1259
}
1253
1260
}
@@ -1324,12 +1331,20 @@ tlv_stream!(InvoiceTlvStream, InvoiceTlvStreamRef<'a>, INVOICE_TYPES, {
1324
1331
} ) ;
1325
1332
1326
1333
/// Valid type range for experimental invoice TLV records.
1327
- const EXPERIMENTAL_INVOICE_TYPES : core:: ops:: RangeFrom < u64 > = 3_000_000_000 ..;
1334
+ pub ( super ) const EXPERIMENTAL_INVOICE_TYPES : core:: ops:: RangeFrom < u64 > = 3_000_000_000 ..;
1328
1335
1336
+ #[ cfg( not( test) ) ]
1329
1337
tlv_stream ! (
1330
1338
ExperimentalInvoiceTlvStream , ExperimentalInvoiceTlvStreamRef , EXPERIMENTAL_INVOICE_TYPES , { }
1331
1339
) ;
1332
1340
1341
+ #[ cfg( test) ]
1342
+ tlv_stream ! (
1343
+ ExperimentalInvoiceTlvStream , ExperimentalInvoiceTlvStreamRef , EXPERIMENTAL_INVOICE_TYPES , {
1344
+ ( 3_999_999_999 , experimental_baz: ( u64 , HighZeroBytesDroppedBigSize ) ) ,
1345
+ }
1346
+ ) ;
1347
+
1333
1348
pub ( super ) type BlindedPathIter < ' a > = core:: iter:: Map <
1334
1349
core:: slice:: Iter < ' a , BlindedPaymentPath > ,
1335
1350
for <' r > fn ( & ' r BlindedPaymentPath ) -> & ' r BlindedPath ,
@@ -1464,7 +1479,10 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
1464
1479
} ,
1465
1480
experimental_offer_tlv_stream,
1466
1481
experimental_invoice_request_tlv_stream,
1467
- ExperimentalInvoiceTlvStream { } ,
1482
+ ExperimentalInvoiceTlvStream {
1483
+ #[ cfg( test) ]
1484
+ experimental_baz,
1485
+ } ,
1468
1486
) = tlv_stream;
1469
1487
1470
1488
if message_paths. is_some ( ) { return Err ( Bolt12SemanticError :: UnexpectedPaths ) }
@@ -1491,6 +1509,8 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
1491
1509
let fields = InvoiceFields {
1492
1510
payment_paths, created_at, relative_expiry, payment_hash, amount_msats, fallbacks,
1493
1511
features, signing_pubkey,
1512
+ #[ cfg( test) ]
1513
+ experimental_baz,
1494
1514
} ;
1495
1515
1496
1516
check_invoice_signing_pubkey ( & fields. signing_pubkey , & offer_tlv_stream) ?;
@@ -1561,7 +1581,7 @@ pub(super) fn check_invoice_signing_pubkey(
1561
1581
1562
1582
#[ cfg( test) ]
1563
1583
mod tests {
1564
- use super :: { Bolt12Invoice , DEFAULT_RELATIVE_EXPIRY , ExperimentalInvoiceTlvStreamRef , FallbackAddress , FullInvoiceTlvStreamRef , INVOICE_TYPES , InvoiceTlvStreamRef , SIGNATURE_TAG , UnsignedBolt12Invoice } ;
1584
+ use super :: { Bolt12Invoice , DEFAULT_RELATIVE_EXPIRY , EXPERIMENTAL_INVOICE_TYPES , ExperimentalInvoiceTlvStreamRef , FallbackAddress , FullInvoiceTlvStreamRef , INVOICE_TYPES , InvoiceTlvStreamRef , SIGNATURE_TAG , UnsignedBolt12Invoice } ;
1565
1585
1566
1586
use bitcoin:: { CompressedPublicKey , WitnessProgram , WitnessVersion } ;
1567
1587
use bitcoin:: constants:: ChainHash ;
@@ -1581,7 +1601,7 @@ mod tests {
1581
1601
use crate :: ln:: inbound_payment:: ExpandedKey ;
1582
1602
use crate :: ln:: msgs:: DecodeError ;
1583
1603
use crate :: offers:: invoice_request:: { ExperimentalInvoiceRequestTlvStreamRef , InvoiceRequestTlvStreamRef } ;
1584
- use crate :: offers:: merkle:: { SignError , SignatureTlvStreamRef , TaggedHash , self } ;
1604
+ use crate :: offers:: merkle:: { SignError , SignatureTlvStreamRef , TaggedHash , TlvStream , self } ;
1585
1605
use crate :: offers:: nonce:: Nonce ;
1586
1606
use crate :: offers:: offer:: { Amount , ExperimentalOfferTlvStreamRef , OfferTlvStreamRef , Quantity } ;
1587
1607
use crate :: prelude:: * ;
@@ -1757,7 +1777,9 @@ mod tests {
1757
1777
ExperimentalInvoiceRequestTlvStreamRef {
1758
1778
experimental_bar: None ,
1759
1779
} ,
1760
- ExperimentalInvoiceTlvStreamRef { } ,
1780
+ ExperimentalInvoiceTlvStreamRef {
1781
+ experimental_baz: None ,
1782
+ } ,
1761
1783
) ,
1762
1784
) ;
1763
1785
@@ -1857,7 +1879,9 @@ mod tests {
1857
1879
ExperimentalInvoiceRequestTlvStreamRef {
1858
1880
experimental_bar: None ,
1859
1881
} ,
1860
- ExperimentalInvoiceTlvStreamRef { } ,
1882
+ ExperimentalInvoiceTlvStreamRef {
1883
+ experimental_baz: None ,
1884
+ } ,
1861
1885
) ,
1862
1886
) ;
1863
1887
@@ -2705,6 +2729,123 @@ mod tests {
2705
2729
}
2706
2730
}
2707
2731
2732
+ #[ test]
2733
+ fn parses_invoice_with_experimental_tlv_records ( ) {
2734
+ let secp_ctx = Secp256k1 :: new ( ) ;
2735
+ let keys = Keypair :: from_secret_key ( & secp_ctx, & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ) ;
2736
+ let invoice = OfferBuilder :: new ( keys. public_key ( ) )
2737
+ . amount_msats ( 1000 )
2738
+ . build ( ) . unwrap ( )
2739
+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
2740
+ . build ( ) . unwrap ( )
2741
+ . sign ( payer_sign) . unwrap ( )
2742
+ . respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
2743
+ . experimental_baz ( 42 )
2744
+ . build ( ) . unwrap ( )
2745
+ . sign ( |message : & UnsignedBolt12Invoice |
2746
+ Ok ( secp_ctx. sign_schnorr_no_aux_rand ( message. as_ref ( ) . as_digest ( ) , & keys) )
2747
+ )
2748
+ . unwrap ( ) ;
2749
+
2750
+ let mut encoded_invoice = Vec :: new ( ) ;
2751
+ invoice. write ( & mut encoded_invoice) . unwrap ( ) ;
2752
+
2753
+ assert ! ( Bolt12Invoice :: try_from( encoded_invoice) . is_ok( ) ) ;
2754
+
2755
+ const UNKNOWN_ODD_TYPE : u64 = EXPERIMENTAL_INVOICE_TYPES . start + 1 ;
2756
+ assert ! ( UNKNOWN_ODD_TYPE % 2 == 1 ) ;
2757
+
2758
+ let mut unsigned_invoice = OfferBuilder :: new ( keys. public_key ( ) )
2759
+ . amount_msats ( 1000 )
2760
+ . build ( ) . unwrap ( )
2761
+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
2762
+ . build ( ) . unwrap ( )
2763
+ . sign ( payer_sign) . unwrap ( )
2764
+ . respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
2765
+ . build ( ) . unwrap ( ) ;
2766
+
2767
+ BigSize ( UNKNOWN_ODD_TYPE ) . write ( & mut unsigned_invoice. experimental_bytes ) . unwrap ( ) ;
2768
+ BigSize ( 32 ) . write ( & mut unsigned_invoice. experimental_bytes ) . unwrap ( ) ;
2769
+ [ 42u8 ; 32 ] . write ( & mut unsigned_invoice. experimental_bytes ) . unwrap ( ) ;
2770
+
2771
+ let tlv_stream = TlvStream :: new ( & unsigned_invoice. bytes )
2772
+ . chain ( TlvStream :: new ( & unsigned_invoice. experimental_bytes ) ) ;
2773
+ unsigned_invoice. tagged_hash = TaggedHash :: from_tlv_stream ( SIGNATURE_TAG , tlv_stream) ;
2774
+
2775
+ let invoice = unsigned_invoice
2776
+ . sign ( |message : & UnsignedBolt12Invoice |
2777
+ Ok ( secp_ctx. sign_schnorr_no_aux_rand ( message. as_ref ( ) . as_digest ( ) , & keys) )
2778
+ )
2779
+ . unwrap ( ) ;
2780
+
2781
+ let mut encoded_invoice = Vec :: new ( ) ;
2782
+ invoice. write ( & mut encoded_invoice) . unwrap ( ) ;
2783
+
2784
+ match Bolt12Invoice :: try_from ( encoded_invoice. clone ( ) ) {
2785
+ Ok ( invoice) => assert_eq ! ( invoice. bytes, encoded_invoice) ,
2786
+ Err ( e) => panic ! ( "error parsing invoice: {:?}" , e) ,
2787
+ }
2788
+
2789
+ const UNKNOWN_EVEN_TYPE : u64 = EXPERIMENTAL_INVOICE_TYPES . start ;
2790
+ assert ! ( UNKNOWN_EVEN_TYPE % 2 == 0 ) ;
2791
+
2792
+ let mut unsigned_invoice = OfferBuilder :: new ( keys. public_key ( ) )
2793
+ . amount_msats ( 1000 )
2794
+ . build ( ) . unwrap ( )
2795
+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
2796
+ . build ( ) . unwrap ( )
2797
+ . sign ( payer_sign) . unwrap ( )
2798
+ . respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
2799
+ . build ( ) . unwrap ( ) ;
2800
+
2801
+ BigSize ( UNKNOWN_EVEN_TYPE ) . write ( & mut unsigned_invoice. experimental_bytes ) . unwrap ( ) ;
2802
+ BigSize ( 32 ) . write ( & mut unsigned_invoice. experimental_bytes ) . unwrap ( ) ;
2803
+ [ 42u8 ; 32 ] . write ( & mut unsigned_invoice. experimental_bytes ) . unwrap ( ) ;
2804
+
2805
+ let tlv_stream = TlvStream :: new ( & unsigned_invoice. bytes )
2806
+ . chain ( TlvStream :: new ( & unsigned_invoice. experimental_bytes ) ) ;
2807
+ unsigned_invoice. tagged_hash = TaggedHash :: from_tlv_stream ( SIGNATURE_TAG , tlv_stream) ;
2808
+
2809
+ let invoice = unsigned_invoice
2810
+ . sign ( |message : & UnsignedBolt12Invoice |
2811
+ Ok ( secp_ctx. sign_schnorr_no_aux_rand ( message. as_ref ( ) . as_digest ( ) , & keys) )
2812
+ )
2813
+ . unwrap ( ) ;
2814
+
2815
+ let mut encoded_invoice = Vec :: new ( ) ;
2816
+ invoice. write ( & mut encoded_invoice) . unwrap ( ) ;
2817
+
2818
+ match Bolt12Invoice :: try_from ( encoded_invoice) {
2819
+ Ok ( _) => panic ! ( "expected error" ) ,
2820
+ Err ( e) => assert_eq ! ( e, Bolt12ParseError :: Decode ( DecodeError :: UnknownRequiredFeature ) ) ,
2821
+ }
2822
+
2823
+ let invoice = OfferBuilder :: new ( keys. public_key ( ) )
2824
+ . amount_msats ( 1000 )
2825
+ . build ( ) . unwrap ( )
2826
+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
2827
+ . build ( ) . unwrap ( )
2828
+ . sign ( payer_sign) . unwrap ( )
2829
+ . respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
2830
+ . build ( ) . unwrap ( )
2831
+ . sign ( |message : & UnsignedBolt12Invoice |
2832
+ Ok ( secp_ctx. sign_schnorr_no_aux_rand ( message. as_ref ( ) . as_digest ( ) , & keys) )
2833
+ )
2834
+ . unwrap ( ) ;
2835
+
2836
+ let mut encoded_invoice = Vec :: new ( ) ;
2837
+ invoice. write ( & mut encoded_invoice) . unwrap ( ) ;
2838
+
2839
+ BigSize ( UNKNOWN_ODD_TYPE ) . write ( & mut encoded_invoice) . unwrap ( ) ;
2840
+ BigSize ( 32 ) . write ( & mut encoded_invoice) . unwrap ( ) ;
2841
+ [ 42u8 ; 32 ] . write ( & mut encoded_invoice) . unwrap ( ) ;
2842
+
2843
+ match Bolt12Invoice :: try_from ( encoded_invoice) {
2844
+ Ok ( _) => panic ! ( "expected error" ) ,
2845
+ Err ( e) => assert_eq ! ( e, Bolt12ParseError :: InvalidSignature ( secp256k1:: Error :: IncorrectSignature ) ) ,
2846
+ }
2847
+ }
2848
+
2708
2849
#[ test]
2709
2850
fn fails_parsing_invoice_with_out_of_range_tlv_records ( ) {
2710
2851
let invoice = OfferBuilder :: new ( recipient_pubkey ( ) )
0 commit comments