@@ -173,10 +173,31 @@ impl<'a> InvoiceRequestBuilder<'a> {
173173
174174#[ cfg( test) ]
175175impl < ' a > InvoiceRequestBuilder < ' a > {
176+ fn chain_unchecked ( mut self , network : Network ) -> Self {
177+ let chain = ChainHash :: using_genesis_block ( network) ;
178+ self . invoice_request . chain = Some ( chain) ;
179+ self
180+ }
181+
182+ fn amount_msats_unchecked ( mut self , amount_msats : u64 ) -> Self {
183+ self . invoice_request . amount_msats = Some ( amount_msats) ;
184+ self
185+ }
186+
176187 fn features_unchecked ( mut self , features : InvoiceRequestFeatures ) -> Self {
177188 self . invoice_request . features = features;
178189 self
179190 }
191+
192+ fn quantity_unchecked ( mut self , quantity : u64 ) -> Self {
193+ self . invoice_request . quantity = Some ( quantity) ;
194+ self
195+ }
196+
197+ fn build_unchecked ( self ) -> UnsignedInvoiceRequest < ' a > {
198+ let InvoiceRequestBuilder { offer, invoice_request } = self ;
199+ UnsignedInvoiceRequest { offer, invoice_request }
200+ }
180201}
181202
182203/// A semantically valid [`InvoiceRequest`] that hasn't been signed.
@@ -463,7 +484,7 @@ mod tests {
463484 use crate :: ln:: features:: InvoiceRequestFeatures ;
464485 use crate :: ln:: msgs:: { DecodeError , MAX_VALUE_MSAT } ;
465486 use crate :: offers:: merkle:: SignError ;
466- use crate :: offers:: offer:: { OfferBuilder , Quantity } ;
487+ use crate :: offers:: offer:: { Amount , OfferBuilder , Quantity } ;
467488 use crate :: offers:: parse:: { ParseError , SemanticError } ;
468489 use crate :: util:: ser:: { BigSize , Writeable } ;
469490 use crate :: util:: string:: PrintableString ;
@@ -893,6 +914,342 @@ mod tests {
893914 }
894915 }
895916
917+ #[ test]
918+ fn parses_invoice_request_with_metadata ( ) {
919+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
920+ . amount_msats ( 1000 )
921+ . build ( ) . unwrap ( )
922+ . request_invoice ( vec ! [ 42 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
923+ . build ( ) . unwrap ( )
924+ . sign ( payer_sign) . unwrap ( ) ;
925+
926+ let mut buffer = Vec :: new ( ) ;
927+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
928+
929+ if let Err ( e) = InvoiceRequest :: try_from ( buffer) {
930+ panic ! ( "error parsing invoice_request: {:?}" , e) ;
931+ }
932+ }
933+
934+ #[ test]
935+ fn parses_invoice_request_with_chain ( ) {
936+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
937+ . amount_msats ( 1000 )
938+ . build ( ) . unwrap ( )
939+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
940+ . chain ( Network :: Bitcoin ) . unwrap ( )
941+ . build ( ) . unwrap ( )
942+ . sign ( payer_sign) . unwrap ( ) ;
943+
944+ let mut buffer = Vec :: new ( ) ;
945+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
946+
947+ if let Err ( e) = InvoiceRequest :: try_from ( buffer) {
948+ panic ! ( "error parsing invoice_request: {:?}" , e) ;
949+ }
950+
951+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
952+ . amount_msats ( 1000 )
953+ . build ( ) . unwrap ( )
954+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
955+ . chain_unchecked ( Network :: Testnet )
956+ . build_unchecked ( )
957+ . sign ( payer_sign) . unwrap ( ) ;
958+
959+ let mut buffer = Vec :: new ( ) ;
960+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
961+
962+ match InvoiceRequest :: try_from ( buffer) {
963+ Ok ( _) => panic ! ( "expected error" ) ,
964+ Err ( e) => assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: UnsupportedChain ) ) ,
965+ }
966+ }
967+
968+ #[ test]
969+ fn parses_invoice_request_with_amount ( ) {
970+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
971+ . amount_msats ( 1000 )
972+ . build ( ) . unwrap ( )
973+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
974+ . build ( ) . unwrap ( )
975+ . sign ( payer_sign) . unwrap ( ) ;
976+
977+ let mut buffer = Vec :: new ( ) ;
978+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
979+
980+ if let Err ( e) = InvoiceRequest :: try_from ( buffer) {
981+ panic ! ( "error parsing invoice_request: {:?}" , e) ;
982+ }
983+
984+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
985+ . build ( ) . unwrap ( )
986+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
987+ . amount_msats ( 1000 ) . unwrap ( )
988+ . build ( ) . unwrap ( )
989+ . sign ( payer_sign) . unwrap ( ) ;
990+
991+ let mut buffer = Vec :: new ( ) ;
992+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
993+
994+ if let Err ( e) = InvoiceRequest :: try_from ( buffer) {
995+ panic ! ( "error parsing invoice_request: {:?}" , e) ;
996+ }
997+
998+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
999+ . build ( ) . unwrap ( )
1000+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1001+ . build_unchecked ( )
1002+ . sign ( payer_sign) . unwrap ( ) ;
1003+
1004+ let mut buffer = Vec :: new ( ) ;
1005+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
1006+
1007+ match InvoiceRequest :: try_from ( buffer) {
1008+ Ok ( _) => panic ! ( "expected error" ) ,
1009+ Err ( e) => assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: MissingAmount ) ) ,
1010+ }
1011+
1012+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1013+ . amount_msats ( 1000 )
1014+ . build ( ) . unwrap ( )
1015+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1016+ . amount_msats_unchecked ( 999 )
1017+ . build_unchecked ( )
1018+ . sign ( payer_sign) . unwrap ( ) ;
1019+
1020+ let mut buffer = Vec :: new ( ) ;
1021+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
1022+
1023+ match InvoiceRequest :: try_from ( buffer) {
1024+ Ok ( _) => panic ! ( "expected error" ) ,
1025+ Err ( e) => assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: InsufficientAmount ) ) ,
1026+ }
1027+
1028+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1029+ . amount ( Amount :: Currency { iso4217_code : * b"USD" , amount : 1000 } )
1030+ . build_unchecked ( )
1031+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1032+ . build_unchecked ( )
1033+ . sign ( payer_sign) . unwrap ( ) ;
1034+
1035+ let mut buffer = Vec :: new ( ) ;
1036+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
1037+
1038+ match InvoiceRequest :: try_from ( buffer) {
1039+ Ok ( _) => panic ! ( "expected error" ) ,
1040+ Err ( e) => {
1041+ assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: UnsupportedCurrency ) ) ;
1042+ } ,
1043+ }
1044+ }
1045+
1046+ #[ test]
1047+ fn parses_invoice_request_with_quantity ( ) {
1048+ let ten = NonZeroU64 :: new ( 10 ) . unwrap ( ) ;
1049+
1050+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1051+ . amount_msats ( 1000 )
1052+ . supported_quantity ( Quantity :: one ( ) )
1053+ . build ( ) . unwrap ( )
1054+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1055+ . build ( ) . unwrap ( )
1056+ . sign ( payer_sign) . unwrap ( ) ;
1057+
1058+ let mut buffer = Vec :: new ( ) ;
1059+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
1060+
1061+ if let Err ( e) = InvoiceRequest :: try_from ( buffer) {
1062+ panic ! ( "error parsing invoice_request: {:?}" , e) ;
1063+ }
1064+
1065+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1066+ . amount_msats ( 1000 )
1067+ . supported_quantity ( Quantity :: one ( ) )
1068+ . build ( ) . unwrap ( )
1069+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1070+ . amount_msats ( 2_000 ) . unwrap ( )
1071+ . quantity_unchecked ( 2 )
1072+ . build_unchecked ( )
1073+ . sign ( payer_sign) . unwrap ( ) ;
1074+
1075+ let mut buffer = Vec :: new ( ) ;
1076+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
1077+
1078+ match InvoiceRequest :: try_from ( buffer) {
1079+ Ok ( _) => panic ! ( "expected error" ) ,
1080+ Err ( e) => {
1081+ assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: UnexpectedQuantity ) ) ;
1082+ } ,
1083+ }
1084+
1085+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1086+ . amount_msats ( 1000 )
1087+ . supported_quantity ( Quantity :: Bounded ( ten) )
1088+ . build ( ) . unwrap ( )
1089+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1090+ . amount_msats ( 10_000 ) . unwrap ( )
1091+ . quantity ( 10 ) . unwrap ( )
1092+ . build ( ) . unwrap ( )
1093+ . sign ( payer_sign) . unwrap ( ) ;
1094+
1095+ let mut buffer = Vec :: new ( ) ;
1096+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
1097+
1098+ if let Err ( e) = InvoiceRequest :: try_from ( buffer) {
1099+ panic ! ( "error parsing invoice_request: {:?}" , e) ;
1100+ }
1101+
1102+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1103+ . amount_msats ( 1000 )
1104+ . supported_quantity ( Quantity :: Bounded ( ten) )
1105+ . build ( ) . unwrap ( )
1106+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1107+ . amount_msats ( 11_000 ) . unwrap ( )
1108+ . quantity_unchecked ( 11 )
1109+ . build_unchecked ( )
1110+ . sign ( payer_sign) . unwrap ( ) ;
1111+
1112+ let mut buffer = Vec :: new ( ) ;
1113+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
1114+
1115+ match InvoiceRequest :: try_from ( buffer) {
1116+ Ok ( _) => panic ! ( "expected error" ) ,
1117+ Err ( e) => assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: InvalidQuantity ) ) ,
1118+ }
1119+
1120+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1121+ . amount_msats ( 1000 )
1122+ . supported_quantity ( Quantity :: Unbounded )
1123+ . build ( ) . unwrap ( )
1124+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1125+ . amount_msats ( 2_000 ) . unwrap ( )
1126+ . quantity ( 2 ) . unwrap ( )
1127+ . build ( ) . unwrap ( )
1128+ . sign ( payer_sign) . unwrap ( ) ;
1129+
1130+ let mut buffer = Vec :: new ( ) ;
1131+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
1132+
1133+ if let Err ( e) = InvoiceRequest :: try_from ( buffer) {
1134+ panic ! ( "error parsing invoice_request: {:?}" , e) ;
1135+ }
1136+
1137+ let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1138+ . amount_msats ( 1000 )
1139+ . supported_quantity ( Quantity :: Unbounded )
1140+ . build ( ) . unwrap ( )
1141+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1142+ . build_unchecked ( )
1143+ . sign ( payer_sign) . unwrap ( ) ;
1144+
1145+ let mut buffer = Vec :: new ( ) ;
1146+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
1147+
1148+ match InvoiceRequest :: try_from ( buffer) {
1149+ Ok ( _) => panic ! ( "expected error" ) ,
1150+ Err ( e) => assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: MissingQuantity ) ) ,
1151+ }
1152+ }
1153+
1154+ #[ test]
1155+ fn fails_parsing_invoice_request_without_metadata ( ) {
1156+ let offer = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1157+ . amount_msats ( 1000 )
1158+ . build ( ) . unwrap ( ) ;
1159+ let unsigned_invoice_request = offer. request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1160+ . build ( ) . unwrap ( ) ;
1161+ let mut tlv_stream = unsigned_invoice_request. invoice_request . as_tlv_stream ( ) ;
1162+ tlv_stream. 0 . metadata = None ;
1163+
1164+ let mut buffer = Vec :: new ( ) ;
1165+ tlv_stream. write ( & mut buffer) . unwrap ( ) ;
1166+
1167+ match InvoiceRequest :: try_from ( buffer) {
1168+ Ok ( _) => panic ! ( "expected error" ) ,
1169+ Err ( e) => {
1170+ assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: MissingPayerMetadata ) ) ;
1171+ } ,
1172+ }
1173+ }
1174+
1175+ #[ test]
1176+ fn fails_parsing_invoice_request_without_payer_id ( ) {
1177+ let offer = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1178+ . amount_msats ( 1000 )
1179+ . build ( ) . unwrap ( ) ;
1180+ let unsigned_invoice_request = offer. request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1181+ . build ( ) . unwrap ( ) ;
1182+ let mut tlv_stream = unsigned_invoice_request. invoice_request . as_tlv_stream ( ) ;
1183+ tlv_stream. 2 . payer_id = None ;
1184+
1185+ let mut buffer = Vec :: new ( ) ;
1186+ tlv_stream. write ( & mut buffer) . unwrap ( ) ;
1187+
1188+ match InvoiceRequest :: try_from ( buffer) {
1189+ Ok ( _) => panic ! ( "expected error" ) ,
1190+ Err ( e) => assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: MissingPayerId ) ) ,
1191+ }
1192+ }
1193+
1194+ #[ test]
1195+ fn fails_parsing_invoice_request_without_node_id ( ) {
1196+ let offer = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1197+ . amount_msats ( 1000 )
1198+ . build ( ) . unwrap ( ) ;
1199+ let unsigned_invoice_request = offer. request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1200+ . build ( ) . unwrap ( ) ;
1201+ let mut tlv_stream = unsigned_invoice_request. invoice_request . as_tlv_stream ( ) ;
1202+ tlv_stream. 1 . node_id = None ;
1203+
1204+ let mut buffer = Vec :: new ( ) ;
1205+ tlv_stream. write ( & mut buffer) . unwrap ( ) ;
1206+
1207+ match InvoiceRequest :: try_from ( buffer) {
1208+ Ok ( _) => panic ! ( "expected error" ) ,
1209+ Err ( e) => {
1210+ assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: MissingSigningPubkey ) ) ;
1211+ } ,
1212+ }
1213+ }
1214+
1215+ #[ test]
1216+ fn parses_invoice_request_without_signature ( ) {
1217+ let mut buffer = Vec :: new ( ) ;
1218+ OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1219+ . amount_msats ( 1000 )
1220+ . build ( ) . unwrap ( )
1221+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1222+ . build ( ) . unwrap ( )
1223+ . invoice_request
1224+ . write ( & mut buffer) . unwrap ( ) ;
1225+
1226+ if let Err ( e) = InvoiceRequest :: try_from ( buffer) {
1227+ panic ! ( "error parsing invoice_request: {:?}" , e) ;
1228+ }
1229+ }
1230+
1231+ #[ test]
1232+ fn fails_parsing_invoice_request_with_invalid_signature ( ) {
1233+ let mut invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1234+ . amount_msats ( 1000 )
1235+ . build ( ) . unwrap ( )
1236+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1237+ . build ( ) . unwrap ( )
1238+ . sign ( payer_sign) . unwrap ( ) ;
1239+ let last_signature_byte = invoice_request. bytes . last_mut ( ) . unwrap ( ) ;
1240+ * last_signature_byte = last_signature_byte. wrapping_add ( 1 ) ;
1241+
1242+ let mut buffer = Vec :: new ( ) ;
1243+ invoice_request. write ( & mut buffer) . unwrap ( ) ;
1244+
1245+ match InvoiceRequest :: try_from ( buffer) {
1246+ Ok ( _) => panic ! ( "expected error" ) ,
1247+ Err ( e) => {
1248+ assert_eq ! ( e, ParseError :: InvalidSignature ( secp256k1:: Error :: InvalidSignature ) ) ;
1249+ } ,
1250+ }
1251+ }
1252+
8961253 #[ test]
8971254 fn fails_parsing_invoice_request_with_extra_tlv_records ( ) {
8981255 let secp_ctx = Secp256k1 :: new ( ) ;
0 commit comments