Refactor handling of InvoiceRequest
[rust-lightning] / lightning / src / offers / invoice_error.rs
1 // This file is Copyright its original authors, visible in version control
2 // history.
3 //
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
8 // licenses.
9
10 //! Data structures and encoding for `invoice_error` messages.
11
12 use crate::io;
13 use crate::ln::msgs::DecodeError;
14 use crate::offers::merkle::SignError;
15 use crate::offers::parse::Bolt12SemanticError;
16 use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, WithoutLength, Writeable, Writer};
17 use crate::util::string::UntrustedString;
18
19 #[allow(unused_imports)]
20 use crate::prelude::*;
21
22 /// An error in response to an [`InvoiceRequest`] or an [`Bolt12Invoice`].
23 ///
24 /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
25 /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
26 #[derive(Clone, Debug)]
27 #[cfg_attr(test, derive(PartialEq))]
28 pub struct InvoiceError {
29         /// The field in the [`InvoiceRequest`] or the [`Bolt12Invoice`] that contained an error.
30         ///
31         /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
32         /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
33         pub erroneous_field: Option<ErroneousField>,
34
35         /// An explanation of the error.
36         pub message: UntrustedString,
37 }
38
39 /// The field in the [`InvoiceRequest`] or the [`Bolt12Invoice`] that contained an error.
40 ///
41 /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
42 /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
43 #[derive(Clone, Debug)]
44 #[cfg_attr(test, derive(PartialEq))]
45 pub struct ErroneousField {
46         /// The type number of the TLV field containing the error.
47         pub tlv_fieldnum: u64,
48
49         /// A value to use for the TLV field to avoid the error.
50         pub suggested_value: Option<Vec<u8>>,
51 }
52
53 impl InvoiceError {
54         /// Creates an [`InvoiceError`] with the given message.
55         pub fn from_string(s: String) -> Self {
56                 Self {
57                         erroneous_field: None,
58                         message: UntrustedString(s),
59                 }
60         }
61 }
62
63 impl core::fmt::Display for InvoiceError {
64         fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
65                 self.message.fmt(f)
66         }
67 }
68
69 impl Writeable for InvoiceError {
70         fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
71                 let tlv_fieldnum = self.erroneous_field.as_ref().map(|f| f.tlv_fieldnum);
72                 let suggested_value =
73                         self.erroneous_field.as_ref().and_then(|f| f.suggested_value.as_ref());
74                 write_tlv_fields!(writer, {
75                         (1, tlv_fieldnum, (option, encoding: (u64, HighZeroBytesDroppedBigSize))),
76                         (3, suggested_value, (option, encoding: (Vec<u8>, WithoutLength))),
77                         (5, WithoutLength(&self.message), required),
78                 });
79                 Ok(())
80         }
81 }
82
83 impl Readable for InvoiceError {
84         fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
85                 _init_and_read_len_prefixed_tlv_fields!(reader, {
86                         (1, erroneous_field, (option, encoding: (u64, HighZeroBytesDroppedBigSize))),
87                         (3, suggested_value, (option, encoding: (Vec<u8>, WithoutLength))),
88                         (5, error, (option, encoding: (UntrustedString, WithoutLength))),
89                 });
90
91                 let erroneous_field = match (erroneous_field, suggested_value) {
92                         (None, None) => None,
93                         (None, Some(_)) => return Err(DecodeError::InvalidValue),
94                         (Some(tlv_fieldnum), suggested_value) => {
95                                 Some(ErroneousField { tlv_fieldnum, suggested_value })
96                         },
97                 };
98
99                 let message = match error {
100                         None => return Err(DecodeError::InvalidValue),
101                         Some(error) => error,
102                 };
103
104                 Ok(InvoiceError { erroneous_field, message })
105         }
106 }
107
108 impl From<Bolt12SemanticError> for InvoiceError {
109         fn from(error: Bolt12SemanticError) -> Self {
110                 InvoiceError {
111                         erroneous_field: None,
112                         message: UntrustedString(format!("{:?}", error)),
113                 }
114         }
115 }
116
117 impl From<SignError> for InvoiceError {
118         fn from(error: SignError) -> Self {
119                 let message = match error {
120                         SignError::Signing => "Failed signing invoice",
121                         SignError::Verification(_) => "Failed invoice signature verification",
122                 };
123                 InvoiceError {
124                         erroneous_field: None,
125                         message: UntrustedString(message.to_string()),
126                 }
127         }
128 }
129
130 #[cfg(test)]
131 mod tests {
132         use super::{ErroneousField, InvoiceError};
133
134         use crate::ln::msgs::DecodeError;
135         use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, VecWriter, WithoutLength, Writeable};
136         use crate::util::string::UntrustedString;
137
138         #[test]
139         fn parses_invoice_error_without_erroneous_field() {
140                 let mut writer = VecWriter(Vec::new());
141                 let invoice_error = InvoiceError {
142                         erroneous_field: None,
143                         message: UntrustedString("Invalid value".to_string()),
144                 };
145                 invoice_error.write(&mut writer).unwrap();
146
147                 let buffer = writer.0;
148                 match InvoiceError::read(&mut &buffer[..]) {
149                         Ok(invoice_error) => {
150                                 assert_eq!(invoice_error.message, UntrustedString("Invalid value".to_string()));
151                                 assert_eq!(invoice_error.erroneous_field, None);
152                         }
153                         Err(e) => panic!("Unexpected error: {:?}", e),
154                 }
155         }
156
157         #[test]
158         fn parses_invoice_error_with_erroneous_field() {
159                 let mut writer = VecWriter(Vec::new());
160                 let invoice_error = InvoiceError {
161                         erroneous_field: Some(ErroneousField {
162                                 tlv_fieldnum: 42,
163                                 suggested_value: Some(vec![42; 32]),
164                         }),
165                         message: UntrustedString("Invalid value".to_string()),
166                 };
167                 invoice_error.write(&mut writer).unwrap();
168
169                 let buffer = writer.0;
170                 match InvoiceError::read(&mut &buffer[..]) {
171                         Ok(invoice_error) => {
172                                 assert_eq!(invoice_error.message, UntrustedString("Invalid value".to_string()));
173                                 assert_eq!(
174                                         invoice_error.erroneous_field,
175                                         Some(ErroneousField { tlv_fieldnum: 42, suggested_value: Some(vec![42; 32]) }),
176                                 );
177                         }
178                         Err(e) => panic!("Unexpected error: {:?}", e),
179                 }
180         }
181
182         #[test]
183         fn parses_invoice_error_without_suggested_value() {
184                 let mut writer = VecWriter(Vec::new());
185                 let invoice_error = InvoiceError {
186                         erroneous_field: Some(ErroneousField {
187                                 tlv_fieldnum: 42,
188                                 suggested_value: None,
189                         }),
190                         message: UntrustedString("Invalid value".to_string()),
191                 };
192                 invoice_error.write(&mut writer).unwrap();
193
194                 let buffer = writer.0;
195                 match InvoiceError::read(&mut &buffer[..]) {
196                         Ok(invoice_error) => {
197                                 assert_eq!(invoice_error.message, UntrustedString("Invalid value".to_string()));
198                                 assert_eq!(
199                                         invoice_error.erroneous_field,
200                                         Some(ErroneousField { tlv_fieldnum: 42, suggested_value: None }),
201                                 );
202                         }
203                         Err(e) => panic!("Unexpected error: {:?}", e),
204                 }
205         }
206
207         #[test]
208         fn fails_parsing_invoice_error_without_message() {
209                 let tlv_fieldnum: Option<u64> = None;
210                 let suggested_value: Option<&Vec<u8>> = None;
211                 let error: Option<&String> = None;
212
213                 let mut writer = VecWriter(Vec::new());
214                 let mut write_tlv = || -> Result<(), DecodeError> {
215                         write_tlv_fields!(&mut writer, {
216                                 (1, tlv_fieldnum, (option, encoding: (u64, HighZeroBytesDroppedBigSize))),
217                                 (3, suggested_value, (option, encoding: (Vec<u8>, WithoutLength))),
218                                 (5, error, (option, encoding: (String, WithoutLength))),
219                         });
220                         Ok(())
221                 };
222                 write_tlv().unwrap();
223
224                 let buffer = writer.0;
225                 match InvoiceError::read(&mut &buffer[..]) {
226                         Ok(_) => panic!("Expected error"),
227                         Err(e) => {
228                                 assert_eq!(e, DecodeError::InvalidValue);
229                         },
230                 }
231         }
232
233         #[test]
234         fn fails_parsing_invoice_error_without_field() {
235                 let tlv_fieldnum: Option<u64> = None;
236                 let suggested_value = vec![42; 32];
237                 let error = "Invalid value".to_string();
238
239                 let mut writer = VecWriter(Vec::new());
240                 let mut write_tlv = || -> Result<(), DecodeError> {
241                         write_tlv_fields!(&mut writer, {
242                                 (1, tlv_fieldnum, (option, encoding: (u64, HighZeroBytesDroppedBigSize))),
243                                 (3, Some(&suggested_value), (option, encoding: (Vec<u8>, WithoutLength))),
244                                 (5, Some(&error), (option, encoding: (String, WithoutLength))),
245                         });
246                         Ok(())
247                 };
248                 write_tlv().unwrap();
249
250                 let buffer = writer.0;
251                 match InvoiceError::read(&mut &buffer[..]) {
252                         Ok(_) => panic!("Expected error"),
253                         Err(e) => {
254                                 assert_eq!(e, DecodeError::InvalidValue);
255                         },
256                 }
257         }
258 }