@@ -293,6 +293,16 @@ impl InvoiceRequest {
293
293
pub fn signature ( & self ) -> Option < Signature > {
294
294
self . signature
295
295
}
296
+
297
+ #[ cfg( test) ]
298
+ fn as_tlv_stream ( & self ) -> FullInvoiceRequestTlvStreamRef {
299
+ let ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream) =
300
+ self . contents . as_tlv_stream ( ) ;
301
+ let signature_tlv_stream = SignatureTlvStreamRef {
302
+ signature : self . signature . as_ref ( ) ,
303
+ } ;
304
+ ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, signature_tlv_stream)
305
+ }
296
306
}
297
307
298
308
impl InvoiceRequestContents {
@@ -349,6 +359,14 @@ tlv_stream!(InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef, 80..160, {
349
359
type FullInvoiceRequestTlvStream =
350
360
( PayerTlvStream , OfferTlvStream , InvoiceRequestTlvStream , SignatureTlvStream ) ;
351
361
362
+ #[ cfg( test) ]
363
+ type FullInvoiceRequestTlvStreamRef < ' a > = (
364
+ PayerTlvStreamRef < ' a > ,
365
+ OfferTlvStreamRef < ' a > ,
366
+ InvoiceRequestTlvStreamRef < ' a > ,
367
+ SignatureTlvStreamRef < ' a > ,
368
+ ) ;
369
+
352
370
impl SeekReadable for FullInvoiceRequestTlvStream {
353
371
fn read < R : io:: Read + io:: Seek > ( r : & mut R ) -> Result < Self , DecodeError > {
354
372
let payer = SeekReadable :: read ( r) ?;
@@ -443,12 +461,352 @@ impl TryFrom<PartialInvoiceRequestTlvStream> for InvoiceRequestContents {
443
461
mod tests {
444
462
use super :: InvoiceRequest ;
445
463
446
- use bitcoin:: secp256k1:: { KeyPair , Secp256k1 , SecretKey } ;
464
+ use bitcoin:: blockdata:: constants:: ChainHash ;
465
+ use bitcoin:: network:: constants:: Network ;
466
+ use bitcoin:: secp256k1:: { KeyPair , Message , PublicKey , Secp256k1 , SecretKey } ;
467
+ use bitcoin:: secp256k1:: schnorr:: Signature ;
447
468
use core:: convert:: TryFrom ;
469
+ use core:: num:: NonZeroU64 ;
470
+ use crate :: ln:: features:: InvoiceRequestFeatures ;
448
471
use crate :: ln:: msgs:: DecodeError ;
449
- use crate :: offers:: offer:: OfferBuilder ;
450
- use crate :: offers:: parse:: ParseError ;
472
+ use crate :: offers:: offer:: { OfferBuilder , Quantity } ;
473
+ use crate :: offers:: parse:: { ParseError , SemanticError } ;
451
474
use crate :: util:: ser:: { BigSize , Writeable } ;
475
+ use crate :: util:: string:: PrintableString ;
476
+
477
+ fn payer_keys ( ) -> KeyPair {
478
+ let secp_ctx = Secp256k1 :: new ( ) ;
479
+ KeyPair :: from_secret_key ( & secp_ctx, & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) )
480
+ }
481
+
482
+ fn payer_sign ( digest : & Message ) -> Signature {
483
+ let secp_ctx = Secp256k1 :: new ( ) ;
484
+ let keys = KeyPair :: from_secret_key ( & secp_ctx, & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ) ;
485
+ secp_ctx. sign_schnorr_no_aux_rand ( digest, & keys)
486
+ }
487
+
488
+ fn payer_pubkey ( ) -> PublicKey {
489
+ payer_keys ( ) . public_key ( )
490
+ }
491
+
492
+ fn recipient_pubkey ( ) -> PublicKey {
493
+ let secp_ctx = Secp256k1 :: new ( ) ;
494
+ KeyPair :: from_secret_key ( & secp_ctx, & SecretKey :: from_slice ( & [ 43 ; 32 ] ) . unwrap ( ) ) . public_key ( )
495
+ }
496
+
497
+ #[ test]
498
+ fn builds_invoice_request_with_defaults ( ) {
499
+ let offer = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
500
+ . amount_msats ( 1000 )
501
+ . build ( ) . unwrap ( ) ;
502
+ let invoice_request = offer. request_invoice ( payer_pubkey ( ) )
503
+ . build ( ) . unwrap ( ) . sign ( payer_sign) . unwrap ( ) ;
504
+
505
+ let ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, signature_tlv_stream) =
506
+ invoice_request. as_tlv_stream ( ) ;
507
+ let mut buffer = Vec :: new ( ) ;
508
+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
509
+
510
+ assert_eq ! ( invoice_request. bytes, buffer. as_slice( ) ) ;
511
+ assert_eq ! ( invoice_request. metadata( ) , None ) ;
512
+ assert_eq ! ( invoice_request. chain( ) , ChainHash :: using_genesis_block( Network :: Bitcoin ) ) ;
513
+ assert_eq ! ( invoice_request. amount_msats( ) , None ) ;
514
+ assert_eq ! ( invoice_request. features( ) , & InvoiceRequestFeatures :: empty( ) ) ;
515
+ assert_eq ! ( invoice_request. quantity( ) , None ) ;
516
+ assert_eq ! ( invoice_request. payer_id( ) , payer_pubkey( ) ) ;
517
+ assert_eq ! ( invoice_request. payer_note( ) , None ) ;
518
+ assert ! ( invoice_request. signature( ) . is_some( ) ) ;
519
+
520
+ assert_eq ! ( payer_tlv_stream. metadata, None ) ;
521
+ assert_eq ! ( offer_tlv_stream. chains, None ) ;
522
+ assert_eq ! ( offer_tlv_stream. metadata, None ) ;
523
+ assert_eq ! ( offer_tlv_stream. currency, None ) ;
524
+ assert_eq ! ( offer_tlv_stream. amount, Some ( 1000 ) ) ;
525
+ assert_eq ! ( offer_tlv_stream. description, Some ( & String :: from( "foo" ) ) ) ;
526
+ assert_eq ! ( offer_tlv_stream. features, None ) ;
527
+ assert_eq ! ( offer_tlv_stream. absolute_expiry, None ) ;
528
+ assert_eq ! ( offer_tlv_stream. paths, None ) ;
529
+ assert_eq ! ( offer_tlv_stream. issuer, None ) ;
530
+ assert_eq ! ( offer_tlv_stream. quantity_max, None ) ;
531
+ assert_eq ! ( offer_tlv_stream. node_id, Some ( & recipient_pubkey( ) ) ) ;
532
+ assert_eq ! ( invoice_request_tlv_stream. chain, None ) ;
533
+ assert_eq ! ( invoice_request_tlv_stream. amount, None ) ;
534
+ assert_eq ! ( invoice_request_tlv_stream. features, None ) ;
535
+ assert_eq ! ( invoice_request_tlv_stream. quantity, None ) ;
536
+ assert_eq ! ( invoice_request_tlv_stream. payer_id, Some ( & payer_pubkey( ) ) ) ;
537
+ assert_eq ! ( invoice_request_tlv_stream. payer_note, None ) ;
538
+ assert ! ( signature_tlv_stream. signature. is_some( ) ) ;
539
+
540
+ if let Err ( e) = InvoiceRequest :: try_from ( buffer) {
541
+ panic ! ( "error parsing offer: {:?}" , e) ;
542
+ }
543
+ }
544
+
545
+ #[ test]
546
+ fn builds_invoice_request_with_metadata ( ) {
547
+ let offer = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
548
+ . amount_msats ( 1000 )
549
+ . build ( ) . unwrap ( ) ;
550
+
551
+ let invoice_request = offer. request_invoice ( payer_pubkey ( ) )
552
+ . metadata ( vec ! [ 42 ; 32 ] )
553
+ . build ( ) . unwrap ( )
554
+ . sign ( payer_sign) . unwrap ( ) ;
555
+ let ( tlv_stream, _, _, _) = invoice_request. as_tlv_stream ( ) ;
556
+ assert_eq ! ( invoice_request. metadata( ) , Some ( & vec![ 42 ; 32 ] ) ) ;
557
+ assert_eq ! ( tlv_stream. metadata, Some ( & vec![ 42 ; 32 ] ) ) ;
558
+
559
+ let invoice_request = offer. request_invoice ( payer_pubkey ( ) )
560
+ . metadata ( vec ! [ 42 ; 32 ] )
561
+ . metadata ( vec ! [ 43 ; 32 ] )
562
+ . build ( ) . unwrap ( )
563
+ . sign ( payer_sign) . unwrap ( ) ;
564
+ let ( tlv_stream, _, _, _) = invoice_request. as_tlv_stream ( ) ;
565
+ assert_eq ! ( invoice_request. metadata( ) , Some ( & vec![ 43 ; 32 ] ) ) ;
566
+ assert_eq ! ( tlv_stream. metadata, Some ( & vec![ 43 ; 32 ] ) ) ;
567
+ }
568
+
569
+ #[ test]
570
+ fn builds_invoice_request_with_chain ( ) {
571
+ let mainnet = ChainHash :: using_genesis_block ( Network :: Bitcoin ) ;
572
+ let testnet = ChainHash :: using_genesis_block ( Network :: Testnet ) ;
573
+
574
+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
575
+ . amount_msats ( 1000 )
576
+ . build ( ) . unwrap ( )
577
+ . request_invoice ( payer_pubkey ( ) )
578
+ . chain ( Network :: Bitcoin )
579
+ . build ( ) . unwrap ( )
580
+ . sign ( payer_sign) . unwrap ( ) ;
581
+ let ( _, _, tlv_stream, _) = invoice_request. as_tlv_stream ( ) ;
582
+ assert_eq ! ( invoice_request. chain( ) , mainnet) ;
583
+ assert_eq ! ( tlv_stream. chain, None ) ;
584
+
585
+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
586
+ . amount_msats ( 1000 )
587
+ . chain ( Network :: Testnet )
588
+ . build ( ) . unwrap ( )
589
+ . request_invoice ( payer_pubkey ( ) )
590
+ . chain ( Network :: Testnet )
591
+ . build ( ) . unwrap ( )
592
+ . sign ( payer_sign) . unwrap ( ) ;
593
+ let ( _, _, tlv_stream, _) = invoice_request. as_tlv_stream ( ) ;
594
+ assert_eq ! ( invoice_request. chain( ) , testnet) ;
595
+ assert_eq ! ( tlv_stream. chain, Some ( & testnet) ) ;
596
+
597
+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
598
+ . amount_msats ( 1000 )
599
+ . chain ( Network :: Bitcoin )
600
+ . chain ( Network :: Testnet )
601
+ . build ( ) . unwrap ( )
602
+ . request_invoice ( payer_pubkey ( ) )
603
+ . chain ( Network :: Bitcoin )
604
+ . build ( ) . unwrap ( )
605
+ . sign ( payer_sign) . unwrap ( ) ;
606
+ let ( _, _, tlv_stream, _) = invoice_request. as_tlv_stream ( ) ;
607
+ assert_eq ! ( invoice_request. chain( ) , mainnet) ;
608
+ assert_eq ! ( tlv_stream. chain, None ) ;
609
+
610
+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
611
+ . amount_msats ( 1000 )
612
+ . chain ( Network :: Testnet )
613
+ . build ( ) . unwrap ( )
614
+ . request_invoice ( payer_pubkey ( ) )
615
+ . chain ( Network :: Bitcoin )
616
+ . chain ( Network :: Testnet )
617
+ . build ( ) . unwrap ( )
618
+ . sign ( payer_sign) . unwrap ( ) ;
619
+ let ( _, _, tlv_stream, _) = invoice_request. as_tlv_stream ( ) ;
620
+ assert_eq ! ( invoice_request. chain( ) , testnet) ;
621
+ assert_eq ! ( tlv_stream. chain, Some ( & testnet) ) ;
622
+
623
+ match OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
624
+ . amount_msats ( 1000 )
625
+ . chain ( Network :: Testnet )
626
+ . build ( ) . unwrap ( )
627
+ . request_invoice ( payer_pubkey ( ) )
628
+ . chain ( Network :: Bitcoin )
629
+ . build ( )
630
+ {
631
+ Ok ( _) => panic ! ( "expected error" ) ,
632
+ Err ( e) => assert_eq ! ( e, SemanticError :: UnsupportedChain ) ,
633
+ }
634
+ }
635
+
636
+ #[ test]
637
+ fn builds_invoice_request_with_amount ( ) {
638
+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
639
+ . amount_msats ( 1000 )
640
+ . build ( ) . unwrap ( )
641
+ . request_invoice ( payer_pubkey ( ) )
642
+ . amount_msats ( 1000 )
643
+ . build ( ) . unwrap ( )
644
+ . sign ( payer_sign) . unwrap ( ) ;
645
+ let ( _, _, tlv_stream, _) = invoice_request. as_tlv_stream ( ) ;
646
+ assert_eq ! ( invoice_request. amount_msats( ) , Some ( 1000 ) ) ;
647
+ assert_eq ! ( tlv_stream. amount, Some ( 1000 ) ) ;
648
+
649
+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
650
+ . amount_msats ( 1000 )
651
+ . build ( ) . unwrap ( )
652
+ . request_invoice ( payer_pubkey ( ) )
653
+ . amount_msats ( 999 )
654
+ . amount_msats ( 1000 )
655
+ . build ( ) . unwrap ( )
656
+ . sign ( payer_sign) . unwrap ( ) ;
657
+ let ( _, _, tlv_stream, _) = invoice_request. as_tlv_stream ( ) ;
658
+ assert_eq ! ( invoice_request. amount_msats( ) , Some ( 1000 ) ) ;
659
+ assert_eq ! ( tlv_stream. amount, Some ( 1000 ) ) ;
660
+
661
+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
662
+ . amount_msats ( 1000 )
663
+ . build ( ) . unwrap ( )
664
+ . request_invoice ( payer_pubkey ( ) )
665
+ . amount_msats ( 1001 )
666
+ . build ( ) . unwrap ( )
667
+ . sign ( payer_sign) . unwrap ( ) ;
668
+ let ( _, _, tlv_stream, _) = invoice_request. as_tlv_stream ( ) ;
669
+ assert_eq ! ( invoice_request. amount_msats( ) , Some ( 1001 ) ) ;
670
+ assert_eq ! ( tlv_stream. amount, Some ( 1001 ) ) ;
671
+
672
+ match OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
673
+ . amount_msats ( 1000 )
674
+ . build ( ) . unwrap ( )
675
+ . request_invoice ( payer_pubkey ( ) )
676
+ . amount_msats ( 999 )
677
+ . build ( )
678
+ {
679
+ Ok ( _) => panic ! ( "expected error" ) ,
680
+ Err ( e) => assert_eq ! ( e, SemanticError :: InsufficientAmount ) ,
681
+ }
682
+
683
+ match OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
684
+ . amount_msats ( 1000 )
685
+ . supported_quantity ( Quantity :: Unbounded )
686
+ . build ( ) . unwrap ( )
687
+ . request_invoice ( payer_pubkey ( ) )
688
+ . amount_msats ( 1000 )
689
+ . quantity ( 2 )
690
+ . build ( )
691
+ {
692
+ Ok ( _) => panic ! ( "expected error" ) ,
693
+ Err ( e) => assert_eq ! ( e, SemanticError :: InsufficientAmount ) ,
694
+ }
695
+
696
+ match OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
697
+ . build ( ) . unwrap ( )
698
+ . request_invoice ( payer_pubkey ( ) )
699
+ . build ( )
700
+ {
701
+ Ok ( _) => panic ! ( "expected error" ) ,
702
+ Err ( e) => assert_eq ! ( e, SemanticError :: MissingAmount ) ,
703
+ }
704
+ }
705
+
706
+ #[ test]
707
+ fn builds_invoice_request_with_quantity ( ) {
708
+ let ten = NonZeroU64 :: new ( 10 ) . unwrap ( ) ;
709
+
710
+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
711
+ . amount_msats ( 1000 )
712
+ . supported_quantity ( Quantity :: one ( ) )
713
+ . build ( ) . unwrap ( )
714
+ . request_invoice ( payer_pubkey ( ) )
715
+ . build ( ) . unwrap ( )
716
+ . sign ( payer_sign) . unwrap ( ) ;
717
+ let ( _, _, tlv_stream, _) = invoice_request. as_tlv_stream ( ) ;
718
+ assert_eq ! ( invoice_request. quantity( ) , None ) ;
719
+ assert_eq ! ( tlv_stream. quantity, None ) ;
720
+
721
+ match OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
722
+ . amount_msats ( 1000 )
723
+ . supported_quantity ( Quantity :: one ( ) )
724
+ . build ( ) . unwrap ( )
725
+ . request_invoice ( payer_pubkey ( ) )
726
+ . amount_msats ( 2_000 )
727
+ . quantity ( 2 )
728
+ . build ( )
729
+ {
730
+ Ok ( _) => panic ! ( "expected error" ) ,
731
+ Err ( e) => assert_eq ! ( e, SemanticError :: UnexpectedQuantity ) ,
732
+ }
733
+
734
+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
735
+ . amount_msats ( 1000 )
736
+ . supported_quantity ( Quantity :: Bounded ( ten) )
737
+ . build ( ) . unwrap ( )
738
+ . request_invoice ( payer_pubkey ( ) )
739
+ . amount_msats ( 10_000 )
740
+ . quantity ( 10 )
741
+ . build ( ) . unwrap ( )
742
+ . sign ( payer_sign) . unwrap ( ) ;
743
+ let ( _, _, tlv_stream, _) = invoice_request. as_tlv_stream ( ) ;
744
+ assert_eq ! ( invoice_request. amount_msats( ) , Some ( 10_000 ) ) ;
745
+ assert_eq ! ( tlv_stream. amount, Some ( 10_000 ) ) ;
746
+
747
+ match OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
748
+ . amount_msats ( 1000 )
749
+ . supported_quantity ( Quantity :: Bounded ( ten) )
750
+ . build ( ) . unwrap ( )
751
+ . request_invoice ( payer_pubkey ( ) )
752
+ . amount_msats ( 11_000 )
753
+ . quantity ( 11 )
754
+ . build ( )
755
+ {
756
+ Ok ( _) => panic ! ( "expected error" ) ,
757
+ Err ( e) => assert_eq ! ( e, SemanticError :: InvalidQuantity ) ,
758
+ }
759
+
760
+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
761
+ . amount_msats ( 1000 )
762
+ . supported_quantity ( Quantity :: Unbounded )
763
+ . build ( ) . unwrap ( )
764
+ . request_invoice ( payer_pubkey ( ) )
765
+ . amount_msats ( 2_000 )
766
+ . quantity ( 2 )
767
+ . build ( ) . unwrap ( )
768
+ . sign ( payer_sign) . unwrap ( ) ;
769
+ let ( _, _, tlv_stream, _) = invoice_request. as_tlv_stream ( ) ;
770
+ assert_eq ! ( invoice_request. amount_msats( ) , Some ( 2_000 ) ) ;
771
+ assert_eq ! ( tlv_stream. amount, Some ( 2_000 ) ) ;
772
+
773
+ match OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
774
+ . amount_msats ( 1000 )
775
+ . supported_quantity ( Quantity :: Unbounded )
776
+ . build ( ) . unwrap ( )
777
+ . request_invoice ( payer_pubkey ( ) )
778
+ . build ( )
779
+ {
780
+ Ok ( _) => panic ! ( "expected error" ) ,
781
+ Err ( e) => assert_eq ! ( e, SemanticError :: MissingQuantity ) ,
782
+ }
783
+ }
784
+
785
+ #[ test]
786
+ fn builds_invoice_request_with_payer_note ( ) {
787
+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
788
+ . amount_msats ( 1000 )
789
+ . build ( ) . unwrap ( )
790
+ . request_invoice ( payer_pubkey ( ) )
791
+ . payer_note ( "bar" . into ( ) )
792
+ . build ( ) . unwrap ( )
793
+ . sign ( payer_sign) . unwrap ( ) ;
794
+ let ( _, _, tlv_stream, _) = invoice_request. as_tlv_stream ( ) ;
795
+ assert_eq ! ( invoice_request. payer_note( ) , Some ( PrintableString ( "bar" ) ) ) ;
796
+ assert_eq ! ( tlv_stream. payer_note, Some ( & String :: from( "bar" ) ) ) ;
797
+
798
+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
799
+ . amount_msats ( 1000 )
800
+ . build ( ) . unwrap ( )
801
+ . request_invoice ( payer_pubkey ( ) )
802
+ . payer_note ( "bar" . into ( ) )
803
+ . payer_note ( "baz" . into ( ) )
804
+ . build ( ) . unwrap ( )
805
+ . sign ( payer_sign) . unwrap ( ) ;
806
+ let ( _, _, tlv_stream, _) = invoice_request. as_tlv_stream ( ) ;
807
+ assert_eq ! ( invoice_request. payer_note( ) , Some ( PrintableString ( "baz" ) ) ) ;
808
+ assert_eq ! ( tlv_stream. payer_note, Some ( & String :: from( "baz" ) ) ) ;
809
+ }
452
810
453
811
#[ test]
454
812
fn fails_parsing_invoice_request_with_extra_tlv_records ( ) {
0 commit comments