@@ -286,6 +286,11 @@ impl Refund {
286
286
pub fn payer_note ( & self ) -> Option < PrintableString > {
287
287
self . contents . payer_note . as_ref ( ) . map ( |payer_note| PrintableString ( payer_note. as_str ( ) ) )
288
288
}
289
+
290
+ #[ cfg( test) ]
291
+ fn as_tlv_stream ( & self ) -> RefundTlvStreamRef {
292
+ self . contents . as_tlv_stream ( )
293
+ }
289
294
}
290
295
291
296
impl AsRef < [ u8 ] > for Refund {
@@ -472,3 +477,228 @@ impl core::fmt::Display for Refund {
472
477
self . fmt_bech32_str ( f)
473
478
}
474
479
}
480
+
481
+ #[ cfg( test) ]
482
+ mod tests {
483
+ use super :: { Refund , RefundBuilder } ;
484
+
485
+ use bitcoin:: blockdata:: constants:: ChainHash ;
486
+ use bitcoin:: network:: constants:: Network ;
487
+ use bitcoin:: secp256k1:: { KeyPair , PublicKey , Secp256k1 , SecretKey } ;
488
+ use core:: convert:: TryFrom ;
489
+ #[ cfg( feature = "std" ) ]
490
+ use core:: time:: Duration ;
491
+ use crate :: ln:: features:: InvoiceRequestFeatures ;
492
+ use crate :: ln:: msgs:: MAX_VALUE_MSAT ;
493
+ use crate :: offers:: invoice_request:: InvoiceRequestTlvStreamRef ;
494
+ use crate :: offers:: offer:: OfferTlvStreamRef ;
495
+ use crate :: offers:: parse:: SemanticError ;
496
+ use crate :: offers:: payer:: PayerTlvStreamRef ;
497
+ use crate :: onion_message:: { BlindedHop , BlindedPath } ;
498
+ use crate :: util:: ser:: Writeable ;
499
+ use crate :: util:: string:: PrintableString ;
500
+
501
+ fn payer_pubkey ( ) -> PublicKey {
502
+ let secp_ctx = Secp256k1 :: new ( ) ;
503
+ KeyPair :: from_secret_key ( & secp_ctx, & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ) . public_key ( )
504
+ }
505
+
506
+ fn pubkey ( byte : u8 ) -> PublicKey {
507
+ let secp_ctx = Secp256k1 :: new ( ) ;
508
+ PublicKey :: from_secret_key ( & secp_ctx, & privkey ( byte) )
509
+ }
510
+
511
+ fn privkey ( byte : u8 ) -> SecretKey {
512
+ SecretKey :: from_slice ( & [ byte; 32 ] ) . unwrap ( )
513
+ }
514
+
515
+ #[ test]
516
+ fn builds_refund_with_defaults ( ) {
517
+ let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
518
+ . build ( ) . unwrap ( ) ;
519
+
520
+ let mut buffer = Vec :: new ( ) ;
521
+ refund. write ( & mut buffer) . unwrap ( ) ;
522
+
523
+ assert_eq ! ( refund. bytes, buffer. as_slice( ) ) ;
524
+ assert_eq ! ( refund. metadata( ) , & [ 1 ; 32 ] ) ;
525
+ assert_eq ! ( refund. description( ) , PrintableString ( "foo" ) ) ;
526
+ assert_eq ! ( refund. absolute_expiry( ) , None ) ;
527
+ #[ cfg( feature = "std" ) ]
528
+ assert ! ( !refund. is_expired( ) ) ;
529
+ assert_eq ! ( refund. paths( ) , & [ ] ) ;
530
+ assert_eq ! ( refund. issuer( ) , None ) ;
531
+ assert_eq ! ( refund. chain( ) , ChainHash :: using_genesis_block( Network :: Bitcoin ) ) ;
532
+ assert_eq ! ( refund. amount_msats( ) , 1000 ) ;
533
+ assert_eq ! ( refund. features( ) , & InvoiceRequestFeatures :: empty( ) ) ;
534
+ assert_eq ! ( refund. payer_id( ) , payer_pubkey( ) ) ;
535
+ assert_eq ! ( refund. payer_note( ) , None ) ;
536
+
537
+ assert_eq ! (
538
+ refund. as_tlv_stream( ) ,
539
+ (
540
+ PayerTlvStreamRef { metadata: Some ( & vec![ 1 ; 32 ] ) } ,
541
+ OfferTlvStreamRef {
542
+ chains: None ,
543
+ metadata: None ,
544
+ currency: None ,
545
+ amount: None ,
546
+ description: Some ( & String :: from( "foo" ) ) ,
547
+ features: None ,
548
+ absolute_expiry: None ,
549
+ paths: None ,
550
+ issuer: None ,
551
+ quantity_max: None ,
552
+ node_id: None ,
553
+ } ,
554
+ InvoiceRequestTlvStreamRef {
555
+ chain: None ,
556
+ amount: Some ( 1000 ) ,
557
+ features: None ,
558
+ quantity: None ,
559
+ payer_id: Some ( & payer_pubkey( ) ) ,
560
+ payer_note: None ,
561
+ } ,
562
+ ) ,
563
+ ) ;
564
+
565
+ if let Err ( e) = Refund :: try_from ( buffer) {
566
+ panic ! ( "error parsing refund: {:?}" , e) ;
567
+ }
568
+ }
569
+
570
+ #[ test]
571
+ fn fails_buidling_refund_with_invalid_amount ( ) {
572
+ match RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , MAX_VALUE_MSAT + 1 ) {
573
+ Ok ( _) => panic ! ( "expected error" ) ,
574
+ Err ( e) => assert_eq ! ( e, SemanticError :: InvalidAmount ) ,
575
+ }
576
+ }
577
+
578
+ #[ test]
579
+ fn builds_refund_with_absolute_expiry ( ) {
580
+ let future_expiry = Duration :: from_secs ( u64:: max_value ( ) ) ;
581
+ let past_expiry = Duration :: from_secs ( 0 ) ;
582
+
583
+ let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
584
+ . absolute_expiry ( future_expiry)
585
+ . build ( )
586
+ . unwrap ( ) ;
587
+ let ( _, tlv_stream, _) = refund. as_tlv_stream ( ) ;
588
+ #[ cfg( feature = "std" ) ]
589
+ assert ! ( !refund. is_expired( ) ) ;
590
+ assert_eq ! ( refund. absolute_expiry( ) , Some ( future_expiry) ) ;
591
+ assert_eq ! ( tlv_stream. absolute_expiry, Some ( future_expiry. as_secs( ) ) ) ;
592
+
593
+ let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
594
+ . absolute_expiry ( future_expiry)
595
+ . absolute_expiry ( past_expiry)
596
+ . build ( )
597
+ . unwrap ( ) ;
598
+ let ( _, tlv_stream, _) = refund. as_tlv_stream ( ) ;
599
+ #[ cfg( feature = "std" ) ]
600
+ assert ! ( refund. is_expired( ) ) ;
601
+ assert_eq ! ( refund. absolute_expiry( ) , Some ( past_expiry) ) ;
602
+ assert_eq ! ( tlv_stream. absolute_expiry, Some ( past_expiry. as_secs( ) ) ) ;
603
+ }
604
+
605
+ #[ test]
606
+ fn builds_refund_with_paths ( ) {
607
+ let paths = vec ! [
608
+ BlindedPath {
609
+ introduction_node_id: pubkey( 40 ) ,
610
+ blinding_point: pubkey( 41 ) ,
611
+ blinded_hops: vec![
612
+ BlindedHop { blinded_node_id: pubkey( 43 ) , encrypted_payload: vec![ 0 ; 43 ] } ,
613
+ BlindedHop { blinded_node_id: pubkey( 44 ) , encrypted_payload: vec![ 0 ; 44 ] } ,
614
+ ] ,
615
+ } ,
616
+ BlindedPath {
617
+ introduction_node_id: pubkey( 40 ) ,
618
+ blinding_point: pubkey( 41 ) ,
619
+ blinded_hops: vec![
620
+ BlindedHop { blinded_node_id: pubkey( 45 ) , encrypted_payload: vec![ 0 ; 45 ] } ,
621
+ BlindedHop { blinded_node_id: pubkey( 46 ) , encrypted_payload: vec![ 0 ; 46 ] } ,
622
+ ] ,
623
+ } ,
624
+ ] ;
625
+
626
+ let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
627
+ . path ( paths[ 0 ] . clone ( ) )
628
+ . path ( paths[ 1 ] . clone ( ) )
629
+ . build ( )
630
+ . unwrap ( ) ;
631
+ let ( _, offer_tlv_stream, invoice_request_tlv_stream) = refund. as_tlv_stream ( ) ;
632
+ assert_eq ! ( refund. paths( ) , paths. as_slice( ) ) ;
633
+ assert_eq ! ( refund. payer_id( ) , pubkey( 42 ) ) ;
634
+ assert_ne ! ( pubkey( 42 ) , pubkey( 44 ) ) ;
635
+ assert_eq ! ( offer_tlv_stream. paths, Some ( & paths) ) ;
636
+ assert_eq ! ( invoice_request_tlv_stream. payer_id, Some ( & pubkey( 42 ) ) ) ;
637
+ }
638
+
639
+ #[ test]
640
+ fn builds_refund_with_issuer ( ) {
641
+ let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
642
+ . issuer ( "bar" . into ( ) )
643
+ . build ( )
644
+ . unwrap ( ) ;
645
+ let ( _, tlv_stream, _) = refund. as_tlv_stream ( ) ;
646
+ assert_eq ! ( refund. issuer( ) , Some ( PrintableString ( "bar" ) ) ) ;
647
+ assert_eq ! ( tlv_stream. issuer, Some ( & String :: from( "bar" ) ) ) ;
648
+
649
+ let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
650
+ . issuer ( "bar" . into ( ) )
651
+ . issuer ( "baz" . into ( ) )
652
+ . build ( )
653
+ . unwrap ( ) ;
654
+ let ( _, tlv_stream, _) = refund. as_tlv_stream ( ) ;
655
+ assert_eq ! ( refund. issuer( ) , Some ( PrintableString ( "baz" ) ) ) ;
656
+ assert_eq ! ( tlv_stream. issuer, Some ( & String :: from( "baz" ) ) ) ;
657
+ }
658
+
659
+ #[ test]
660
+ fn builds_refund_with_chain ( ) {
661
+ let mainnet = ChainHash :: using_genesis_block ( Network :: Bitcoin ) ;
662
+ let testnet = ChainHash :: using_genesis_block ( Network :: Testnet ) ;
663
+
664
+ let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
665
+ . chain ( Network :: Bitcoin )
666
+ . build ( ) . unwrap ( ) ;
667
+ let ( _, _, tlv_stream) = refund. as_tlv_stream ( ) ;
668
+ assert_eq ! ( refund. chain( ) , mainnet) ;
669
+ assert_eq ! ( tlv_stream. chain, None ) ;
670
+
671
+ let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
672
+ . chain ( Network :: Testnet )
673
+ . build ( ) . unwrap ( ) ;
674
+ let ( _, _, tlv_stream) = refund. as_tlv_stream ( ) ;
675
+ assert_eq ! ( refund. chain( ) , testnet) ;
676
+ assert_eq ! ( tlv_stream. chain, Some ( & testnet) ) ;
677
+
678
+ let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
679
+ . chain ( Network :: Regtest )
680
+ . chain ( Network :: Testnet )
681
+ . build ( ) . unwrap ( ) ;
682
+ let ( _, _, tlv_stream) = refund. as_tlv_stream ( ) ;
683
+ assert_eq ! ( refund. chain( ) , testnet) ;
684
+ assert_eq ! ( tlv_stream. chain, Some ( & testnet) ) ;
685
+ }
686
+
687
+ #[ test]
688
+ fn builds_refund_with_payer_note ( ) {
689
+ let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
690
+ . payer_note ( "bar" . into ( ) )
691
+ . build ( ) . unwrap ( ) ;
692
+ let ( _, _, tlv_stream) = refund. as_tlv_stream ( ) ;
693
+ assert_eq ! ( refund. payer_note( ) , Some ( PrintableString ( "bar" ) ) ) ;
694
+ assert_eq ! ( tlv_stream. payer_note, Some ( & String :: from( "bar" ) ) ) ;
695
+
696
+ let refund = RefundBuilder :: new ( "foo" . into ( ) , vec ! [ 1 ; 32 ] , payer_pubkey ( ) , 1000 ) . unwrap ( )
697
+ . payer_note ( "bar" . into ( ) )
698
+ . payer_note ( "baz" . into ( ) )
699
+ . build ( ) . unwrap ( ) ;
700
+ let ( _, _, tlv_stream) = refund. as_tlv_stream ( ) ;
701
+ assert_eq ! ( refund. payer_note( ) , Some ( PrintableString ( "baz" ) ) ) ;
702
+ assert_eq ! ( tlv_stream. payer_note, Some ( & String :: from( "baz" ) ) ) ;
703
+ }
704
+ }
0 commit comments