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