@@ -450,6 +450,12 @@ impl Writeable for Invoice {
450450 }
451451}
452452
453+ impl Writeable for InvoiceContents {
454+ fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
455+ self . as_tlv_stream ( ) . write ( writer)
456+ }
457+ }
458+
453459impl TryFrom < Vec < u8 > > for Invoice {
454460 type Error = ParseError ;
455461
@@ -644,7 +650,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
644650
645651#[ cfg( test) ]
646652mod tests {
647- use super :: { DEFAULT_RELATIVE_EXPIRY , BlindedPayInfo , FallbackAddress , Invoice , InvoiceTlvStreamRef , SIGNATURE_TAG } ;
653+ use super :: { DEFAULT_RELATIVE_EXPIRY , BlindedPayInfo , FallbackAddress , FullInvoiceTlvStreamRef , Invoice , InvoiceTlvStreamRef , SIGNATURE_TAG } ;
648654
649655 use bitcoin:: blockdata:: script:: Script ;
650656 use bitcoin:: hashes:: Hash ;
@@ -657,15 +663,16 @@ mod tests {
657663 #[ cfg( feature = "std" ) ]
658664 use core:: time:: Duration ;
659665 use crate :: ln:: PaymentHash ;
666+ use crate :: ln:: msgs:: DecodeError ;
660667 use crate :: ln:: features:: { BlindedHopFeatures , Bolt12InvoiceFeatures } ;
661668 use crate :: offers:: invoice_request:: InvoiceRequestTlvStreamRef ;
662669 use crate :: offers:: merkle:: { SignError , SignatureTlvStreamRef , self } ;
663670 use crate :: offers:: offer:: { OfferBuilder , OfferTlvStreamRef } ;
664- use crate :: offers:: parse:: SemanticError ;
671+ use crate :: offers:: parse:: { ParseError , SemanticError } ;
665672 use crate :: offers:: payer:: PayerTlvStreamRef ;
666673 use crate :: offers:: refund:: RefundBuilder ;
667674 use crate :: onion_message:: { BlindedHop , BlindedPath } ;
668- use crate :: util:: ser:: { Iterable , Writeable } ;
675+ use crate :: util:: ser:: { BigSize , Iterable , Writeable } ;
669676
670677 fn payer_keys ( ) -> KeyPair {
671678 let secp_ctx = Secp256k1 :: new ( ) ;
@@ -706,6 +713,22 @@ mod tests {
706713 SecretKey :: from_slice ( & [ byte; 32 ] ) . unwrap ( )
707714 }
708715
716+ trait ToBytes {
717+ fn to_bytes ( & self ) -> Vec < u8 > ;
718+ }
719+
720+ impl < ' a > ToBytes for FullInvoiceTlvStreamRef < ' a > {
721+ fn to_bytes ( & self ) -> Vec < u8 > {
722+ let mut buffer = Vec :: new ( ) ;
723+ self . 0 . write ( & mut buffer) . unwrap ( ) ;
724+ self . 1 . write ( & mut buffer) . unwrap ( ) ;
725+ self . 2 . write ( & mut buffer) . unwrap ( ) ;
726+ self . 3 . write ( & mut buffer) . unwrap ( ) ;
727+ self . 4 . write ( & mut buffer) . unwrap ( ) ;
728+ buffer
729+ }
730+ }
731+
709732 fn payment_paths ( ) -> Vec < ( BlindedPath , BlindedPayInfo ) > {
710733 let paths = vec ! [
711734 BlindedPath {
@@ -1092,4 +1115,246 @@ mod tests {
10921115 Err ( e) => assert_eq ! ( e, SignError :: Verification ( secp256k1:: Error :: InvalidSignature ) ) ,
10931116 }
10941117 }
1118+
1119+ #[ test]
1120+ fn parses_invoice_with_payment_paths ( ) {
1121+ let invoice = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1122+ . amount_msats ( 1000 )
1123+ . build ( ) . unwrap ( )
1124+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1125+ . build ( ) . unwrap ( )
1126+ . sign ( payer_sign) . unwrap ( )
1127+ . respond_with ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
1128+ . build ( ) . unwrap ( )
1129+ . sign ( recipient_sign) . unwrap ( ) ;
1130+
1131+ let mut buffer = Vec :: new ( ) ;
1132+ invoice. write ( & mut buffer) . unwrap ( ) ;
1133+
1134+ if let Err ( e) = Invoice :: try_from ( buffer) {
1135+ panic ! ( "error parsing invoice: {:?}" , e) ;
1136+ }
1137+
1138+ let mut tlv_stream = invoice. as_tlv_stream ( ) ;
1139+ tlv_stream. 3 . paths = None ;
1140+
1141+ match Invoice :: try_from ( tlv_stream. to_bytes ( ) ) {
1142+ Ok ( _) => panic ! ( "expected error" ) ,
1143+ Err ( e) => assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: MissingPaths ) ) ,
1144+ }
1145+
1146+ let mut tlv_stream = invoice. as_tlv_stream ( ) ;
1147+ tlv_stream. 3 . blindedpay = None ;
1148+
1149+ match Invoice :: try_from ( tlv_stream. to_bytes ( ) ) {
1150+ Ok ( _) => panic ! ( "expected error" ) ,
1151+ Err ( e) => assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: InvalidPayInfo ) ) ,
1152+ }
1153+
1154+ let empty_payment_paths = vec ! [ ] ;
1155+ let mut tlv_stream = invoice. as_tlv_stream ( ) ;
1156+ tlv_stream. 3 . paths = Some ( Iterable ( empty_payment_paths. iter ( ) . map ( |( path, _) | path) ) ) ;
1157+
1158+ match Invoice :: try_from ( tlv_stream. to_bytes ( ) ) {
1159+ Ok ( _) => panic ! ( "expected error" ) ,
1160+ Err ( e) => assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: MissingPaths ) ) ,
1161+ }
1162+
1163+ let mut payment_paths = payment_paths ( ) ;
1164+ payment_paths. pop ( ) ;
1165+ let mut tlv_stream = invoice. as_tlv_stream ( ) ;
1166+ tlv_stream. 3 . blindedpay = Some ( Iterable ( payment_paths. iter ( ) . map ( |( _, payinfo) | payinfo) ) ) ;
1167+
1168+ match Invoice :: try_from ( tlv_stream. to_bytes ( ) ) {
1169+ Ok ( _) => panic ! ( "expected error" ) ,
1170+ Err ( e) => assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: InvalidPayInfo ) ) ,
1171+ }
1172+ }
1173+
1174+ #[ test]
1175+ fn parses_invoice_with_created_at ( ) {
1176+ let invoice = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1177+ . amount_msats ( 1000 )
1178+ . build ( ) . unwrap ( )
1179+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1180+ . build ( ) . unwrap ( )
1181+ . sign ( payer_sign) . unwrap ( )
1182+ . respond_with ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
1183+ . build ( ) . unwrap ( )
1184+ . sign ( recipient_sign) . unwrap ( ) ;
1185+
1186+ let mut buffer = Vec :: new ( ) ;
1187+ invoice. write ( & mut buffer) . unwrap ( ) ;
1188+
1189+ if let Err ( e) = Invoice :: try_from ( buffer) {
1190+ panic ! ( "error parsing invoice: {:?}" , e) ;
1191+ }
1192+
1193+ let mut tlv_stream = invoice. as_tlv_stream ( ) ;
1194+ tlv_stream. 3 . created_at = None ;
1195+
1196+ match Invoice :: try_from ( tlv_stream. to_bytes ( ) ) {
1197+ Ok ( _) => panic ! ( "expected error" ) ,
1198+ Err ( e) => {
1199+ assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: MissingCreationTime ) ) ;
1200+ } ,
1201+ }
1202+ }
1203+
1204+ #[ test]
1205+ fn parses_invoice_with_payment_hash ( ) {
1206+ let invoice = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1207+ . amount_msats ( 1000 )
1208+ . build ( ) . unwrap ( )
1209+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1210+ . build ( ) . unwrap ( )
1211+ . sign ( payer_sign) . unwrap ( )
1212+ . respond_with ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
1213+ . build ( ) . unwrap ( )
1214+ . sign ( recipient_sign) . unwrap ( ) ;
1215+
1216+ let mut buffer = Vec :: new ( ) ;
1217+ invoice. write ( & mut buffer) . unwrap ( ) ;
1218+
1219+ if let Err ( e) = Invoice :: try_from ( buffer) {
1220+ panic ! ( "error parsing invoice: {:?}" , e) ;
1221+ }
1222+
1223+ let mut tlv_stream = invoice. as_tlv_stream ( ) ;
1224+ tlv_stream. 3 . payment_hash = None ;
1225+
1226+ match Invoice :: try_from ( tlv_stream. to_bytes ( ) ) {
1227+ Ok ( _) => panic ! ( "expected error" ) ,
1228+ Err ( e) => {
1229+ assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: MissingPaymentHash ) ) ;
1230+ } ,
1231+ }
1232+ }
1233+
1234+ #[ test]
1235+ fn parses_invoice_with_amount ( ) {
1236+ let invoice = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1237+ . amount_msats ( 1000 )
1238+ . build ( ) . unwrap ( )
1239+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1240+ . build ( ) . unwrap ( )
1241+ . sign ( payer_sign) . unwrap ( )
1242+ . respond_with ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
1243+ . build ( ) . unwrap ( )
1244+ . sign ( recipient_sign) . unwrap ( ) ;
1245+
1246+ let mut buffer = Vec :: new ( ) ;
1247+ invoice. write ( & mut buffer) . unwrap ( ) ;
1248+
1249+ if let Err ( e) = Invoice :: try_from ( buffer) {
1250+ panic ! ( "error parsing invoice: {:?}" , e) ;
1251+ }
1252+
1253+ let mut tlv_stream = invoice. as_tlv_stream ( ) ;
1254+ tlv_stream. 3 . amount = None ;
1255+
1256+ match Invoice :: try_from ( tlv_stream. to_bytes ( ) ) {
1257+ Ok ( _) => panic ! ( "expected error" ) ,
1258+ Err ( e) => assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: MissingAmount ) ) ,
1259+ }
1260+ }
1261+
1262+ #[ test]
1263+ fn parses_invoice_with_node_id ( ) {
1264+ let invoice = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1265+ . amount_msats ( 1000 )
1266+ . build ( ) . unwrap ( )
1267+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1268+ . build ( ) . unwrap ( )
1269+ . sign ( payer_sign) . unwrap ( )
1270+ . respond_with ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
1271+ . build ( ) . unwrap ( )
1272+ . sign ( recipient_sign) . unwrap ( ) ;
1273+
1274+ let mut buffer = Vec :: new ( ) ;
1275+ invoice. write ( & mut buffer) . unwrap ( ) ;
1276+
1277+ if let Err ( e) = Invoice :: try_from ( buffer) {
1278+ panic ! ( "error parsing invoice: {:?}" , e) ;
1279+ }
1280+
1281+ let mut tlv_stream = invoice. as_tlv_stream ( ) ;
1282+ tlv_stream. 3 . node_id = None ;
1283+
1284+ match Invoice :: try_from ( tlv_stream. to_bytes ( ) ) {
1285+ Ok ( _) => panic ! ( "expected error" ) ,
1286+ Err ( e) => {
1287+ assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: MissingSigningPubkey ) ) ;
1288+ } ,
1289+ }
1290+ }
1291+
1292+ #[ test]
1293+ fn fails_parsing_invoice_without_signature ( ) {
1294+ let mut buffer = Vec :: new ( ) ;
1295+ OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1296+ . amount_msats ( 1000 )
1297+ . build ( ) . unwrap ( )
1298+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1299+ . build ( ) . unwrap ( )
1300+ . sign ( payer_sign) . unwrap ( )
1301+ . respond_with ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
1302+ . build ( ) . unwrap ( )
1303+ . invoice
1304+ . write ( & mut buffer) . unwrap ( ) ;
1305+
1306+ match Invoice :: try_from ( buffer) {
1307+ Ok ( _) => panic ! ( "expected error" ) ,
1308+ Err ( e) => assert_eq ! ( e, ParseError :: InvalidSemantics ( SemanticError :: MissingSignature ) ) ,
1309+ }
1310+ }
1311+
1312+ #[ test]
1313+ fn fails_parsing_invoice_with_invalid_signature ( ) {
1314+ let mut invoice = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1315+ . amount_msats ( 1000 )
1316+ . build ( ) . unwrap ( )
1317+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1318+ . build ( ) . unwrap ( )
1319+ . sign ( payer_sign) . unwrap ( )
1320+ . respond_with ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
1321+ . build ( ) . unwrap ( )
1322+ . sign ( recipient_sign) . unwrap ( ) ;
1323+ let last_signature_byte = invoice. bytes . last_mut ( ) . unwrap ( ) ;
1324+ * last_signature_byte = last_signature_byte. wrapping_add ( 1 ) ;
1325+
1326+ let mut buffer = Vec :: new ( ) ;
1327+ invoice. write ( & mut buffer) . unwrap ( ) ;
1328+
1329+ match Invoice :: try_from ( buffer) {
1330+ Ok ( _) => panic ! ( "expected error" ) ,
1331+ Err ( e) => {
1332+ assert_eq ! ( e, ParseError :: InvalidSignature ( secp256k1:: Error :: InvalidSignature ) ) ;
1333+ } ,
1334+ }
1335+ }
1336+
1337+ #[ test]
1338+ fn fails_parsing_invoice_with_extra_tlv_records ( ) {
1339+ let invoice = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1340+ . amount_msats ( 1000 )
1341+ . build ( ) . unwrap ( )
1342+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1343+ . build ( ) . unwrap ( )
1344+ . sign ( payer_sign) . unwrap ( )
1345+ . respond_with ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
1346+ . build ( ) . unwrap ( )
1347+ . sign ( recipient_sign) . unwrap ( ) ;
1348+
1349+ let mut encoded_invoice = Vec :: new ( ) ;
1350+ invoice. write ( & mut encoded_invoice) . unwrap ( ) ;
1351+ BigSize ( 1002 ) . write ( & mut encoded_invoice) . unwrap ( ) ;
1352+ BigSize ( 32 ) . write ( & mut encoded_invoice) . unwrap ( ) ;
1353+ [ 42u8 ; 32 ] . write ( & mut encoded_invoice) . unwrap ( ) ;
1354+
1355+ match Invoice :: try_from ( encoded_invoice) {
1356+ Ok ( _) => panic ! ( "expected error" ) ,
1357+ Err ( e) => assert_eq ! ( e, ParseError :: Decode ( DecodeError :: InvalidValue ) ) ,
1358+ }
1359+ }
10951360}
0 commit comments