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