Qualify the BOLT 11 parse error type
[rust-lightning] / lightning-invoice / tests / ser_de.rs
1 extern crate bech32;
2 extern crate bitcoin_hashes;
3 extern crate lightning;
4 extern crate lightning_invoice;
5 extern crate secp256k1;
6 extern crate hex;
7
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;
21
22 fn get_test_tuples() -> Vec<(String, SignedRawBolt11Invoice, bool, bool)> {
23         vec![
24                 (
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"
31                                 ).unwrap())
32                                 .description("Please consider supporting this project".to_owned())
33                                 .build_raw()
34                                 .unwrap()
35                                 .sign(|_| {
36                                         RecoverableSignature::from_compact(
37                                                 &hex::decode("8d3ce9e28357337f62da0162d9454df827f83cfe499aeb1c1db349d4d81127425e434ca29929406c23bba1ae8ac6ca32880b38d4bf6ff874024cac34ba9625f1").unwrap(),
38                                                 RecoveryId::from_i32(1).unwrap()
39                                         )
40                                 }).unwrap(),
41                         false, // Same features as set in InvoiceBuilder
42                         false, // No unknown fields
43                 ),
44                 (
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"
52                                 ).unwrap())
53                                 .description("1 cup coffee".to_owned())
54                                 .expiry_time(Duration::from_secs(60))
55                                 .build_raw()
56                                 .unwrap()
57                                 .sign(|_| {
58                                         RecoverableSignature::from_compact(
59                                                 &hex::decode("e59e3ffbd3945e4334879158d31e89b076dff54f3fa7979ae79df2db9dcaf5896cbfe1a478b8d2307e92c88139464cb7e6ef26e414c4abe33337961ddc5e8ab1").unwrap(),
60                                                 RecoveryId::from_i32(1).unwrap()
61                                         )
62                                 }).unwrap(),
63                         false, // Same features as set in InvoiceBuilder
64                         false, // No unknown fields
65                 ),
66                 (
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"
74                                 ).unwrap())
75                                 .description("ナンセンス 1杯".to_owned())
76                                 .expiry_time(Duration::from_secs(60))
77                                 .build_raw()
78                                 .unwrap()
79                                 .sign(|_| {
80                                         RecoverableSignature::from_compact(
81                                                 &hex::decode("bae41ef385e0fc972977c7ea42b12cbd76577d2412919da8a8a22f9577b6507710c0e96dd78c821dea16453037f717f44aa7e3d196ebb18fbb97307dcb7336c3").unwrap(),
82                                                 RecoveryId::from_i32(1).unwrap()
83                                         )
84                                 }).unwrap(),
85                         false, // Same features as set in InvoiceBuilder
86                         false, // No unknown fields
87                 ),
88                 (
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"
97                                 ).unwrap())
98                                 .build_raw()
99                                 .unwrap()
100                                 .sign(|_| {
101                                         RecoverableSignature::from_compact(
102                                                 &hex::decode("f67a5f696648fa4fb102e1a07b230e54722f8e024cee71e80b4847ac191da3fb2d2cdb28cc32344d7e9a9cf5c9b6a0ee0582ae46e9938b9c81e344a4dbb5289d").unwrap(),
103                                                 RecoveryId::from_i32(1).unwrap()
104                                         )
105                                 }).unwrap(),
106                         false, // Same features as set in InvoiceBuilder
107                         false, // No unknown fields
108                 ),
109                 (
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"
118                                 ).unwrap())
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()))
120                                 .build_raw()
121                                 .unwrap()
122                                 .sign(|_| {
123                                         RecoverableSignature::from_compact(
124                                                 &hex::decode("6ca95a74dc32e69ced6175b15a5cc56a92bf19f5dace0f134b7d94d464b9f5cf6090a18d48b243f289394d17bdf89466d8e6b37df5981f696bc3dd5986e1bee1").unwrap(),
125                                                 RecoveryId::from_i32(1).unwrap()
126                                         )
127                                 }).unwrap(),
128                         false, // Same features as set in InvoiceBuilder
129                         false, // No unknown fields
130                 ),
131                 (
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"
140                                 ).unwrap())
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,
150                                 }, RouteHintHop {
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,
158                                 }]))
159                                 .build_raw()
160                                 .unwrap()
161                                 .sign(|_| {
162                                         RecoverableSignature::from_compact(
163                                                 &hex::decode("6a6586db4e8f6d40e3a5bb92e4df5110c627e9ce493af237e20a046b4e86ea200178c59564ecf892f33a9558bf041b6ad2cb8292d7a6c351fbb7f2ae2d16b54e").unwrap(),
164                                                 RecoveryId::from_i32(0).unwrap()
165                                         )
166                                 }).unwrap(),
167                         false, // Same features as set in InvoiceBuilder
168                         false, // No unknown fields
169                 ),
170                 (
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"
179                                 ).unwrap())
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()))
181                                 .build_raw()
182                                 .unwrap()
183                                 .sign(|_| {
184                                         RecoverableSignature::from_compact(
185                                                 &hex::decode("16810439d1a9bfd5a65acc61340dc92448bb2d456a80b58ce012b73cb5202438020500c9ab7ef5573a4d174c811f669885ae27f895bb3a3be52c243589f87518").unwrap(),
186                                                 RecoveryId::from_i32(1).unwrap()
187                                         )
188                                 }).unwrap(),
189                         false, // Same features as set in InvoiceBuilder
190                         false, // No unknown fields
191                 ),
192                 (
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"
201                                 ).unwrap())
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]
204                                 })
205                                 .build_raw()
206                                 .unwrap()
207                                 .sign(|_| {
208                                         RecoverableSignature::from_compact(
209                                                 &hex::decode("5a8bd7b97c1cc9055ee60cf2356621f8752248e037a953886a1782b44a58f5ff2d94e6bc89b7b514541a3603bb33722b6c08aa1a3639d34becc549a99fea6eae").unwrap(),
210                                                 RecoveryId::from_i32(0).unwrap()
211                                         )
212                                 }).unwrap(),
213                         false, // Same features as set in InvoiceBuilder
214                         false, // No unknown fields
215                 ),
216                 (
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"
225                                 ).unwrap())
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]
228                                 })
229                                 .build_raw()
230                                 .unwrap()
231                                 .sign(|_| {
232                                         RecoverableSignature::from_compact(
233                                                 &hex::decode("2b3ec248f80301a421817369194f012cdd8af8df1c279981420f9e901e20fa3309d791e11355e609b59ce4a220852a0cd55ab862b1785a83b206c90fa74d01c8").unwrap(),
234                                                 RecoveryId::from_i32(1).unwrap()
235                                         )
236                                 }).unwrap(),
237                         false, // Same features as set in InvoiceBuilder
238                         false, // No unknown fields
239                 ),
240                 (
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"
248                                 ).unwrap())
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,
260                                 }]))
261                                 .build_raw()
262                                 .unwrap()
263                                 .sign(|_| {
264                                         RecoverableSignature::from_compact(
265                                                 &hex::decode("1b1160cf6186b55722c1ac7ea502086baaccaabdc76b326e666b7f309d972b15069bfca11cd365304b36f48230cc12f3f13a017aab65f7c165a169df32282a58").unwrap(),
266                                                 RecoveryId::from_i32(1).unwrap()
267                                         )
268                                 }).unwrap(),
269                         false, // Same features as set in InvoiceBuilder
270                         false, // No unknown fields
271                 ),
272                 (
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"
280                                 ).unwrap())
281                                 .description("coffee beans".to_owned())
282                                 .build_raw()
283                                 .unwrap()
284                                 .sign(|_| {
285                                         RecoverableSignature::from_compact(
286                                                 &hex::decode("5755469bf4b8e6b6ae7a1308d5f9bad5c82812e0855cd24fac242aa323fa820c5c551ede4faeabcb7fb6d5a464ad0e35c86f615589ee0e0c250c216a662198c1").unwrap(),
287                                                 RecoveryId::from_i32(1).unwrap()
288                                         )
289                                 }).unwrap(),
290                         true, // Different features than set in InvoiceBuilder
291                         false, // No unknown fields
292                 ),
293                 (
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"
301                                 ).unwrap())
302                                 .description("coffee beans".to_owned())
303                                 .build_raw()
304                                 .unwrap()
305                                 .sign(|_| {
306                                         RecoverableSignature::from_compact(
307                                                 &hex::decode("5755469bf4b8e6b6ae7a1308d5f9bad5c82812e0855cd24fac242aa323fa820c5c551ede4faeabcb7fb6d5a464ad0e35c86f615589ee0e0c250c216a662198c1").unwrap(),
308                                                 RecoveryId::from_i32(1).unwrap()
309                                         )
310                                 }).unwrap(),
311                         true, // Different features than set in InvoiceBuilder
312                         false, // No unknown fields
313                 ),
314                 (
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"
322                                 ).unwrap())
323                                 .description("coffee beans".to_owned())
324                                 .build_raw()
325                                 .unwrap()
326                                 .sign(|_| {
327                                         RecoverableSignature::from_compact(
328                                                 &hex::decode("150a5252308f25bc2641a186de87470189bb003774326beee33b9a2a720d1584386631c5dda6fc3195f97464bfc93d2574868eadd767d6da1078329c4349c837").unwrap(),
329                                                 RecoveryId::from_i32(0).unwrap()
330                                         )
331                                 }).unwrap(),
332                         true, // Different features than set in InvoiceBuilder
333                         true, // Some unknown fields
334                 ),
335                 ( // Older version of the payment metadata test with a payment_pubkey set
336                         "lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66sp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgqy9gw6ymamd20jumvdgpfphkhp8fzhhdhycw36egcmla5vlrtrmhs9t7psfy3hkkdqzm9eq64fjg558znccds5nhsfmxveha5xe0dykgpspdha0".to_owned(),
337                         InvoiceBuilder::new(Currency::Bitcoin)
338                                 .amount_milli_satoshis(1_000_000_000)
339                                 .duration_since_epoch(Duration::from_secs(1496314658))
340                                 .payment_hash(sha256::Hash::from_hex(
341                                         "0001020304050607080900010203040506070809000102030405060708090102"
342                                 ).unwrap())
343                                 .description("payment metadata inside".to_owned())
344                                 .payment_metadata(hex::decode("01fafaf0").unwrap())
345                                 .require_payment_metadata()
346                                 .payee_pub_key(PublicKey::from_slice(&hex::decode(
347                                                 "03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad"
348                                         ).unwrap()).unwrap())
349                                 .payment_secret(PaymentSecret([0x11; 32]))
350                                 .build_raw()
351                                 .unwrap()
352                                 .sign(|_| {
353                                         RecoverableSignature::from_compact(
354                                                 &hex::decode("2150ed137ddb54f9736c6a0290ded709d22bddb7261d1d6518dffb467c6b1eef02afc182491bdacd00b65c83554c914a1c53c61b0a4ef04eccccdfb4365ed259").unwrap(),
355                                                 RecoveryId::from_i32(1).unwrap()
356                                         )
357                                 }).unwrap(),
358                         false, // Different features than set in InvoiceBuilder
359                         true, // Some unknown fields
360                 ),
361                 (
362                         "lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgq7hf8he7ecf7n4ffphs6awl9t6676rrclv9ckg3d3ncn7fct63p6s365duk5wrk202cfy3aj5xnnp5gs3vrdvruverwwq7yzhkf5a3xqpd05wjc".to_owned(),
363                         InvoiceBuilder::new(Currency::Bitcoin)
364                                 .amount_milli_satoshis(1_000_000_000)
365                                 .duration_since_epoch(Duration::from_secs(1496314658))
366                                 .payment_hash(sha256::Hash::from_hex(
367                                         "0001020304050607080900010203040506070809000102030405060708090102"
368                                 ).unwrap())
369                                 .description("payment metadata inside".to_owned())
370                                 .payment_metadata(hex::decode("01fafaf0").unwrap())
371                                 .require_payment_metadata()
372                                 .payment_secret(PaymentSecret([0x11; 32]))
373                                 .build_raw()
374                                 .unwrap()
375                                 .sign(|_| {
376                                         RecoverableSignature::from_compact(
377                                                 &hex::decode("f5d27be7d9c27d3aa521bc35d77cabd6bda18f1f61716445b19e27e4e17a887508ea8de5a8e1d94f561248f65434e61a221160dac1f1991b9c0f1057b269d898").unwrap(),
378                                                 RecoveryId::from_i32(1).unwrap()
379                                         )
380                                 }).unwrap(),
381                         false, // Different features than set in InvoiceBuilder
382                         true, // Some unknown fields
383                 ),
384
385         ]
386 }
387
388 #[test]
389 fn invoice_deserialize() {
390         for (serialized, deserialized, ignore_feature_diff, ignore_unknown_fields) in get_test_tuples() {
391                 eprintln!("Testing invoice {}...", serialized);
392                 let parsed = serialized.parse::<SignedRawBolt11Invoice>().unwrap();
393
394                 let (parsed_invoice, _, parsed_sig) = parsed.into_parts();
395                 let (deserialized_invoice, _, deserialized_sig) = deserialized.into_parts();
396
397                 assert_eq!(deserialized_sig, parsed_sig);
398                 assert_eq!(deserialized_invoice.hrp, parsed_invoice.hrp);
399                 assert_eq!(deserialized_invoice.data.timestamp, parsed_invoice.data.timestamp);
400
401                 let mut deserialized_hunks: HashSet<_> = deserialized_invoice.data.tagged_fields.iter().collect();
402                 let mut parsed_hunks: HashSet<_> = parsed_invoice.data.tagged_fields.iter().collect();
403                 if ignore_feature_diff {
404                         deserialized_hunks.retain(|h|
405                                 if let RawTaggedField::KnownSemantics(TaggedField::Features(_)) = h { false } else { true });
406                         parsed_hunks.retain(|h|
407                                 if let RawTaggedField::KnownSemantics(TaggedField::Features(_)) = h { false } else { true });
408                 }
409                 if ignore_unknown_fields {
410                         parsed_hunks.retain(|h|
411                                 if let RawTaggedField::UnknownSemantics(_) = h { false } else { true });
412                 }
413                 assert_eq!(deserialized_hunks, parsed_hunks);
414
415                 Bolt11Invoice::from_signed(serialized.parse::<SignedRawBolt11Invoice>().unwrap()).unwrap();
416         }
417 }
418
419 #[test]
420 fn test_bolt_invalid_invoices() {
421         // Tests the BOLT 11 invalid invoice test vectors
422         assert_eq!(Bolt11Invoice::from_str(
423                 "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqqsgqtqyx5vggfcsll4wu246hz02kp85x4katwsk9639we5n5yngc3yhqkm35jnjw4len8vrnqnf5ejh0mzj9n3vz2px97evektfm2l6wqccp3y7372"
424                 ), Err(ParseOrSemanticError::SemanticError(SemanticError::InvalidFeatures)));
425         assert_eq!(Bolt11Invoice::from_str(
426                 "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrnt"
427                 ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::Bech32Error(bech32::Error::InvalidChecksum))));
428         assert_eq!(Bolt11Invoice::from_str(
429                 "pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny"
430                 ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::Bech32Error(bech32::Error::MissingSeparator))));
431         assert_eq!(Bolt11Invoice::from_str(
432                 "LNBC2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny"
433                 ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::Bech32Error(bech32::Error::MixedCase))));
434         assert_eq!(Bolt11Invoice::from_str(
435                 "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqwgt7mcn5yqw3yx0w94pswkpq6j9uh6xfqqqtsk4tnarugeektd4hg5975x9am52rz4qskukxdmjemg92vvqz8nvmsye63r5ykel43pgz7zq0g2"
436                 ), Err(ParseOrSemanticError::SemanticError(SemanticError::InvalidSignature)));
437         assert_eq!(Bolt11Invoice::from_str(
438                 "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6na6hlh"
439                 ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::TooShortDataPart)));
440         assert_eq!(Bolt11Invoice::from_str(
441                 "lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqrrzc4cvfue4zp3hggxp47ag7xnrlr8vgcmkjxk3j5jqethnumgkpqp23z9jclu3v0a7e0aruz366e9wqdykw6dxhdzcjjhldxq0w6wgqcnu43j"
442                 ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::UnknownSiPrefix)));
443         assert_eq!(Bolt11Invoice::from_str(
444                 "lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgq0lzc236j96a95uv0m3umg28gclm5lqxtqqwk32uuk4k6673k6n5kfvx3d2h8s295fad45fdhmusm8sjudfhlf6dcsxmfvkeywmjdkxcp99202x"
445                 ), Err(ParseOrSemanticError::SemanticError(SemanticError::ImpreciseAmount)));
446 }