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