@@ -565,19 +565,20 @@ mod tests {
565
565
use crate :: blinded_path:: { BlindedHop , BlindedPath , IntroductionNode } ;
566
566
use crate :: ln:: features:: { Bolt12InvoiceFeatures , OfferFeatures } ;
567
567
use crate :: ln:: inbound_payment:: ExpandedKey ;
568
+ use crate :: ln:: msgs:: DecodeError ;
568
569
use crate :: offers:: invoice:: { InvoiceTlvStreamRef , SIGNATURE_TAG } ;
569
570
use crate :: offers:: merkle;
570
571
use crate :: offers:: merkle:: { SignatureTlvStreamRef , TaggedHash } ;
571
572
use crate :: offers:: offer:: { Offer , OfferBuilder , OfferTlvStreamRef , Quantity } ;
572
- use crate :: offers:: parse:: Bolt12SemanticError ;
573
+ use crate :: offers:: parse:: { Bolt12ParseError , Bolt12SemanticError } ;
573
574
use crate :: offers:: static_invoice:: {
574
575
StaticInvoice , StaticInvoiceBuilder , DEFAULT_RELATIVE_EXPIRY ,
575
576
} ;
576
577
use crate :: offers:: test_utils:: * ;
577
578
use crate :: sign:: KeyMaterial ;
578
- use crate :: util:: ser:: { Iterable , Writeable } ;
579
+ use crate :: util:: ser:: { BigSize , Iterable , Writeable } ;
579
580
use bitcoin:: blockdata:: constants:: ChainHash ;
580
- use bitcoin:: secp256k1:: Secp256k1 ;
581
+ use bitcoin:: secp256k1:: { self , Secp256k1 } ;
581
582
use bitcoin:: Network ;
582
583
use core:: time:: Duration ;
583
584
@@ -595,6 +596,43 @@ mod tests {
595
596
}
596
597
}
597
598
599
+ fn tlv_stream_to_bytes (
600
+ tlv_stream : & ( OfferTlvStreamRef , InvoiceTlvStreamRef , SignatureTlvStreamRef ) ,
601
+ ) -> Vec < u8 > {
602
+ let mut buffer = Vec :: new ( ) ;
603
+ tlv_stream. 0 . write ( & mut buffer) . unwrap ( ) ;
604
+ tlv_stream. 1 . write ( & mut buffer) . unwrap ( ) ;
605
+ tlv_stream. 2 . write ( & mut buffer) . unwrap ( ) ;
606
+ buffer
607
+ }
608
+
609
+ fn invoice ( ) -> StaticInvoice {
610
+ let node_id = recipient_pubkey ( ) ;
611
+ let payment_paths = payment_paths ( ) ;
612
+ let now = now ( ) ;
613
+ let expanded_key = ExpandedKey :: new ( & KeyMaterial ( [ 42 ; 32 ] ) ) ;
614
+ let entropy = FixedEntropy { } ;
615
+ let secp_ctx = Secp256k1 :: new ( ) ;
616
+
617
+ let offer =
618
+ OfferBuilder :: deriving_signing_pubkey ( node_id, & expanded_key, & entropy, & secp_ctx)
619
+ . path ( blinded_path ( ) )
620
+ . build ( )
621
+ . unwrap ( ) ;
622
+
623
+ StaticInvoiceBuilder :: for_offer_using_derived_keys (
624
+ & offer,
625
+ payment_paths. clone ( ) ,
626
+ vec ! [ blinded_path( ) ] ,
627
+ now,
628
+ & expanded_key,
629
+ & secp_ctx,
630
+ )
631
+ . unwrap ( )
632
+ . build_and_sign ( & secp_ctx)
633
+ . unwrap ( )
634
+ }
635
+
598
636
fn blinded_path ( ) -> BlindedPath {
599
637
BlindedPath {
600
638
introduction_node : IntroductionNode :: NodeId ( pubkey ( 40 ) ) ,
@@ -905,4 +943,231 @@ mod tests {
905
943
panic ! ( "expected error" )
906
944
}
907
945
}
946
+
947
+ #[ test]
948
+ fn parses_invoice_with_relative_expiry ( ) {
949
+ let node_id = recipient_pubkey ( ) ;
950
+ let payment_paths = payment_paths ( ) ;
951
+ let now = now ( ) ;
952
+ let expanded_key = ExpandedKey :: new ( & KeyMaterial ( [ 42 ; 32 ] ) ) ;
953
+ let entropy = FixedEntropy { } ;
954
+ let secp_ctx = Secp256k1 :: new ( ) ;
955
+
956
+ let offer =
957
+ OfferBuilder :: deriving_signing_pubkey ( node_id, & expanded_key, & entropy, & secp_ctx)
958
+ . path ( blinded_path ( ) )
959
+ . build ( )
960
+ . unwrap ( ) ;
961
+
962
+ const TEST_RELATIVE_EXPIRY : u32 = 3600 ;
963
+ let invoice = StaticInvoiceBuilder :: for_offer_using_derived_keys (
964
+ & offer,
965
+ payment_paths. clone ( ) ,
966
+ vec ! [ blinded_path( ) ] ,
967
+ now,
968
+ & expanded_key,
969
+ & secp_ctx,
970
+ )
971
+ . unwrap ( )
972
+ . relative_expiry ( TEST_RELATIVE_EXPIRY )
973
+ . build_and_sign ( & secp_ctx)
974
+ . unwrap ( ) ;
975
+
976
+ let mut buffer = Vec :: new ( ) ;
977
+ invoice. write ( & mut buffer) . unwrap ( ) ;
978
+
979
+ match StaticInvoice :: try_from ( buffer) {
980
+ Ok ( invoice) => assert_eq ! (
981
+ invoice. relative_expiry( ) ,
982
+ Duration :: from_secs( TEST_RELATIVE_EXPIRY as u64 )
983
+ ) ,
984
+ Err ( e) => panic ! ( "error parsing invoice: {:?}" , e) ,
985
+ }
986
+ }
987
+
988
+ #[ test]
989
+ fn parses_invoice_with_allow_mpp ( ) {
990
+ let node_id = recipient_pubkey ( ) ;
991
+ let payment_paths = payment_paths ( ) ;
992
+ let now = now ( ) ;
993
+ let expanded_key = ExpandedKey :: new ( & KeyMaterial ( [ 42 ; 32 ] ) ) ;
994
+ let entropy = FixedEntropy { } ;
995
+ let secp_ctx = Secp256k1 :: new ( ) ;
996
+
997
+ let offer =
998
+ OfferBuilder :: deriving_signing_pubkey ( node_id, & expanded_key, & entropy, & secp_ctx)
999
+ . path ( blinded_path ( ) )
1000
+ . build ( )
1001
+ . unwrap ( ) ;
1002
+
1003
+ let invoice = StaticInvoiceBuilder :: for_offer_using_derived_keys (
1004
+ & offer,
1005
+ payment_paths. clone ( ) ,
1006
+ vec ! [ blinded_path( ) ] ,
1007
+ now,
1008
+ & expanded_key,
1009
+ & secp_ctx,
1010
+ )
1011
+ . unwrap ( )
1012
+ . allow_mpp ( )
1013
+ . build_and_sign ( & secp_ctx)
1014
+ . unwrap ( ) ;
1015
+
1016
+ let mut buffer = Vec :: new ( ) ;
1017
+ invoice. write ( & mut buffer) . unwrap ( ) ;
1018
+
1019
+ match StaticInvoice :: try_from ( buffer) {
1020
+ Ok ( invoice) => {
1021
+ let mut features = Bolt12InvoiceFeatures :: empty ( ) ;
1022
+ features. set_basic_mpp_optional ( ) ;
1023
+ assert_eq ! ( invoice. invoice_features( ) , & features) ;
1024
+ } ,
1025
+ Err ( e) => panic ! ( "error parsing invoice: {:?}" , e) ,
1026
+ }
1027
+ }
1028
+
1029
+ #[ test]
1030
+ fn fails_parsing_missing_invoice_fields ( ) {
1031
+ // Error if `created_at` is missing.
1032
+ let missing_created_at_invoice = invoice ( ) ;
1033
+ let mut tlv_stream = missing_created_at_invoice. as_tlv_stream ( ) ;
1034
+ tlv_stream. 1 . created_at = None ;
1035
+ match StaticInvoice :: try_from ( tlv_stream_to_bytes ( & tlv_stream) ) {
1036
+ Ok ( _) => panic ! ( "expected error" ) ,
1037
+ Err ( e) => {
1038
+ assert_eq ! (
1039
+ e,
1040
+ Bolt12ParseError :: InvalidSemantics ( Bolt12SemanticError :: MissingCreationTime )
1041
+ ) ;
1042
+ } ,
1043
+ }
1044
+
1045
+ // Error if `node_id` is missing.
1046
+ let missing_node_id_invoice = invoice ( ) ;
1047
+ let mut tlv_stream = missing_node_id_invoice. as_tlv_stream ( ) ;
1048
+ tlv_stream. 1 . node_id = None ;
1049
+ match StaticInvoice :: try_from ( tlv_stream_to_bytes ( & tlv_stream) ) {
1050
+ Ok ( _) => panic ! ( "expected error" ) ,
1051
+ Err ( e) => {
1052
+ assert_eq ! (
1053
+ e,
1054
+ Bolt12ParseError :: InvalidSemantics ( Bolt12SemanticError :: MissingSigningPubkey )
1055
+ ) ;
1056
+ } ,
1057
+ }
1058
+
1059
+ // Error if message paths are missing.
1060
+ let missing_message_paths_invoice = invoice ( ) ;
1061
+ let mut tlv_stream = missing_message_paths_invoice. as_tlv_stream ( ) ;
1062
+ tlv_stream. 1 . message_paths = None ;
1063
+ match StaticInvoice :: try_from ( tlv_stream_to_bytes ( & tlv_stream) ) {
1064
+ Ok ( _) => panic ! ( "expected error" ) ,
1065
+ Err ( e) => {
1066
+ assert_eq ! (
1067
+ e,
1068
+ Bolt12ParseError :: InvalidSemantics ( Bolt12SemanticError :: MissingPaths )
1069
+ ) ;
1070
+ } ,
1071
+ }
1072
+
1073
+ // Error if signature is missing.
1074
+ let invoice = invoice ( ) ;
1075
+ let mut buffer = Vec :: new ( ) ;
1076
+ invoice. contents . as_tlv_stream ( ) . write ( & mut buffer) . unwrap ( ) ;
1077
+ match StaticInvoice :: try_from ( buffer) {
1078
+ Ok ( _) => panic ! ( "expected error" ) ,
1079
+ Err ( e) => assert_eq ! (
1080
+ e,
1081
+ Bolt12ParseError :: InvalidSemantics ( Bolt12SemanticError :: MissingSignature )
1082
+ ) ,
1083
+ }
1084
+ }
1085
+
1086
+ #[ test]
1087
+ fn fails_parsing_invalid_signing_pubkey ( ) {
1088
+ let invoice = invoice ( ) ;
1089
+ let invalid_pubkey = payer_pubkey ( ) ;
1090
+ let mut tlv_stream = invoice. as_tlv_stream ( ) ;
1091
+ tlv_stream. 1 . node_id = Some ( & invalid_pubkey) ;
1092
+
1093
+ match StaticInvoice :: try_from ( tlv_stream_to_bytes ( & tlv_stream) ) {
1094
+ Ok ( _) => panic ! ( "expected error" ) ,
1095
+ Err ( e) => {
1096
+ assert_eq ! (
1097
+ e,
1098
+ Bolt12ParseError :: InvalidSemantics ( Bolt12SemanticError :: InvalidSigningPubkey )
1099
+ ) ;
1100
+ } ,
1101
+ }
1102
+ }
1103
+
1104
+ #[ test]
1105
+ fn fails_parsing_invoice_with_invalid_signature ( ) {
1106
+ let mut invoice = invoice ( ) ;
1107
+ let last_signature_byte = invoice. bytes . last_mut ( ) . unwrap ( ) ;
1108
+ * last_signature_byte = last_signature_byte. wrapping_add ( 1 ) ;
1109
+
1110
+ let mut buffer = Vec :: new ( ) ;
1111
+ invoice. write ( & mut buffer) . unwrap ( ) ;
1112
+
1113
+ match StaticInvoice :: try_from ( buffer) {
1114
+ Ok ( _) => panic ! ( "expected error" ) ,
1115
+ Err ( e) => {
1116
+ assert_eq ! (
1117
+ e,
1118
+ Bolt12ParseError :: InvalidSignature ( secp256k1:: Error :: InvalidSignature )
1119
+ ) ;
1120
+ } ,
1121
+ }
1122
+ }
1123
+
1124
+ #[ test]
1125
+ fn fails_parsing_invoice_with_extra_tlv_records ( ) {
1126
+ let invoice = invoice ( ) ;
1127
+ let mut encoded_invoice = Vec :: new ( ) ;
1128
+ invoice. write ( & mut encoded_invoice) . unwrap ( ) ;
1129
+ BigSize ( 1002 ) . write ( & mut encoded_invoice) . unwrap ( ) ;
1130
+ BigSize ( 32 ) . write ( & mut encoded_invoice) . unwrap ( ) ;
1131
+ [ 42u8 ; 32 ] . write ( & mut encoded_invoice) . unwrap ( ) ;
1132
+
1133
+ match StaticInvoice :: try_from ( encoded_invoice) {
1134
+ Ok ( _) => panic ! ( "expected error" ) ,
1135
+ Err ( e) => assert_eq ! ( e, Bolt12ParseError :: Decode ( DecodeError :: InvalidValue ) ) ,
1136
+ }
1137
+ }
1138
+
1139
+ #[ test]
1140
+ fn fails_parsing_invoice_with_invalid_offer_fields ( ) {
1141
+ // Error if the offer is missing paths.
1142
+ let missing_offer_paths_invoice = invoice ( ) ;
1143
+ let mut tlv_stream = missing_offer_paths_invoice. as_tlv_stream ( ) ;
1144
+ tlv_stream. 0 . paths = None ;
1145
+ match StaticInvoice :: try_from ( tlv_stream_to_bytes ( & tlv_stream) ) {
1146
+ Ok ( _) => panic ! ( "expected error" ) ,
1147
+ Err ( e) => {
1148
+ assert_eq ! (
1149
+ e,
1150
+ Bolt12ParseError :: InvalidSemantics ( Bolt12SemanticError :: MissingPaths )
1151
+ ) ;
1152
+ } ,
1153
+ }
1154
+
1155
+ // Error if the offer has more than one chain.
1156
+ let invalid_offer_chains_invoice = invoice ( ) ;
1157
+ let mut tlv_stream = invalid_offer_chains_invoice. as_tlv_stream ( ) ;
1158
+ let invalid_chains = vec ! [
1159
+ ChainHash :: using_genesis_block( Network :: Bitcoin ) ,
1160
+ ChainHash :: using_genesis_block( Network :: Testnet ) ,
1161
+ ] ;
1162
+ tlv_stream. 0 . chains = Some ( & invalid_chains) ;
1163
+ match StaticInvoice :: try_from ( tlv_stream_to_bytes ( & tlv_stream) ) {
1164
+ Ok ( _) => panic ! ( "expected error" ) ,
1165
+ Err ( e) => {
1166
+ assert_eq ! (
1167
+ e,
1168
+ Bolt12ParseError :: InvalidSemantics ( Bolt12SemanticError :: UnexpectedChain )
1169
+ ) ;
1170
+ } ,
1171
+ }
1172
+ }
908
1173
}
0 commit comments