2 extern crate bitcoin_hashes;
3 extern crate lightning;
4 extern crate lightning_invoice;
5 extern crate secp256k1;
8 use bitcoin::util::address::WitnessVersion;
9 use bitcoin::{PubkeyHash, ScriptHash};
10 use bitcoin_hashes::hex::FromHex;
11 use bitcoin_hashes::{sha256, Hash};
12 use lightning::ln::PaymentSecret;
13 use lightning::routing::gossip::RoutingFees;
14 use lightning::routing::router::{RouteHint, RouteHintHop};
15 use lightning_invoice::*;
16 use secp256k1::PublicKey;
17 use secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
18 use std::collections::HashSet;
19 use std::time::Duration;
20 use std::str::FromStr;
22 fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
25 "lnbc1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq9qrsgq357wnc5r2ueh7ck6q93dj32dlqnls087fxdwk8qakdyafkq3yap9us6v52vjjsrvywa6rt52cm9r9zqt8r2t7mlcwspyetp5h2tztugp9lfyql".to_owned(),
26 InvoiceBuilder::new(Currency::Bitcoin)
27 .duration_since_epoch(Duration::from_secs(1496314658))
28 .payment_secret(PaymentSecret([0x11; 32]))
29 .payment_hash(sha256::Hash::from_hex(
30 "0001020304050607080900010203040506070809000102030405060708090102"
32 .description("Please consider supporting this project".to_owned())
36 RecoverableSignature::from_compact(
37 &hex::decode("8d3ce9e28357337f62da0162d9454df827f83cfe499aeb1c1db349d4d81127425e434ca29929406c23bba1ae8ac6ca32880b38d4bf6ff874024cac34ba9625f1").unwrap(),
38 RecoveryId::from_i32(1).unwrap()
41 false, // Same features as set in InvoiceBuilder
42 false, // No unknown fields
45 "lnbc2500u1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu9qrsgquk0rl77nj30yxdy8j9vdx85fkpmdla2087ne0xh8nhedh8w27kyke0lp53ut353s06fv3qfegext0eh0ymjpf39tuven09sam30g4vgpfna3rh".to_owned(),
46 InvoiceBuilder::new(Currency::Bitcoin)
47 .amount_milli_satoshis(250_000_000)
48 .duration_since_epoch(Duration::from_secs(1496314658))
49 .payment_secret(PaymentSecret([0x11; 32]))
50 .payment_hash(sha256::Hash::from_hex(
51 "0001020304050607080900010203040506070809000102030405060708090102"
53 .description("1 cup coffee".to_owned())
54 .expiry_time(Duration::from_secs(60))
58 RecoverableSignature::from_compact(
59 &hex::decode("e59e3ffbd3945e4334879158d31e89b076dff54f3fa7979ae79df2db9dcaf5896cbfe1a478b8d2307e92c88139464cb7e6ef26e414c4abe33337961ddc5e8ab1").unwrap(),
60 RecoveryId::from_i32(1).unwrap()
63 false, // Same features as set in InvoiceBuilder
64 false, // No unknown fields
67 "lnbc2500u1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpu9qrsgqhtjpauu9ur7fw2thcl4y9vfvh4m9wlfyz2gem29g5ghe2aak2pm3ps8fdhtceqsaagty2vph7utlgj48u0ged6a337aewvraedendscp573dxr".to_owned(),
68 InvoiceBuilder::new(Currency::Bitcoin)
69 .amount_milli_satoshis(250_000_000)
70 .duration_since_epoch(Duration::from_secs(1496314658))
71 .payment_secret(PaymentSecret([0x11; 32]))
72 .payment_hash(sha256::Hash::from_hex(
73 "0001020304050607080900010203040506070809000102030405060708090102"
75 .description("ナンセンス 1杯".to_owned())
76 .expiry_time(Duration::from_secs(60))
80 RecoverableSignature::from_compact(
81 &hex::decode("bae41ef385e0fc972977c7ea42b12cbd76577d2412919da8a8a22f9577b6507710c0e96dd78c821dea16453037f717f44aa7e3d196ebb18fbb97307dcb7336c3").unwrap(),
82 RecoveryId::from_i32(1).unwrap()
85 false, // Same features as set in InvoiceBuilder
86 false, // No unknown fields
89 "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qrsgq7ea976txfraylvgzuxs8kgcw23ezlrszfnh8r6qtfpr6cxga50aj6txm9rxrydzd06dfeawfk6swupvz4erwnyutnjq7x39ymw6j38gp7ynn44".to_owned(),
90 InvoiceBuilder::new(Currency::Bitcoin)
91 .amount_milli_satoshis(2_000_000_000)
92 .duration_since_epoch(Duration::from_secs(1496314658))
93 .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"))
94 .payment_secret(PaymentSecret([0x11; 32]))
95 .payment_hash(sha256::Hash::from_hex(
96 "0001020304050607080900010203040506070809000102030405060708090102"
101 RecoverableSignature::from_compact(
102 &hex::decode("f67a5f696648fa4fb102e1a07b230e54722f8e024cee71e80b4847ac191da3fb2d2cdb28cc32344d7e9a9cf5c9b6a0ee0582ae46e9938b9c81e344a4dbb5289d").unwrap(),
103 RecoveryId::from_i32(1).unwrap()
106 false, // Same features as set in InvoiceBuilder
107 false, // No unknown fields
110 "lntb20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfpp3x9et2e20v6pu37c5d9vax37wxq72un989qrsgqdj545axuxtnfemtpwkc45hx9d2ft7x04mt8q7y6t0k2dge9e7h8kpy9p34ytyslj3yu569aalz2xdk8xkd7ltxqld94u8h2esmsmacgpghe9k8".to_owned(),
111 InvoiceBuilder::new(Currency::BitcoinTestnet)
112 .amount_milli_satoshis(2_000_000_000)
113 .duration_since_epoch(Duration::from_secs(1496314658))
114 .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"))
115 .payment_secret(PaymentSecret([0x11; 32]))
116 .payment_hash(sha256::Hash::from_hex(
117 "0001020304050607080900010203040506070809000102030405060708090102"
119 .fallback(Fallback::PubKeyHash(PubkeyHash::from_slice(&[49, 114, 181, 101, 79, 102, 131, 200, 251, 20, 105, 89, 211, 71, 206, 48, 60, 174, 76, 167]).unwrap()))
123 RecoverableSignature::from_compact(
124 &hex::decode("6ca95a74dc32e69ced6175b15a5cc56a92bf19f5dace0f134b7d94d464b9f5cf6090a18d48b243f289394d17bdf89466d8e6b37df5981f696bc3dd5986e1bee1").unwrap(),
125 RecoveryId::from_i32(1).unwrap()
128 false, // Same features as set in InvoiceBuilder
129 false, // No unknown fields
132 "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzq9qrsgqdfjcdk6w3ak5pca9hwfwfh63zrrz06wwfya0ydlzpgzxkn5xagsqz7x9j4jwe7yj7vaf2k9lqsdk45kts2fd0fkr28am0u4w95tt2nsq76cqw0".to_owned(),
133 InvoiceBuilder::new(Currency::Bitcoin)
134 .amount_milli_satoshis(2_000_000_000)
135 .duration_since_epoch(Duration::from_secs(1496314658))
136 .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"))
137 .payment_secret(PaymentSecret([0x11; 32]))
138 .payment_hash(sha256::Hash::from_hex(
139 "0001020304050607080900010203040506070809000102030405060708090102"
141 .fallback(Fallback::PubKeyHash(PubkeyHash::from_slice(&[4, 182, 31, 125, 193, 234, 13, 201, 148, 36, 70, 76, 196, 6, 77, 197, 100, 217, 30, 137]).unwrap()))
142 .private_route(RouteHint(vec![RouteHintHop {
143 src_node_id: PublicKey::from_slice(&hex::decode(
144 "029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"
145 ).unwrap()).unwrap(),
146 short_channel_id: (66051 << 40) | (263430 << 16) | 1800,
147 fees: RoutingFees { base_msat: 1, proportional_millionths: 20 },
148 cltv_expiry_delta: 3,
149 htlc_maximum_msat: None, htlc_minimum_msat: None,
151 src_node_id: PublicKey::from_slice(&hex::decode(
152 "039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"
153 ).unwrap()).unwrap(),
154 short_channel_id: (197637 << 40) | (395016 << 16) | 2314,
155 fees: RoutingFees { base_msat: 2, proportional_millionths: 30 },
156 cltv_expiry_delta: 4,
157 htlc_maximum_msat: None, htlc_minimum_msat: None,
162 RecoverableSignature::from_compact(
163 &hex::decode("6a6586db4e8f6d40e3a5bb92e4df5110c627e9ce493af237e20a046b4e86ea200178c59564ecf892f33a9558bf041b6ad2cb8292d7a6c351fbb7f2ae2d16b54e").unwrap(),
164 RecoveryId::from_i32(0).unwrap()
167 false, // Same features as set in InvoiceBuilder
168 false, // No unknown fields
171 "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfppj3a24vwu6r8ejrss3axul8rxldph2q7z99qrsgqz6qsgww34xlatfj6e3sngrwfy3ytkt29d2qttr8qz2mnedfqysuqypgqex4haa2h8fx3wnypranf3pdwyluftwe680jjcfp438u82xqphf75ym".to_owned(),
172 InvoiceBuilder::new(Currency::Bitcoin)
173 .amount_milli_satoshis(2_000_000_000)
174 .duration_since_epoch(Duration::from_secs(1496314658))
175 .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"))
176 .payment_secret(PaymentSecret([0x11; 32]))
177 .payment_hash(sha256::Hash::from_hex(
178 "0001020304050607080900010203040506070809000102030405060708090102"
180 .fallback(Fallback::ScriptHash(ScriptHash::from_slice(&[143, 85, 86, 59, 154, 25, 243, 33, 194, 17, 233, 185, 243, 140, 223, 104, 110, 160, 120, 69]).unwrap()))
184 RecoverableSignature::from_compact(
185 &hex::decode("16810439d1a9bfd5a65acc61340dc92448bb2d456a80b58ce012b73cb5202438020500c9ab7ef5573a4d174c811f669885ae27f895bb3a3be52c243589f87518").unwrap(),
186 RecoveryId::from_i32(1).unwrap()
189 false, // Same features as set in InvoiceBuilder
190 false, // No unknown fields
193 "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfppqw508d6qejxtdg4y5r3zarvary0c5xw7k9qrsgqt29a0wturnys2hhxpner2e3plp6jyj8qx7548zr2z7ptgjjc7hljm98xhjym0dg52sdrvqamxdezkmqg4gdrvwwnf0kv2jdfnl4xatsqmrnsse".to_owned(),
194 InvoiceBuilder::new(Currency::Bitcoin)
195 .amount_milli_satoshis(2_000_000_000)
196 .duration_since_epoch(Duration::from_secs(1496314658))
197 .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"))
198 .payment_secret(PaymentSecret([0x11; 32]))
199 .payment_hash(sha256::Hash::from_hex(
200 "0001020304050607080900010203040506070809000102030405060708090102"
202 .fallback(Fallback::SegWitProgram { version: WitnessVersion::V0,
203 program: vec![117, 30, 118, 232, 25, 145, 150, 212, 84, 148, 28, 69, 209, 179, 163, 35, 241, 67, 59, 214]
208 RecoverableSignature::from_compact(
209 &hex::decode("5a8bd7b97c1cc9055ee60cf2356621f8752248e037a953886a1782b44a58f5ff2d94e6bc89b7b514541a3603bb33722b6c08aa1a3639d34becc549a99fea6eae").unwrap(),
210 RecoveryId::from_i32(0).unwrap()
213 false, // Same features as set in InvoiceBuilder
214 false, // No unknown fields
217 "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfp4qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q9qrsgq9vlvyj8cqvq6ggvpwd53jncp9nwc47xlrsnenq2zp70fq83qlgesn4u3uyf4tesfkkwwfg3qs54qe426hp3tz7z6sweqdjg05axsrjqp9yrrwc".to_owned(),
218 InvoiceBuilder::new(Currency::Bitcoin)
219 .amount_milli_satoshis(2_000_000_000)
220 .duration_since_epoch(Duration::from_secs(1496314658))
221 .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"))
222 .payment_secret(PaymentSecret([0x11; 32]))
223 .payment_hash(sha256::Hash::from_hex(
224 "0001020304050607080900010203040506070809000102030405060708090102"
226 .fallback(Fallback::SegWitProgram { version: WitnessVersion::V0,
227 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]
232 RecoverableSignature::from_compact(
233 &hex::decode("2b3ec248f80301a421817369194f012cdd8af8df1c279981420f9e901e20fa3309d791e11355e609b59ce4a220852a0cd55ab862b1785a83b206c90fa74d01c8").unwrap(),
234 RecoveryId::from_i32(1).unwrap()
237 false, // Same features as set in InvoiceBuilder
238 false, // No unknown fields
241 "lnbc9678785340p1pwmna7lpp5gc3xfm08u9qy06djf8dfflhugl6p7lgza6dsjxq454gxhj9t7a0sd8dgfkx7cmtwd68yetpd5s9xar0wfjn5gpc8qhrsdfq24f5ggrxdaezqsnvda3kkum5wfjkzmfqf3jkgem9wgsyuctwdus9xgrcyqcjcgpzgfskx6eqf9hzqnteypzxz7fzypfhg6trddjhygrcyqezcgpzfysywmm5ypxxjemgw3hxjmn8yptk7untd9hxwg3q2d6xjcmtv4ezq7pqxgsxzmnyyqcjqmt0wfjjq6t5v4khxsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsxqyjw5qcqp2rzjq0gxwkzc8w6323m55m4jyxcjwmy7stt9hwkwe2qxmy8zpsgg7jcuwz87fcqqeuqqqyqqqqlgqqqqn3qq9q9qrsgqrvgkpnmps664wgkp43l22qsgdw4ve24aca4nymnxddlnp8vh9v2sdxlu5ywdxefsfvm0fq3sesf08uf6q9a2ke0hc9j6z6wlxg5z5kqpu2v9wz".to_owned(),
242 InvoiceBuilder::new(Currency::Bitcoin)
243 .amount_milli_satoshis(967878534)
244 .duration_since_epoch(Duration::from_secs(1572468703))
245 .payment_secret(PaymentSecret([0x11; 32]))
246 .payment_hash(sha256::Hash::from_hex(
247 "462264ede7e14047e9b249da94fefc47f41f7d02ee9b091815a5506bc8abf75f"
249 .expiry_time(Duration::from_secs(604800))
250 .min_final_cltv_expiry_delta(10)
251 .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())
252 .private_route(RouteHint(vec![RouteHintHop {
253 src_node_id: PublicKey::from_slice(&hex::decode(
254 "03d06758583bb5154774a6eb221b1276c9e82d65bbaceca806d90e20c108f4b1c7"
255 ).unwrap()).unwrap(),
256 short_channel_id: (589390 << 40) | (3312 << 16) | 1,
257 fees: RoutingFees { base_msat: 1000, proportional_millionths: 2500 },
258 cltv_expiry_delta: 40,
259 htlc_maximum_msat: None, htlc_minimum_msat: None,
264 RecoverableSignature::from_compact(
265 &hex::decode("1b1160cf6186b55722c1ac7ea502086baaccaabdc76b326e666b7f309d972b15069bfca11cd365304b36f48230cc12f3f13a017aab65f7c165a169df32282a58").unwrap(),
266 RecoveryId::from_i32(1).unwrap()
269 false, // Same features as set in InvoiceBuilder
270 false, // No unknown fields
273 "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqqsgq2a25dxl5hrntdtn6zvydt7d66hyzsyhqs4wdynavys42xgl6sgx9c4g7me86a27t07mdtfry458rtjr0v92cnmswpsjscgt2vcse3sgpz3uapa".to_owned(),
274 InvoiceBuilder::new(Currency::Bitcoin)
275 .amount_milli_satoshis(2_500_000_000)
276 .duration_since_epoch(Duration::from_secs(1496314658))
277 .payment_secret(PaymentSecret([0x11; 32]))
278 .payment_hash(sha256::Hash::from_hex(
279 "0001020304050607080900010203040506070809000102030405060708090102"
281 .description("coffee beans".to_owned())
285 RecoverableSignature::from_compact(
286 &hex::decode("5755469bf4b8e6b6ae7a1308d5f9bad5c82812e0855cd24fac242aa323fa820c5c551ede4faeabcb7fb6d5a464ad0e35c86f615589ee0e0c250c216a662198c1").unwrap(),
287 RecoveryId::from_i32(1).unwrap()
290 true, // Different features than set in InvoiceBuilder
291 false, // No unknown fields
294 "LNBC25M1PVJLUEZPP5QQQSYQCYQ5RQWZQFQQQSYQCYQ5RQWZQFQQQSYQCYQ5RQWZQFQYPQDQ5VDHKVEN9V5SXYETPDEESSP5ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYGS9Q5SQQQQQQQQQQQQQQQQSGQ2A25DXL5HRNTDTN6ZVYDT7D66HYZSYHQS4WDYNAVYS42XGL6SGX9C4G7ME86A27T07MDTFRY458RTJR0V92CNMSWPSJSCGT2VCSE3SGPZ3UAPA".to_owned(),
295 InvoiceBuilder::new(Currency::Bitcoin)
296 .amount_milli_satoshis(2_500_000_000)
297 .duration_since_epoch(Duration::from_secs(1496314658))
298 .payment_secret(PaymentSecret([0x11; 32]))
299 .payment_hash(sha256::Hash::from_hex(
300 "0001020304050607080900010203040506070809000102030405060708090102"
302 .description("coffee beans".to_owned())
306 RecoverableSignature::from_compact(
307 &hex::decode("5755469bf4b8e6b6ae7a1308d5f9bad5c82812e0855cd24fac242aa323fa820c5c551ede4faeabcb7fb6d5a464ad0e35c86f615589ee0e0c250c216a662198c1").unwrap(),
308 RecoveryId::from_i32(1).unwrap()
311 true, // Different features than set in InvoiceBuilder
312 false, // No unknown fields
315 "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqqsgq2qrqqqfppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhpnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqspnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnp5qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnpkqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqz599y53s3ujmcfjp5xrdap68qxymkqphwsexhmhr8wdz5usdzkzrse33chw6dlp3jhuhge9ley7j2ayx36kawe7kmgg8sv5ugdyusdcqzn8z9x".to_owned(),
316 InvoiceBuilder::new(Currency::Bitcoin)
317 .amount_milli_satoshis(2_500_000_000)
318 .duration_since_epoch(Duration::from_secs(1496314658))
319 .payment_secret(PaymentSecret([0x11; 32]))
320 .payment_hash(sha256::Hash::from_hex(
321 "0001020304050607080900010203040506070809000102030405060708090102"
323 .description("coffee beans".to_owned())
327 RecoverableSignature::from_compact(
328 &hex::decode("150a5252308f25bc2641a186de87470189bb003774326beee33b9a2a720d1584386631c5dda6fc3195f97464bfc93d2574868eadd767d6da1078329c4349c837").unwrap(),
329 RecoveryId::from_i32(0).unwrap()
332 true, // Different features than set in InvoiceBuilder
333 true, // Some unknown fields
339 fn invoice_deserialize() {
340 for (serialized, deserialized, ignore_feature_diff, ignore_unknown_fields) in get_test_tuples() {
341 eprintln!("Testing invoice {}...", serialized);
342 let parsed = serialized.parse::<SignedRawInvoice>().unwrap();
344 let (parsed_invoice, _, parsed_sig) = parsed.into_parts();
345 let (deserialized_invoice, _, deserialized_sig) = deserialized.into_parts();
347 assert_eq!(deserialized_sig, parsed_sig);
348 assert_eq!(deserialized_invoice.hrp, parsed_invoice.hrp);
349 assert_eq!(deserialized_invoice.data.timestamp, parsed_invoice.data.timestamp);
351 let mut deserialized_hunks: HashSet<_> = deserialized_invoice.data.tagged_fields.iter().collect();
352 let mut parsed_hunks: HashSet<_> = parsed_invoice.data.tagged_fields.iter().collect();
353 if ignore_feature_diff {
354 deserialized_hunks.retain(|h|
355 if let RawTaggedField::KnownSemantics(TaggedField::Features(_)) = h { false } else { true });
356 parsed_hunks.retain(|h|
357 if let RawTaggedField::KnownSemantics(TaggedField::Features(_)) = h { false } else { true });
359 if ignore_unknown_fields {
360 parsed_hunks.retain(|h|
361 if let RawTaggedField::UnknownSemantics(_) = h { false } else { true });
363 assert_eq!(deserialized_hunks, parsed_hunks);
365 Invoice::from_signed(serialized.parse::<SignedRawInvoice>().unwrap()).unwrap();
370 fn test_bolt_invalid_invoices() {
371 // Tests the BOLT 11 invalid invoice test vectors
372 assert_eq!(Invoice::from_str(
373 "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqqsgqtqyx5vggfcsll4wu246hz02kp85x4katwsk9639we5n5yngc3yhqkm35jnjw4len8vrnqnf5ejh0mzj9n3vz2px97evektfm2l6wqccp3y7372"
374 ), Err(ParseOrSemanticError::SemanticError(SemanticError::InvalidFeatures)));
375 assert_eq!(Invoice::from_str(
376 "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrnt"
377 ), Err(ParseOrSemanticError::ParseError(ParseError::Bech32Error(bech32::Error::InvalidChecksum))));
378 assert_eq!(Invoice::from_str(
379 "pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny"
380 ), Err(ParseOrSemanticError::ParseError(ParseError::Bech32Error(bech32::Error::MissingSeparator))));
381 assert_eq!(Invoice::from_str(
382 "LNBC2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny"
383 ), Err(ParseOrSemanticError::ParseError(ParseError::Bech32Error(bech32::Error::MixedCase))));
384 assert_eq!(Invoice::from_str(
385 "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqwgt7mcn5yqw3yx0w94pswkpq6j9uh6xfqqqtsk4tnarugeektd4hg5975x9am52rz4qskukxdmjemg92vvqz8nvmsye63r5ykel43pgz7zq0g2"
386 ), Err(ParseOrSemanticError::SemanticError(SemanticError::InvalidSignature)));
387 assert_eq!(Invoice::from_str(
388 "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6na6hlh"
389 ), Err(ParseOrSemanticError::ParseError(ParseError::TooShortDataPart)));
390 assert_eq!(Invoice::from_str(
391 "lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqrrzc4cvfue4zp3hggxp47ag7xnrlr8vgcmkjxk3j5jqethnumgkpqp23z9jclu3v0a7e0aruz366e9wqdykw6dxhdzcjjhldxq0w6wgqcnu43j"
392 ), Err(ParseOrSemanticError::ParseError(ParseError::UnknownSiPrefix)));
393 assert_eq!(Invoice::from_str(
394 "lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgq0lzc236j96a95uv0m3umg28gclm5lqxtqqwk32uuk4k6673k6n5kfvx3d2h8s295fad45fdhmusm8sjudfhlf6dcsxmfvkeywmjdkxcp99202x"
395 ), Err(ParseOrSemanticError::SemanticError(SemanticError::ImpreciseAmount)));