Convert the invoice creation API to millisats and req it for parse
[rust-lightning] / lightning-invoice / tests / ser_de.rs
1 extern crate bitcoin_hashes;
2 extern crate lightning;
3 extern crate lightning_invoice;
4 extern crate secp256k1;
5
6 use bitcoin_hashes::hex::FromHex;
7 use bitcoin_hashes::sha256;
8 use lightning::ln::PaymentSecret;
9 use lightning_invoice::*;
10 use secp256k1::Secp256k1;
11 use secp256k1::key::SecretKey;
12 use secp256k1::recovery::{RecoverableSignature, RecoveryId};
13 use std::time::{Duration, UNIX_EPOCH};
14 use std::str::FromStr;
15
16 // TODO: add more of the examples from BOLT11 and generate ones causing SemanticErrors
17
18 fn get_test_tuples() -> Vec<(String, SignedRawInvoice, Option<SemanticError>)> {
19         vec![
20                 (
21                         "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmw\
22                         wd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9\
23                         ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w".to_owned(),
24                         InvoiceBuilder::new(Currency::Bitcoin)
25                                 .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
26                                 .payment_hash(sha256::Hash::from_hex(
27                                                 "0001020304050607080900010203040506070809000102030405060708090102"
28                                 ).unwrap())
29                                 .description("Please consider supporting this project".to_owned())
30                                 .build_raw()
31                                 .unwrap()
32                                 .sign(|_| {
33                                         RecoverableSignature::from_compact(
34                                                 & [
35                                                         0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
36                                                         0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
37                                                         0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
38                                                         0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
39                                                         0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
40                                                         0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
41                                                 ],
42                                                 RecoveryId::from_i32(0).unwrap()
43                                         )
44                                 }).unwrap(),
45                         None
46                 ),
47                 (
48                         "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3\
49                         k7enxv4jsxqzpuaztrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch\
50                         9zw97j25emudupq63nyw24cg27h2rspfj9srp".to_owned(),
51                         InvoiceBuilder::new(Currency::Bitcoin)
52                                 .amount_milli_satoshis(250_000_000)
53                                 .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
54                                 .payment_hash(sha256::Hash::from_hex(
55                                         "0001020304050607080900010203040506070809000102030405060708090102"
56                                 ).unwrap())
57                                 .description("1 cup coffee".to_owned())
58                                 .expiry_time(Duration::from_secs(60))
59                                 .build_raw()
60                                 .unwrap()
61                                 .sign(|_| {
62                                         RecoverableSignature::from_compact(
63                                                 & [
64                                                         0xe8, 0x96, 0x39, 0xba, 0x68, 0x14, 0xe3, 0x66, 0x89, 0xd4, 0xb9, 0x1b,
65                                                         0xf1, 0x25, 0xf1, 0x03, 0x51, 0xb5, 0x5d, 0xa0, 0x57, 0xb0, 0x06, 0x47,
66                                                         0xa8, 0xda, 0xba, 0xeb, 0x8a, 0x90, 0xc9, 0x5f, 0x16, 0x0f, 0x9d, 0x5a,
67                                                         0x6e, 0x0f, 0x79, 0xd1, 0xfc, 0x2b, 0x96, 0x42, 0x38, 0xb9, 0x44, 0xe2,
68                                                         0xfa, 0x4a, 0xa6, 0x77, 0xc6, 0xf0, 0x20, 0xd4, 0x66, 0x47, 0x2a, 0xb8,
69                                                         0x42, 0xbd, 0x75, 0x0e
70                                                 ],
71                                                 RecoveryId::from_i32(1).unwrap()
72                                         )
73                                 }).unwrap(),
74                         None
75                 ),
76                 (
77                         "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qq\
78                         dhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqscc6gd6ql3jrc5yzme8v4ntcewwz5cnw92tz0pc8qcuufvq7k\
79                         hhr8wpald05e92xw006sq94mg8v2ndf4sefvf9sygkshp5zfem29trqq2yxxz7".to_owned(),
80                         InvoiceBuilder::new(Currency::Bitcoin)
81                                 .amount_milli_satoshis(2_000_000_000)
82                                 .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
83                                 .payment_hash(sha256::Hash::from_hex(
84                                         "0001020304050607080900010203040506070809000102030405060708090102"
85                                 ).unwrap())
86                                 .description_hash(sha256::Hash::from_hex(
87                                         "3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1"
88                                 ).unwrap())
89                                 .build_raw()
90                                 .unwrap()
91                                 .sign(|_| {
92                                         RecoverableSignature::from_compact(
93                                                 & [
94                                                         0xc6, 0x34, 0x86, 0xe8, 0x1f, 0x8c, 0x87, 0x8a, 0x10, 0x5b, 0xc9, 0xd9,
95                                                         0x59, 0xaf, 0x19, 0x73, 0x85, 0x4c, 0x4d, 0xc5, 0x52, 0xc4, 0xf0, 0xe0,
96                                                         0xe0, 0xc7, 0x38, 0x96, 0x03, 0xd6, 0xbd, 0xc6, 0x77, 0x07, 0xbf, 0x6b,
97                                                         0xe9, 0x92, 0xa8, 0xce, 0x7b, 0xf5, 0x00, 0x16, 0xbb, 0x41, 0xd8, 0xa9,
98                                                         0xb5, 0x35, 0x86, 0x52, 0xc4, 0x96, 0x04, 0x45, 0xa1, 0x70, 0xd0, 0x49,
99                                                         0xce, 0xd4, 0x55, 0x8c
100                                                 ],
101                                                 RecoveryId::from_i32(0).unwrap()
102                                         )
103                                 }).unwrap(),
104                         None
105                 ),
106                 (
107                         "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp59g4z52329g4z52329g4z52329g4z52329g4z52329g4z52329g4q9qrsgqzfhag3vsafx4e5qssalvw4rn0phsvpp3e5h2xxyk9l8fxsutvndx9t840dqvdrlu2gqmk0q8apqrgnjy9amc07hmjl9e9yzqjks5w2gqgjnyms".to_owned(),
108                         InvoiceBuilder::new(Currency::Bitcoin)
109                                 .payment_hash(sha256::Hash::from_hex(
110                                         "0001020304050607080900010203040506070809000102030405060708090102"
111                                 ).unwrap())
112                                 .description("coffee beans".to_string())
113                                 .amount_milli_satoshis(2_000_000_000)
114                                 .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
115                                 .payment_secret(PaymentSecret([42; 32]))
116                                 .build_raw()
117                                 .unwrap()
118                                 .sign::<_, ()>(|msg_hash| {
119                                         let privkey = SecretKey::from_slice(&[41; 32]).unwrap();
120                                         let secp_ctx = Secp256k1::new();
121                                         Ok(secp_ctx.sign_recoverable(msg_hash, &privkey))
122                                 })
123                                 .unwrap(),
124                         None
125                 )
126         ]
127 }
128
129
130 #[test]
131 fn serialize() {
132         for (serialized, deserialized, _) in get_test_tuples() {
133                 assert_eq!(deserialized.to_string(), serialized);
134         }
135 }
136
137 #[test]
138 fn deserialize() {
139         for (serialized, deserialized, maybe_error) in get_test_tuples() {
140                 let parsed = serialized.parse::<SignedRawInvoice>().unwrap();
141
142                 assert_eq!(parsed, deserialized);
143
144                 let validated = Invoice::from_signed(parsed);
145
146                 if let Some(error) = maybe_error {
147                         assert_eq!(Err(error), validated);
148                 } else {
149                         assert!(validated.is_ok());
150                 }
151         }
152 }
153
154 #[test]
155 fn test_bolt_invalid_invoices() {
156         // Tests the BOLT 11 invalid invoice test vectors
157         assert_eq!(Invoice::from_str(
158                 "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrnt"
159                 ), Err(ParseOrSemanticError::ParseError(ParseError::Bech32Error(bech32::Error::InvalidChecksum))));
160         assert_eq!(Invoice::from_str(
161                 "pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny"
162                 ), Err(ParseOrSemanticError::ParseError(ParseError::Bech32Error(bech32::Error::MissingSeparator))));
163         assert_eq!(Invoice::from_str(
164                 "LNBC2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny"
165                 ), Err(ParseOrSemanticError::ParseError(ParseError::Bech32Error(bech32::Error::MixedCase))));
166         assert_eq!(Invoice::from_str(
167                 "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaxtrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspk28uwq"
168                 ), Err(ParseOrSemanticError::SemanticError(SemanticError::InvalidSignature)));
169         assert_eq!(Invoice::from_str(
170                 "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6na6hlh"
171                 ), Err(ParseOrSemanticError::ParseError(ParseError::TooShortDataPart)));
172         assert_eq!(Invoice::from_str(
173                 "lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpujr6jxr9gq9pv6g46y7d20jfkegkg4gljz2ea2a3m9lmvvr95tq2s0kvu70u3axgelz3kyvtp2ywwt0y8hkx2869zq5dll9nelr83zzqqpgl2zg"
174                 ), Err(ParseOrSemanticError::ParseError(ParseError::UnknownSiPrefix)));
175         assert_eq!(Invoice::from_str(
176                 "lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu7hqtk93pkf7sw55rdv4k9z2vj050rxdr6za9ekfs3nlt5lr89jqpdmxsmlj9urqumg0h9wzpqecw7th56tdms40p2ny9q4ddvjsedzcplva53s"
177                 ), Err(ParseOrSemanticError::SemanticError(SemanticError::ImpreciseAmount)));
178 }