73e2ea8384a1190680c913cf50a5336317f6f171
[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, SignedRawInvoice, 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         ]
336 }
337
338 #[test]
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();
343
344                 let (parsed_invoice, _, parsed_sig) = parsed.into_parts();
345                 let (deserialized_invoice, _, deserialized_sig) = deserialized.into_parts();
346
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);
350
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 });
358                 }
359                 if ignore_unknown_fields {
360                         parsed_hunks.retain(|h|
361                                 if let RawTaggedField::UnknownSemantics(_) = h { false } else { true });
362                 }
363                 assert_eq!(deserialized_hunks, parsed_hunks);
364
365                 Invoice::from_signed(serialized.parse::<SignedRawInvoice>().unwrap()).unwrap();
366         }
367 }
368
369 #[test]
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)));
396 }