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