2 extern crate bitcoin_hashes;
3 extern crate lightning;
4 extern crate lightning_invoice;
5 extern crate secp256k1;
8 use bitcoin_hashes::hex::FromHex;
9 use bitcoin_hashes::{sha256, Hash};
11 use lightning::ln::PaymentSecret;
12 use lightning::routing::gossip::RoutingFees;
13 use lightning::routing::router::{RouteHint, RouteHintHop};
14 use lightning_invoice::*;
15 use secp256k1::PublicKey;
16 use secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
17 use std::collections::HashSet;
18 use std::time::Duration;
19 use std::str::FromStr;
21 fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
24 "lnbc1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq9qrsgq357wnc5r2ueh7ck6q93dj32dlqnls087fxdwk8qakdyafkq3yap9us6v52vjjsrvywa6rt52cm9r9zqt8r2t7mlcwspyetp5h2tztugp9lfyql".to_owned(),
25 InvoiceBuilder::new(Currency::Bitcoin)
26 .duration_since_epoch(Duration::from_secs(1496314658))
27 .payment_secret(PaymentSecret([0x11; 32]))
28 .payment_hash(sha256::Hash::from_hex(
29 "0001020304050607080900010203040506070809000102030405060708090102"
31 .description("Please consider supporting this project".to_owned())
35 RecoverableSignature::from_compact(
36 &hex::decode("8d3ce9e28357337f62da0162d9454df827f83cfe499aeb1c1db349d4d81127425e434ca29929406c23bba1ae8ac6ca32880b38d4bf6ff874024cac34ba9625f1").unwrap(),
37 RecoveryId::from_i32(1).unwrap()
40 false, // Same features as set in InvoiceBuilder
41 false, // No unknown fields
44 "lnbc2500u1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu9qrsgquk0rl77nj30yxdy8j9vdx85fkpmdla2087ne0xh8nhedh8w27kyke0lp53ut353s06fv3qfegext0eh0ymjpf39tuven09sam30g4vgpfna3rh".to_owned(),
45 InvoiceBuilder::new(Currency::Bitcoin)
46 .amount_milli_satoshis(250_000_000)
47 .duration_since_epoch(Duration::from_secs(1496314658))
48 .payment_secret(PaymentSecret([0x11; 32]))
49 .payment_hash(sha256::Hash::from_hex(
50 "0001020304050607080900010203040506070809000102030405060708090102"
52 .description("1 cup coffee".to_owned())
53 .expiry_time(Duration::from_secs(60))
57 RecoverableSignature::from_compact(
58 &hex::decode("e59e3ffbd3945e4334879158d31e89b076dff54f3fa7979ae79df2db9dcaf5896cbfe1a478b8d2307e92c88139464cb7e6ef26e414c4abe33337961ddc5e8ab1").unwrap(),
59 RecoveryId::from_i32(1).unwrap()
62 false, // Same features as set in InvoiceBuilder
63 false, // No unknown fields
66 "lnbc2500u1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpu9qrsgqhtjpauu9ur7fw2thcl4y9vfvh4m9wlfyz2gem29g5ghe2aak2pm3ps8fdhtceqsaagty2vph7utlgj48u0ged6a337aewvraedendscp573dxr".to_owned(),
67 InvoiceBuilder::new(Currency::Bitcoin)
68 .amount_milli_satoshis(250_000_000)
69 .duration_since_epoch(Duration::from_secs(1496314658))
70 .payment_secret(PaymentSecret([0x11; 32]))
71 .payment_hash(sha256::Hash::from_hex(
72 "0001020304050607080900010203040506070809000102030405060708090102"
74 .description("ナンセンス 1杯".to_owned())
75 .expiry_time(Duration::from_secs(60))
79 RecoverableSignature::from_compact(
80 &hex::decode("bae41ef385e0fc972977c7ea42b12cbd76577d2412919da8a8a22f9577b6507710c0e96dd78c821dea16453037f717f44aa7e3d196ebb18fbb97307dcb7336c3").unwrap(),
81 RecoveryId::from_i32(1).unwrap()
84 false, // Same features as set in InvoiceBuilder
85 false, // No unknown fields
88 "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qrsgq7ea976txfraylvgzuxs8kgcw23ezlrszfnh8r6qtfpr6cxga50aj6txm9rxrydzd06dfeawfk6swupvz4erwnyutnjq7x39ymw6j38gp7ynn44".to_owned(),
89 InvoiceBuilder::new(Currency::Bitcoin)
90 .amount_milli_satoshis(2_000_000_000)
91 .duration_since_epoch(Duration::from_secs(1496314658))
92 .description_hash(sha256::Hash::hash(b"One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
93 .payment_secret(PaymentSecret([0x11; 32]))
94 .payment_hash(sha256::Hash::from_hex(
95 "0001020304050607080900010203040506070809000102030405060708090102"
100 RecoverableSignature::from_compact(
101 &hex::decode("f67a5f696648fa4fb102e1a07b230e54722f8e024cee71e80b4847ac191da3fb2d2cdb28cc32344d7e9a9cf5c9b6a0ee0582ae46e9938b9c81e344a4dbb5289d").unwrap(),
102 RecoveryId::from_i32(1).unwrap()
105 false, // Same features as set in InvoiceBuilder
106 false, // No unknown fields
109 "lntb20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfpp3x9et2e20v6pu37c5d9vax37wxq72un989qrsgqdj545axuxtnfemtpwkc45hx9d2ft7x04mt8q7y6t0k2dge9e7h8kpy9p34ytyslj3yu569aalz2xdk8xkd7ltxqld94u8h2esmsmacgpghe9k8".to_owned(),
110 InvoiceBuilder::new(Currency::BitcoinTestnet)
111 .amount_milli_satoshis(2_000_000_000)
112 .duration_since_epoch(Duration::from_secs(1496314658))
113 .description_hash(sha256::Hash::hash(b"One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
114 .payment_secret(PaymentSecret([0x11; 32]))
115 .payment_hash(sha256::Hash::from_hex(
116 "0001020304050607080900010203040506070809000102030405060708090102"
118 .fallback(Fallback::PubKeyHash([49, 114, 181, 101, 79, 102, 131, 200, 251, 20, 105, 89, 211, 71, 206, 48, 60, 174, 76, 167]))
122 RecoverableSignature::from_compact(
123 &hex::decode("6ca95a74dc32e69ced6175b15a5cc56a92bf19f5dace0f134b7d94d464b9f5cf6090a18d48b243f289394d17bdf89466d8e6b37df5981f696bc3dd5986e1bee1").unwrap(),
124 RecoveryId::from_i32(1).unwrap()
127 false, // Same features as set in InvoiceBuilder
128 false, // No unknown fields
131 "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzq9qrsgqdfjcdk6w3ak5pca9hwfwfh63zrrz06wwfya0ydlzpgzxkn5xagsqz7x9j4jwe7yj7vaf2k9lqsdk45kts2fd0fkr28am0u4w95tt2nsq76cqw0".to_owned(),
132 InvoiceBuilder::new(Currency::Bitcoin)
133 .amount_milli_satoshis(2_000_000_000)
134 .duration_since_epoch(Duration::from_secs(1496314658))
135 .description_hash(sha256::Hash::hash(b"One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
136 .payment_secret(PaymentSecret([0x11; 32]))
137 .payment_hash(sha256::Hash::from_hex(
138 "0001020304050607080900010203040506070809000102030405060708090102"
140 .fallback(Fallback::PubKeyHash([4, 182, 31, 125, 193, 234, 13, 201, 148, 36, 70, 76, 196, 6, 77, 197, 100, 217, 30, 137]))
141 .private_route(RouteHint(vec![RouteHintHop {
142 src_node_id: PublicKey::from_slice(&hex::decode(
143 "029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"
144 ).unwrap()).unwrap(),
145 short_channel_id: (66051 << 40) | (263430 << 16) | 1800,
146 fees: RoutingFees { base_msat: 1, proportional_millionths: 20 },
147 cltv_expiry_delta: 3,
148 htlc_maximum_msat: None, htlc_minimum_msat: None,
150 src_node_id: PublicKey::from_slice(&hex::decode(
151 "039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"
152 ).unwrap()).unwrap(),
153 short_channel_id: (197637 << 40) | (395016 << 16) | 2314,
154 fees: RoutingFees { base_msat: 2, proportional_millionths: 30 },
155 cltv_expiry_delta: 4,
156 htlc_maximum_msat: None, htlc_minimum_msat: None,
161 RecoverableSignature::from_compact(
162 &hex::decode("6a6586db4e8f6d40e3a5bb92e4df5110c627e9ce493af237e20a046b4e86ea200178c59564ecf892f33a9558bf041b6ad2cb8292d7a6c351fbb7f2ae2d16b54e").unwrap(),
163 RecoveryId::from_i32(0).unwrap()
166 false, // Same features as set in InvoiceBuilder
167 false, // No unknown fields
170 "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfppj3a24vwu6r8ejrss3axul8rxldph2q7z99qrsgqz6qsgww34xlatfj6e3sngrwfy3ytkt29d2qttr8qz2mnedfqysuqypgqex4haa2h8fx3wnypranf3pdwyluftwe680jjcfp438u82xqphf75ym".to_owned(),
171 InvoiceBuilder::new(Currency::Bitcoin)
172 .amount_milli_satoshis(2_000_000_000)
173 .duration_since_epoch(Duration::from_secs(1496314658))
174 .description_hash(sha256::Hash::hash(b"One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
175 .payment_secret(PaymentSecret([0x11; 32]))
176 .payment_hash(sha256::Hash::from_hex(
177 "0001020304050607080900010203040506070809000102030405060708090102"
179 .fallback(Fallback::ScriptHash([143, 85, 86, 59, 154, 25, 243, 33, 194, 17, 233, 185, 243, 140, 223, 104, 110, 160, 120, 69]))
183 RecoverableSignature::from_compact(
184 &hex::decode("16810439d1a9bfd5a65acc61340dc92448bb2d456a80b58ce012b73cb5202438020500c9ab7ef5573a4d174c811f669885ae27f895bb3a3be52c243589f87518").unwrap(),
185 RecoveryId::from_i32(1).unwrap()
188 false, // Same features as set in InvoiceBuilder
189 false, // No unknown fields
192 "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfppqw508d6qejxtdg4y5r3zarvary0c5xw7k9qrsgqt29a0wturnys2hhxpner2e3plp6jyj8qx7548zr2z7ptgjjc7hljm98xhjym0dg52sdrvqamxdezkmqg4gdrvwwnf0kv2jdfnl4xatsqmrnsse".to_owned(),
193 InvoiceBuilder::new(Currency::Bitcoin)
194 .amount_milli_satoshis(2_000_000_000)
195 .duration_since_epoch(Duration::from_secs(1496314658))
196 .description_hash(sha256::Hash::hash(b"One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
197 .payment_secret(PaymentSecret([0x11; 32]))
198 .payment_hash(sha256::Hash::from_hex(
199 "0001020304050607080900010203040506070809000102030405060708090102"
201 .fallback(Fallback::SegWitProgram { version: u5::try_from_u8(0).unwrap(),
202 program: vec![117, 30, 118, 232, 25, 145, 150, 212, 84, 148, 28, 69, 209, 179, 163, 35, 241, 67, 59, 214]
207 RecoverableSignature::from_compact(
208 &hex::decode("5a8bd7b97c1cc9055ee60cf2356621f8752248e037a953886a1782b44a58f5ff2d94e6bc89b7b514541a3603bb33722b6c08aa1a3639d34becc549a99fea6eae").unwrap(),
209 RecoveryId::from_i32(0).unwrap()
212 false, // Same features as set in InvoiceBuilder
213 false, // No unknown fields
216 "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfp4qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q9qrsgq9vlvyj8cqvq6ggvpwd53jncp9nwc47xlrsnenq2zp70fq83qlgesn4u3uyf4tesfkkwwfg3qs54qe426hp3tz7z6sweqdjg05axsrjqp9yrrwc".to_owned(),
217 InvoiceBuilder::new(Currency::Bitcoin)
218 .amount_milli_satoshis(2_000_000_000)
219 .duration_since_epoch(Duration::from_secs(1496314658))
220 .description_hash(sha256::Hash::hash(b"One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
221 .payment_secret(PaymentSecret([0x11; 32]))
222 .payment_hash(sha256::Hash::from_hex(
223 "0001020304050607080900010203040506070809000102030405060708090102"
225 .fallback(Fallback::SegWitProgram { version: u5::try_from_u8(0).unwrap(),
226 program: vec![24, 99, 20, 60, 20, 197, 22, 104, 4, 189, 25, 32, 51, 86, 218, 19, 108, 152, 86, 120, 205, 77, 39, 161, 184, 198, 50, 150, 4, 144, 50, 98]
231 RecoverableSignature::from_compact(
232 &hex::decode("2b3ec248f80301a421817369194f012cdd8af8df1c279981420f9e901e20fa3309d791e11355e609b59ce4a220852a0cd55ab862b1785a83b206c90fa74d01c8").unwrap(),
233 RecoveryId::from_i32(1).unwrap()
236 false, // Same features as set in InvoiceBuilder
237 false, // No unknown fields
240 "lnbc9678785340p1pwmna7lpp5gc3xfm08u9qy06djf8dfflhugl6p7lgza6dsjxq454gxhj9t7a0sd8dgfkx7cmtwd68yetpd5s9xar0wfjn5gpc8qhrsdfq24f5ggrxdaezqsnvda3kkum5wfjkzmfqf3jkgem9wgsyuctwdus9xgrcyqcjcgpzgfskx6eqf9hzqnteypzxz7fzypfhg6trddjhygrcyqezcgpzfysywmm5ypxxjemgw3hxjmn8yptk7untd9hxwg3q2d6xjcmtv4ezq7pqxgsxzmnyyqcjqmt0wfjjq6t5v4khxsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsxqyjw5qcqp2rzjq0gxwkzc8w6323m55m4jyxcjwmy7stt9hwkwe2qxmy8zpsgg7jcuwz87fcqqeuqqqyqqqqlgqqqqn3qq9q9qrsgqrvgkpnmps664wgkp43l22qsgdw4ve24aca4nymnxddlnp8vh9v2sdxlu5ywdxefsfvm0fq3sesf08uf6q9a2ke0hc9j6z6wlxg5z5kqpu2v9wz".to_owned(),
241 InvoiceBuilder::new(Currency::Bitcoin)
242 .amount_milli_satoshis(967878534)
243 .duration_since_epoch(Duration::from_secs(1572468703))
244 .payment_secret(PaymentSecret([0x11; 32]))
245 .payment_hash(sha256::Hash::from_hex(
246 "462264ede7e14047e9b249da94fefc47f41f7d02ee9b091815a5506bc8abf75f"
248 .expiry_time(Duration::from_secs(604800))
249 .min_final_cltv_expiry(10)
250 .description("Blockstream Store: 88.85 USD for Blockstream Ledger Nano S x 1, \"Back In My Day\" Sticker x 2, \"I Got Lightning Working\" Sticker x 2 and 1 more items".to_owned())
251 .private_route(RouteHint(vec![RouteHintHop {
252 src_node_id: PublicKey::from_slice(&hex::decode(
253 "03d06758583bb5154774a6eb221b1276c9e82d65bbaceca806d90e20c108f4b1c7"
254 ).unwrap()).unwrap(),
255 short_channel_id: (589390 << 40) | (3312 << 16) | 1,
256 fees: RoutingFees { base_msat: 1000, proportional_millionths: 2500 },
257 cltv_expiry_delta: 40,
258 htlc_maximum_msat: None, htlc_minimum_msat: None,
263 RecoverableSignature::from_compact(
264 &hex::decode("1b1160cf6186b55722c1ac7ea502086baaccaabdc76b326e666b7f309d972b15069bfca11cd365304b36f48230cc12f3f13a017aab65f7c165a169df32282a58").unwrap(),
265 RecoveryId::from_i32(1).unwrap()
268 false, // Same features as set in InvoiceBuilder
269 false, // No unknown fields
272 "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqqsgq2a25dxl5hrntdtn6zvydt7d66hyzsyhqs4wdynavys42xgl6sgx9c4g7me86a27t07mdtfry458rtjr0v92cnmswpsjscgt2vcse3sgpz3uapa".to_owned(),
273 InvoiceBuilder::new(Currency::Bitcoin)
274 .amount_milli_satoshis(2_500_000_000)
275 .duration_since_epoch(Duration::from_secs(1496314658))
276 .payment_secret(PaymentSecret([0x11; 32]))
277 .payment_hash(sha256::Hash::from_hex(
278 "0001020304050607080900010203040506070809000102030405060708090102"
280 .description("coffee beans".to_owned())
284 RecoverableSignature::from_compact(
285 &hex::decode("5755469bf4b8e6b6ae7a1308d5f9bad5c82812e0855cd24fac242aa323fa820c5c551ede4faeabcb7fb6d5a464ad0e35c86f615589ee0e0c250c216a662198c1").unwrap(),
286 RecoveryId::from_i32(1).unwrap()
289 true, // Different features than set in InvoiceBuilder
290 false, // No unknown fields
293 "LNBC25M1PVJLUEZPP5QQQSYQCYQ5RQWZQFQQQSYQCYQ5RQWZQFQQQSYQCYQ5RQWZQFQYPQDQ5VDHKVEN9V5SXYETPDEESSP5ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYGS9Q5SQQQQQQQQQQQQQQQQSGQ2A25DXL5HRNTDTN6ZVYDT7D66HYZSYHQS4WDYNAVYS42XGL6SGX9C4G7ME86A27T07MDTFRY458RTJR0V92CNMSWPSJSCGT2VCSE3SGPZ3UAPA".to_owned(),
294 InvoiceBuilder::new(Currency::Bitcoin)
295 .amount_milli_satoshis(2_500_000_000)
296 .duration_since_epoch(Duration::from_secs(1496314658))
297 .payment_secret(PaymentSecret([0x11; 32]))
298 .payment_hash(sha256::Hash::from_hex(
299 "0001020304050607080900010203040506070809000102030405060708090102"
301 .description("coffee beans".to_owned())
305 RecoverableSignature::from_compact(
306 &hex::decode("5755469bf4b8e6b6ae7a1308d5f9bad5c82812e0855cd24fac242aa323fa820c5c551ede4faeabcb7fb6d5a464ad0e35c86f615589ee0e0c250c216a662198c1").unwrap(),
307 RecoveryId::from_i32(1).unwrap()
310 true, // Different features than set in InvoiceBuilder
311 false, // No unknown fields
314 "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqqsgq2qrqqqfppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhpnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqspnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnp5qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnpkqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqz599y53s3ujmcfjp5xrdap68qxymkqphwsexhmhr8wdz5usdzkzrse33chw6dlp3jhuhge9ley7j2ayx36kawe7kmgg8sv5ugdyusdcqzn8z9x".to_owned(),
315 InvoiceBuilder::new(Currency::Bitcoin)
316 .amount_milli_satoshis(2_500_000_000)
317 .duration_since_epoch(Duration::from_secs(1496314658))
318 .payment_secret(PaymentSecret([0x11; 32]))
319 .payment_hash(sha256::Hash::from_hex(
320 "0001020304050607080900010203040506070809000102030405060708090102"
322 .description("coffee beans".to_owned())
326 RecoverableSignature::from_compact(
327 &hex::decode("150a5252308f25bc2641a186de87470189bb003774326beee33b9a2a720d1584386631c5dda6fc3195f97464bfc93d2574868eadd767d6da1078329c4349c837").unwrap(),
328 RecoveryId::from_i32(0).unwrap()
331 true, // Different features than set in InvoiceBuilder
332 true, // Some unknown fields
338 fn invoice_deserialize() {
339 for (serialized, deserialized, ignore_feature_diff, ignore_unknown_fields) in get_test_tuples() {
340 eprintln!("Testing invoice {}...", serialized);
341 let parsed = serialized.parse::<SignedRawInvoice>().unwrap();
343 let (parsed_invoice, _, parsed_sig) = parsed.into_parts();
344 let (deserialized_invoice, _, deserialized_sig) = deserialized.into_parts();
346 assert_eq!(deserialized_sig, parsed_sig);
347 assert_eq!(deserialized_invoice.hrp, parsed_invoice.hrp);
348 assert_eq!(deserialized_invoice.data.timestamp, parsed_invoice.data.timestamp);
350 let mut deserialized_hunks: HashSet<_> = deserialized_invoice.data.tagged_fields.iter().collect();
351 let mut parsed_hunks: HashSet<_> = parsed_invoice.data.tagged_fields.iter().collect();
352 if ignore_feature_diff {
353 deserialized_hunks.retain(|h|
354 if let RawTaggedField::KnownSemantics(TaggedField::Features(_)) = h { false } else { true });
355 parsed_hunks.retain(|h|
356 if let RawTaggedField::KnownSemantics(TaggedField::Features(_)) = h { false } else { true });
358 if ignore_unknown_fields {
359 parsed_hunks.retain(|h|
360 if let RawTaggedField::UnknownSemantics(_) = h { false } else { true });
362 assert_eq!(deserialized_hunks, parsed_hunks);
364 Invoice::from_signed(serialized.parse::<SignedRawInvoice>().unwrap()).unwrap();
369 fn test_bolt_invalid_invoices() {
370 // Tests the BOLT 11 invalid invoice test vectors
371 assert_eq!(Invoice::from_str(
372 "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqqsgqtqyx5vggfcsll4wu246hz02kp85x4katwsk9639we5n5yngc3yhqkm35jnjw4len8vrnqnf5ejh0mzj9n3vz2px97evektfm2l6wqccp3y7372"
373 ), Err(ParseOrSemanticError::SemanticError(SemanticError::InvalidFeatures)));
374 assert_eq!(Invoice::from_str(
375 "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrnt"
376 ), Err(ParseOrSemanticError::ParseError(ParseError::Bech32Error(bech32::Error::InvalidChecksum))));
377 assert_eq!(Invoice::from_str(
378 "pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny"
379 ), Err(ParseOrSemanticError::ParseError(ParseError::Bech32Error(bech32::Error::MissingSeparator))));
380 assert_eq!(Invoice::from_str(
381 "LNBC2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny"
382 ), Err(ParseOrSemanticError::ParseError(ParseError::Bech32Error(bech32::Error::MixedCase))));
383 assert_eq!(Invoice::from_str(
384 "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqwgt7mcn5yqw3yx0w94pswkpq6j9uh6xfqqqtsk4tnarugeektd4hg5975x9am52rz4qskukxdmjemg92vvqz8nvmsye63r5ykel43pgz7zq0g2"
385 ), Err(ParseOrSemanticError::SemanticError(SemanticError::InvalidSignature)));
386 assert_eq!(Invoice::from_str(
387 "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6na6hlh"
388 ), Err(ParseOrSemanticError::ParseError(ParseError::TooShortDataPart)));
389 assert_eq!(Invoice::from_str(
390 "lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqrrzc4cvfue4zp3hggxp47ag7xnrlr8vgcmkjxk3j5jqethnumgkpqp23z9jclu3v0a7e0aruz366e9wqdykw6dxhdzcjjhldxq0w6wgqcnu43j"
391 ), Err(ParseOrSemanticError::ParseError(ParseError::UnknownSiPrefix)));
392 assert_eq!(Invoice::from_str(
393 "lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgq0lzc236j96a95uv0m3umg28gclm5lqxtqqwk32uuk4k6673k6n5kfvx3d2h8s295fad45fdhmusm8sjudfhlf6dcsxmfvkeywmjdkxcp99202x"
394 ), Err(ParseOrSemanticError::SemanticError(SemanticError::ImpreciseAmount)));