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