@@ -546,3 +546,304 @@ impl TryFrom<(OfferTlvStream, InvoiceTlvStream)> for InvoiceContents {
546
546
} )
547
547
}
548
548
}
549
+
550
+ #[ cfg( test) ]
551
+ mod tests {
552
+ use crate :: blinded_path:: { BlindedHop , BlindedPath , IntroductionNode } ;
553
+ use crate :: ln:: features:: { Bolt12InvoiceFeatures , OfferFeatures } ;
554
+ use crate :: ln:: inbound_payment:: ExpandedKey ;
555
+ use crate :: offers:: invoice:: SIGNATURE_TAG ;
556
+ use crate :: offers:: merkle;
557
+ use crate :: offers:: merkle:: TaggedHash ;
558
+ use crate :: offers:: offer:: { Offer , OfferBuilder , Quantity } ;
559
+ use crate :: offers:: parse:: Bolt12SemanticError ;
560
+ use crate :: offers:: static_invoice:: {
561
+ StaticInvoice , StaticInvoiceBuilder , DEFAULT_RELATIVE_EXPIRY ,
562
+ } ;
563
+ use crate :: offers:: test_utils:: * ;
564
+ use crate :: sign:: KeyMaterial ;
565
+ use crate :: util:: ser:: Writeable ;
566
+ use bitcoin:: blockdata:: constants:: ChainHash ;
567
+ use bitcoin:: network:: constants:: Network ;
568
+ use bitcoin:: secp256k1:: Secp256k1 ;
569
+ use core:: time:: Duration ;
570
+
571
+ fn blinded_path ( ) -> BlindedPath {
572
+ BlindedPath {
573
+ introduction_node : IntroductionNode :: NodeId ( pubkey ( 40 ) ) ,
574
+ blinding_point : pubkey ( 41 ) ,
575
+ blinded_hops : vec ! [
576
+ BlindedHop { blinded_node_id: pubkey( 42 ) , encrypted_payload: vec![ 0 ; 43 ] } ,
577
+ BlindedHop { blinded_node_id: pubkey( 43 ) , encrypted_payload: vec![ 0 ; 44 ] } ,
578
+ ] ,
579
+ }
580
+ }
581
+
582
+ #[ test]
583
+ fn builds_invoice_for_offer_with_defaults ( ) {
584
+ let node_id = recipient_pubkey ( ) ;
585
+ let payment_paths = payment_paths ( ) ;
586
+ let now = now ( ) ;
587
+ let expanded_key = ExpandedKey :: new ( & KeyMaterial ( [ 42 ; 32 ] ) ) ;
588
+ let entropy = FixedEntropy { } ;
589
+ let secp_ctx = Secp256k1 :: new ( ) ;
590
+
591
+ let offer =
592
+ OfferBuilder :: deriving_signing_pubkey ( node_id, & expanded_key, & entropy, & secp_ctx)
593
+ . path ( blinded_path ( ) )
594
+ . build ( )
595
+ . unwrap ( ) ;
596
+
597
+ let ( _offer_id, keys_opt) = offer. verify ( & expanded_key, & secp_ctx) . unwrap ( ) ;
598
+ let invoice = StaticInvoiceBuilder :: for_offer_using_keys (
599
+ & offer,
600
+ payment_paths. clone ( ) ,
601
+ vec ! [ blinded_path( ) ] ,
602
+ now,
603
+ keys_opt. unwrap ( ) ,
604
+ )
605
+ . unwrap ( )
606
+ . build_and_sign ( & secp_ctx)
607
+ . unwrap ( ) ;
608
+
609
+ let mut buffer = Vec :: new ( ) ;
610
+ invoice. write ( & mut buffer) . unwrap ( ) ;
611
+
612
+ assert_eq ! ( invoice. bytes, buffer. as_slice( ) ) ;
613
+ assert ! ( invoice. metadata( ) . is_some( ) ) ;
614
+ assert_eq ! ( invoice. amount( ) , None ) ;
615
+ assert_eq ! ( invoice. description( ) , None ) ;
616
+ assert_eq ! ( invoice. offer_features( ) , & OfferFeatures :: empty( ) ) ;
617
+ assert_eq ! ( invoice. absolute_expiry( ) , None ) ;
618
+ assert_eq ! ( invoice. offer_message_paths( ) , & [ blinded_path( ) ] ) ;
619
+ assert_eq ! ( invoice. message_paths( ) , & [ blinded_path( ) ] ) ;
620
+ assert_eq ! ( invoice. issuer( ) , None ) ;
621
+ assert_eq ! ( invoice. supported_quantity( ) , Quantity :: One ) ;
622
+ assert_ne ! ( invoice. signing_pubkey( ) , recipient_pubkey( ) ) ;
623
+ assert_eq ! ( invoice. chain( ) , ChainHash :: using_genesis_block( Network :: Bitcoin ) ) ;
624
+ assert_eq ! ( invoice. payment_paths( ) , payment_paths. as_slice( ) ) ;
625
+ assert_eq ! ( invoice. created_at( ) , now) ;
626
+ assert_eq ! ( invoice. relative_expiry( ) , DEFAULT_RELATIVE_EXPIRY ) ;
627
+ #[ cfg( feature = "std" ) ]
628
+ assert ! ( !invoice. is_expired( ) ) ;
629
+ assert_eq ! ( invoice. fallbacks( ) , vec![ ] ) ;
630
+ assert_eq ! ( invoice. invoice_features( ) , & Bolt12InvoiceFeatures :: empty( ) ) ;
631
+
632
+ let message = TaggedHash :: from_valid_tlv_stream_bytes ( SIGNATURE_TAG , & invoice. bytes ) ;
633
+ assert ! ( merkle:: verify_signature(
634
+ & invoice. signature,
635
+ & message,
636
+ keys_opt. unwrap( ) . public_key( )
637
+ )
638
+ . is_ok( ) ) ;
639
+
640
+ if let Err ( e) = StaticInvoice :: try_from ( buffer) {
641
+ panic ! ( "error parsing invoice: {:?}" , e) ;
642
+ }
643
+ }
644
+
645
+ #[ cfg( feature = "std" ) ]
646
+ #[ test]
647
+ fn builds_invoice_from_offer_with_expiration ( ) {
648
+ let node_id = recipient_pubkey ( ) ;
649
+ let now = now ( ) ;
650
+ let expanded_key = ExpandedKey :: new ( & KeyMaterial ( [ 42 ; 32 ] ) ) ;
651
+ let entropy = FixedEntropy { } ;
652
+ let secp_ctx = Secp256k1 :: new ( ) ;
653
+
654
+ let future_expiry = Duration :: from_secs ( u64:: max_value ( ) ) ;
655
+ let past_expiry = Duration :: from_secs ( 0 ) ;
656
+
657
+ let valid_offer =
658
+ OfferBuilder :: deriving_signing_pubkey ( node_id, & expanded_key, & entropy, & secp_ctx)
659
+ . path ( blinded_path ( ) )
660
+ . absolute_expiry ( future_expiry)
661
+ . build ( )
662
+ . unwrap ( ) ;
663
+
664
+ let ( _offer_id, keys_opt) = valid_offer. verify ( & expanded_key, & secp_ctx) . unwrap ( ) ;
665
+ let invoice = StaticInvoiceBuilder :: for_offer_using_keys (
666
+ & valid_offer,
667
+ payment_paths ( ) ,
668
+ vec ! [ blinded_path( ) ] ,
669
+ now,
670
+ keys_opt. unwrap ( ) ,
671
+ )
672
+ . unwrap ( )
673
+ . build_and_sign ( & secp_ctx)
674
+ . unwrap ( ) ;
675
+ assert ! ( !invoice. is_expired( ) ) ;
676
+ assert_eq ! ( invoice. absolute_expiry( ) , Some ( future_expiry) ) ;
677
+
678
+ let expired_offer =
679
+ OfferBuilder :: deriving_signing_pubkey ( node_id, & expanded_key, & entropy, & secp_ctx)
680
+ . path ( blinded_path ( ) )
681
+ . absolute_expiry ( past_expiry)
682
+ . build ( )
683
+ . unwrap ( ) ;
684
+ let ( _offer_id, keys_opt) = expired_offer. verify ( & expanded_key, & secp_ctx) . unwrap ( ) ;
685
+ if let Err ( e) = StaticInvoiceBuilder :: for_offer_using_keys (
686
+ & expired_offer,
687
+ payment_paths ( ) ,
688
+ vec ! [ blinded_path( ) ] ,
689
+ now,
690
+ keys_opt. unwrap ( ) ,
691
+ )
692
+ . unwrap ( )
693
+ . build_and_sign ( & secp_ctx)
694
+ {
695
+ assert_eq ! ( e, Bolt12SemanticError :: AlreadyExpired ) ;
696
+ } else {
697
+ panic ! ( "expected error" )
698
+ }
699
+ }
700
+
701
+ #[ test]
702
+ fn fails_build_with_missing_paths ( ) {
703
+ let node_id = recipient_pubkey ( ) ;
704
+ let now = now ( ) ;
705
+ let expanded_key = ExpandedKey :: new ( & KeyMaterial ( [ 42 ; 32 ] ) ) ;
706
+ let entropy = FixedEntropy { } ;
707
+ let secp_ctx = Secp256k1 :: new ( ) ;
708
+
709
+ let valid_offer =
710
+ OfferBuilder :: deriving_signing_pubkey ( node_id, & expanded_key, & entropy, & secp_ctx)
711
+ . path ( blinded_path ( ) )
712
+ . build ( )
713
+ . unwrap ( ) ;
714
+ let ( _offer_id, keys_opt) = valid_offer. verify ( & expanded_key, & secp_ctx) . unwrap ( ) ;
715
+
716
+ // Error if payment paths are missing.
717
+ if let Err ( e) = StaticInvoiceBuilder :: for_offer_using_keys (
718
+ & valid_offer,
719
+ Vec :: new ( ) ,
720
+ vec ! [ blinded_path( ) ] ,
721
+ now,
722
+ keys_opt. unwrap ( ) ,
723
+ ) {
724
+ assert_eq ! ( e, Bolt12SemanticError :: MissingPaths ) ;
725
+ } else {
726
+ panic ! ( "expected error" )
727
+ }
728
+
729
+ // Error if message paths are missing.
730
+ if let Err ( e) = StaticInvoiceBuilder :: for_offer_using_keys (
731
+ & valid_offer,
732
+ payment_paths ( ) ,
733
+ Vec :: new ( ) ,
734
+ now,
735
+ keys_opt. unwrap ( ) ,
736
+ ) {
737
+ assert_eq ! ( e, Bolt12SemanticError :: MissingPaths ) ;
738
+ } else {
739
+ panic ! ( "expected error" )
740
+ }
741
+
742
+ // Error if offer paths are missing.
743
+ let mut offer_without_paths = valid_offer. clone ( ) ;
744
+ let mut offer_tlv_stream = offer_without_paths. as_tlv_stream ( ) ;
745
+ offer_tlv_stream. paths . take ( ) ;
746
+ let mut buffer = Vec :: new ( ) ;
747
+ offer_tlv_stream. write ( & mut buffer) . unwrap ( ) ;
748
+ offer_without_paths = Offer :: try_from ( buffer) . unwrap ( ) ;
749
+ if let Err ( e) = StaticInvoiceBuilder :: for_offer_using_keys (
750
+ & offer_without_paths,
751
+ payment_paths ( ) ,
752
+ vec ! [ blinded_path( ) ] ,
753
+ now,
754
+ keys_opt. unwrap ( ) ,
755
+ ) {
756
+ assert_eq ! ( e, Bolt12SemanticError :: MissingPaths ) ;
757
+ } else {
758
+ panic ! ( "expected error" )
759
+ }
760
+ }
761
+
762
+ #[ test]
763
+ fn fails_build_offer_signing_pubkey ( ) {
764
+ let node_id = recipient_pubkey ( ) ;
765
+ let now = now ( ) ;
766
+ let expanded_key = ExpandedKey :: new ( & KeyMaterial ( [ 42 ; 32 ] ) ) ;
767
+ let entropy = FixedEntropy { } ;
768
+ let secp_ctx = Secp256k1 :: new ( ) ;
769
+
770
+ let valid_offer =
771
+ OfferBuilder :: deriving_signing_pubkey ( node_id, & expanded_key, & entropy, & secp_ctx)
772
+ . path ( blinded_path ( ) )
773
+ . build ( )
774
+ . unwrap ( ) ;
775
+ let ( _offer_id, keys_opt) = valid_offer. verify ( & expanded_key, & secp_ctx) . unwrap ( ) ;
776
+
777
+ // Error if offer signing pubkey is missing.
778
+ let mut offer_missing_signing_pubkey = valid_offer. clone ( ) ;
779
+ let mut offer_tlv_stream = offer_missing_signing_pubkey. as_tlv_stream ( ) ;
780
+ offer_tlv_stream. node_id . take ( ) ;
781
+ let mut buffer = Vec :: new ( ) ;
782
+ offer_tlv_stream. write ( & mut buffer) . unwrap ( ) ;
783
+ offer_missing_signing_pubkey = Offer :: try_from ( buffer) . unwrap ( ) ;
784
+
785
+ if let Err ( e) = StaticInvoiceBuilder :: for_offer_using_keys (
786
+ & offer_missing_signing_pubkey,
787
+ payment_paths ( ) ,
788
+ vec ! [ blinded_path( ) ] ,
789
+ now,
790
+ keys_opt. unwrap ( ) ,
791
+ ) {
792
+ assert_eq ! ( e, Bolt12SemanticError :: MissingSigningPubkey ) ;
793
+ } else {
794
+ panic ! ( "expected error" )
795
+ }
796
+
797
+ // Error if the offer's signing pubkey doesn't match the invoice's.
798
+ let mut offer_invalid_signing_pubkey = valid_offer. clone ( ) ;
799
+ let mut offer_tlv_stream = offer_invalid_signing_pubkey. as_tlv_stream ( ) ;
800
+ let invalid_node_id = payer_pubkey ( ) ;
801
+ offer_tlv_stream. node_id = Some ( & invalid_node_id) ;
802
+ let mut buffer = Vec :: new ( ) ;
803
+ offer_tlv_stream. write ( & mut buffer) . unwrap ( ) ;
804
+ offer_invalid_signing_pubkey = Offer :: try_from ( buffer) . unwrap ( ) ;
805
+
806
+ if let Err ( e) = StaticInvoiceBuilder :: for_offer_using_keys (
807
+ & offer_invalid_signing_pubkey,
808
+ payment_paths ( ) ,
809
+ vec ! [ blinded_path( ) ] ,
810
+ now,
811
+ keys_opt. unwrap ( ) ,
812
+ ) {
813
+ assert_eq ! ( e, Bolt12SemanticError :: InvalidSigningPubkey ) ;
814
+ } else {
815
+ panic ! ( "expected error" )
816
+ }
817
+ }
818
+
819
+ #[ test]
820
+ fn fails_build_with_extra_offer_chains ( ) {
821
+ let node_id = recipient_pubkey ( ) ;
822
+ let now = now ( ) ;
823
+ let expanded_key = ExpandedKey :: new ( & KeyMaterial ( [ 42 ; 32 ] ) ) ;
824
+ let entropy = FixedEntropy { } ;
825
+ let secp_ctx = Secp256k1 :: new ( ) ;
826
+
827
+ let offer_with_extra_chain =
828
+ OfferBuilder :: deriving_signing_pubkey ( node_id, & expanded_key, & entropy, & secp_ctx)
829
+ . path ( blinded_path ( ) )
830
+ . chain ( Network :: Bitcoin )
831
+ . chain ( Network :: Testnet )
832
+ . build ( )
833
+ . unwrap ( ) ;
834
+ let ( _offer_id, keys_opt) =
835
+ offer_with_extra_chain. verify ( & expanded_key, & secp_ctx) . unwrap ( ) ;
836
+
837
+ if let Err ( e) = StaticInvoiceBuilder :: for_offer_using_keys (
838
+ & offer_with_extra_chain,
839
+ payment_paths ( ) ,
840
+ vec ! [ blinded_path( ) ] ,
841
+ now,
842
+ keys_opt. unwrap ( ) ,
843
+ ) {
844
+ assert_eq ! ( e, Bolt12SemanticError :: UnexpectedChain ) ;
845
+ } else {
846
+ panic ! ( "expected error" )
847
+ }
848
+ }
849
+ }
0 commit comments