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