Skip to content

Commit 74a9ed9

Browse files
authored
Merge pull request #2294 from jkczyz/2023-05-onion-message-replies
BOLT 12 Offers message handling support
2 parents d78dd48 + 3fd6b44 commit 74a9ed9

File tree

12 files changed

+848
-139
lines changed

12 files changed

+848
-139
lines changed

fuzz/src/onion_message.rs

+44-12
Large diffs are not rendered by default.

lightning-background-processor/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -519,8 +519,9 @@ use core::task;
519519
/// # type MyUtxoLookup = dyn lightning::routing::utxo::UtxoLookup + Send + Sync;
520520
/// # type MyFilter = dyn lightning::chain::Filter + Send + Sync;
521521
/// # type MyLogger = dyn lightning::util::logger::Logger + Send + Sync;
522+
/// # type MyMessageRouter = dyn lightning::onion_message::MessageRouter + Send + Sync;
522523
/// # type MyChainMonitor = lightning::chain::chainmonitor::ChainMonitor<lightning::sign::InMemorySigner, Arc<MyFilter>, Arc<MyBroadcaster>, Arc<MyFeeEstimator>, Arc<MyLogger>, Arc<MyPersister>>;
523-
/// # type MyPeerManager = lightning::ln::peer_handler::SimpleArcPeerManager<MySocketDescriptor, MyChainMonitor, MyBroadcaster, MyFeeEstimator, MyUtxoLookup, MyLogger>;
524+
/// # type MyPeerManager = lightning::ln::peer_handler::SimpleArcPeerManager<MySocketDescriptor, MyChainMonitor, MyBroadcaster, MyFeeEstimator, MyUtxoLookup, MyLogger, MyMessageRouter>;
524525
/// # type MyNetworkGraph = lightning::routing::gossip::NetworkGraph<Arc<MyLogger>>;
525526
/// # type MyGossipSync = lightning::routing::gossip::P2PGossipSync<Arc<MyNetworkGraph>, Arc<MyUtxoLookup>, Arc<MyLogger>>;
526527
/// # type MyChannelManager = lightning::ln::channelmanager::SimpleArcChannelManager<MyChainMonitor, MyBroadcaster, MyFeeEstimator, MyLogger>;

lightning/src/ln/peer_handler.rs

+25-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use crate::util::ser::{VecWriter, Writeable, Writer};
2828
use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep};
2929
use crate::ln::wire;
3030
use crate::ln::wire::{Encode, Type};
31-
use crate::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
31+
use crate::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
3232
use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, NodeAlias};
3333
use crate::util::atomic_counter::AtomicCounter;
3434
use crate::util::logger::Logger;
@@ -118,9 +118,12 @@ impl OnionMessageHandler for IgnoringMessageHandler {
118118
InitFeatures::empty()
119119
}
120120
}
121+
impl OffersMessageHandler for IgnoringMessageHandler {
122+
fn handle_message(&self, _msg: OffersMessage) -> Option<OffersMessage> { None }
123+
}
121124
impl CustomOnionMessageHandler for IgnoringMessageHandler {
122125
type CustomMessage = Infallible;
123-
fn handle_custom_message(&self, _msg: Infallible) {
126+
fn handle_custom_message(&self, _msg: Infallible) -> Option<Infallible> {
124127
// Since we always return `None` in the read the handle method should never be called.
125128
unreachable!();
126129
}
@@ -604,7 +607,15 @@ impl Peer {
604607
/// issues such as overly long function definitions.
605608
///
606609
/// This is not exported to bindings users as `Arc`s don't make sense in bindings.
607-
pub type SimpleArcPeerManager<SD, M, T, F, C, L> = PeerManager<SD, Arc<SimpleArcChannelManager<M, T, F, L>>, Arc<P2PGossipSync<Arc<NetworkGraph<Arc<L>>>, Arc<C>, Arc<L>>>, Arc<SimpleArcOnionMessenger<L>>, Arc<L>, IgnoringMessageHandler, Arc<KeysManager>>;
610+
pub type SimpleArcPeerManager<SD, M, T, F, C, L, R> = PeerManager<
611+
SD,
612+
Arc<SimpleArcChannelManager<M, T, F, L>>,
613+
Arc<P2PGossipSync<Arc<NetworkGraph<Arc<L>>>, Arc<C>, Arc<L>>>,
614+
Arc<SimpleArcOnionMessenger<L, R>>,
615+
Arc<L>,
616+
IgnoringMessageHandler,
617+
Arc<KeysManager>
618+
>;
608619

609620
/// SimpleRefPeerManager is a type alias for a PeerManager reference, and is the reference
610621
/// counterpart to the SimpleArcPeerManager type alias. Use this type by default when you don't
@@ -614,7 +625,17 @@ pub type SimpleArcPeerManager<SD, M, T, F, C, L> = PeerManager<SD, Arc<SimpleArc
614625
/// helps with issues such as long function definitions.
615626
///
616627
/// This is not exported to bindings users as general type aliases don't make sense in bindings.
617-
pub type SimpleRefPeerManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, 'm, SD, M, T, F, C, L> = PeerManager<SD, SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'm, M, T, F, L>, &'f P2PGossipSync<&'g NetworkGraph<&'f L>, &'h C, &'f L>, &'i SimpleRefOnionMessenger<'j, 'k, L>, &'f L, IgnoringMessageHandler, &'c KeysManager>;
628+
pub type SimpleRefPeerManager<
629+
'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, 'm, 'n, SD, M, T, F, C, L, R
630+
> = PeerManager<
631+
SD,
632+
&'n SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'm, M, T, F, L>,
633+
&'f P2PGossipSync<&'g NetworkGraph<&'f L>, &'h C, &'f L>,
634+
&'i SimpleRefOnionMessenger<'g, 'm, 'n, L, R>,
635+
&'f L,
636+
IgnoringMessageHandler,
637+
&'c KeysManager
638+
>;
618639

619640

620641
/// A generic trait which is implemented for all [`PeerManager`]s. This makes bounding functions or

lightning/src/offers/invoice_error.rs

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

lightning/src/offers/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//! Offers are a flexible protocol for Lightning payments.
1414
1515
pub mod invoice;
16+
pub mod invoice_error;
1617
pub mod invoice_request;
1718
mod merkle;
1819
pub mod offer;

0 commit comments

Comments
 (0)