Skip to content

Commit 78923e8

Browse files
committed
Onion message payload for Offers
TODO: Include details
1 parent de4d8c6 commit 78923e8

File tree

4 files changed

+123
-14
lines changed

4 files changed

+123
-14
lines changed

lightning/src/onion_message/messenger.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,8 @@ impl<ES: Deref, NS: Deref, L: Deref, CMH: Deref> OnionMessenger<ES, NS, L, CMH>
217217
return Err(SendError::TooFewBlindedHops);
218218
}
219219
}
220-
let OnionMessageContents::Custom(ref msg) = message;
221-
if msg.tlv_type() < 64 { return Err(SendError::InvalidMessage) }
220+
221+
if message.tlv_type() < 64 { return Err(SendError::InvalidMessage) }
222222

223223
// If we are sending straight to a blinded path and we are the introduction node, we need to
224224
// advance the blinded path by 1 hop so the second hop is the new introduction node.
@@ -342,6 +342,7 @@ impl<ES: Deref, NS: Deref, L: Deref, CMH: Deref> OnionMessageHandler for OnionMe
342342
"Received an onion message with path_id {:02x?} and {} reply_path",
343343
path_id, if reply_path.is_some() { "a" } else { "no" });
344344
match message {
345+
OnionMessageContents::Offers(_msg) => todo!(),
345346
OnionMessageContents::Custom(msg) => self.custom_handler.handle_custom_message(msg),
346347
}
347348
},

lightning/src/onion_message/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
2323
mod blinded_path;
2424
mod messenger;
25+
mod offers;
2526
mod packet;
2627
mod utils;
2728
#[cfg(test)]
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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+
//! Message handling for BOLT 12 Offers.
11+
12+
use core::convert::TryFrom;
13+
use crate::io::{self, Read};
14+
use crate::ln::msgs::DecodeError;
15+
use crate::offers::invoice_request::InvoiceRequest;
16+
use crate::offers::invoice::Invoice;
17+
use crate::offers::parse::ParseError;
18+
use crate::util::ser::{ReadableArgs, Writeable, Writer};
19+
20+
use crate::prelude::*;
21+
22+
// TLV record types for the `onionmsg_tlv` TLV stream as defined in BOLT 4.
23+
const INVOICE_REQUEST_TLV_TYPE: u64 = 64;
24+
const INVOICE_TLV_TYPE: u64 = 66;
25+
const INVOICE_ERROR_TLV_TYPE: u64 = 68;
26+
27+
/// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`].
28+
///
29+
/// [`OnionMessage`]: crate::ln::msgs::OnionMessage
30+
#[derive(Debug)]
31+
pub enum OffersMessage {
32+
/// A request for an [`Invoice`] for a particular [`Offer`].
33+
///
34+
/// [`Offer`]: crate::offers::offer::Offer
35+
InvoiceRequest(InvoiceRequest),
36+
37+
/// An [`Invoice`] sent in response to an [`InvoiceRequest`] or a [`Refund`].
38+
///
39+
/// [`Refund`]: crate::offers::refund::Refund
40+
Invoice(Invoice),
41+
42+
/// An error from handling an [`OffersMessage`].
43+
InvoiceError,
44+
}
45+
46+
impl OffersMessage {
47+
/// Returns whether `tlv_type` corresponds to a TLV record for Offers.
48+
pub fn is_known_type(tlv_type: u64) -> bool {
49+
match tlv_type {
50+
INVOICE_REQUEST_TLV_TYPE | INVOICE_TLV_TYPE | INVOICE_ERROR_TLV_TYPE => true,
51+
_ => false,
52+
}
53+
}
54+
55+
/// The TLV record type for the message as used in an `onionmsg_tlv` TLV stream.
56+
pub fn tlv_type(&self) -> u64 {
57+
match self {
58+
OffersMessage::InvoiceRequest(_) => INVOICE_REQUEST_TLV_TYPE,
59+
OffersMessage::Invoice(_) => INVOICE_TLV_TYPE,
60+
OffersMessage::InvoiceError => INVOICE_ERROR_TLV_TYPE,
61+
}
62+
}
63+
64+
fn parse(tlv_type: u64, bytes: Vec<u8>) -> Result<Self, ParseError> {
65+
match tlv_type {
66+
INVOICE_REQUEST_TLV_TYPE => Ok(Self::InvoiceRequest(InvoiceRequest::try_from(bytes)?)),
67+
INVOICE_TLV_TYPE => Ok(Self::Invoice(Invoice::try_from(bytes)?)),
68+
INVOICE_ERROR_TLV_TYPE => Ok(Self::InvoiceError),
69+
_ => unreachable!(),
70+
}
71+
}
72+
}
73+
74+
impl Writeable for OffersMessage {
75+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
76+
match self {
77+
OffersMessage::InvoiceRequest(message) => message.write(w),
78+
OffersMessage::Invoice(message) => message.write(w),
79+
OffersMessage::InvoiceError => Ok(()),
80+
}
81+
}
82+
}
83+
84+
impl ReadableArgs<u64> for OffersMessage {
85+
fn read<R: Read>(r: &mut R, tlv_type: u64) -> Result<Self, DecodeError> {
86+
let mut bytes = Vec::new();
87+
r.read_to_end(&mut bytes).unwrap();
88+
89+
match Self::parse(tlv_type, bytes) {
90+
Ok(message) => Ok(message),
91+
Err(ParseError::Decode(e)) => Err(e),
92+
Err(_) => Err(DecodeError::InvalidValue), // TODO: log ParseError?
93+
}
94+
}
95+
}

lightning/src/onion_message/packet.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::ln::msgs::DecodeError;
1616
use crate::ln::onion_utils;
1717
use super::blinded_path::{BlindedPath, ForwardTlvs, ReceiveTlvs};
1818
use super::messenger::CustomOnionMessageHandler;
19+
use super::offers::OffersMessage;
1920
use crate::util::chacha20poly1305rfc::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter};
2021
use crate::util::ser::{BigSize, FixedLengthReader, LengthRead, LengthReadable, LengthReadableArgs, Readable, ReadableArgs, Writeable, Writer};
2122

@@ -108,10 +109,8 @@ pub(super) enum Payload<T: CustomOnionMessageContents> {
108109
/// The contents of an onion message. In the context of offers, this would be the invoice, invoice
109110
/// request, or invoice error.
110111
pub enum OnionMessageContents<T: CustomOnionMessageContents> {
111-
// Coming soon:
112-
// Invoice,
113-
// InvoiceRequest,
114-
// InvoiceError,
112+
/// A message related to BOLT 12 Offers.
113+
Offers(OffersMessage),
115114
/// A custom onion message specified by the user.
116115
Custom(T),
117116
}
@@ -122,6 +121,7 @@ impl<T: CustomOnionMessageContents> OnionMessageContents<T> {
122121
/// (C-not exported) as methods on non-cloneable enums are not currently exportable
123122
pub fn tlv_type(&self) -> u64 {
124123
match self {
124+
&OnionMessageContents::Offers(ref msg) => msg.tlv_type(),
125125
&OnionMessageContents::Custom(ref msg) => msg.tlv_type(),
126126
}
127127
}
@@ -131,6 +131,7 @@ impl<T: CustomOnionMessageContents> OnionMessageContents<T> {
131131
impl<T: CustomOnionMessageContents> Writeable for OnionMessageContents<T> {
132132
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
133133
match self {
134+
OnionMessageContents::Offers(msg) => Ok(msg.write(w)?),
134135
OnionMessageContents::Custom(msg) => Ok(msg.write(w)?),
135136
}
136137
}
@@ -215,19 +216,30 @@ impl<H: CustomOnionMessageHandler> ReadableArgs<(SharedSecret, &H)> for Payload<
215216
decode_tlv_stream_with_custom_tlv_decode!(&mut rd, {
216217
(2, reply_path, option),
217218
(4, read_adapter, (option: LengthReadableArgs, rho)),
218-
}, |msg_type, msg_reader| {
219+
}, |msg_type, msg_reader: &mut FixedLengthReader<_>| {
219220
if msg_type < 64 { return Ok(false) }
220221
// Don't allow reading more than one data TLV from an onion message.
221222
if message_type.is_some() { return Err(DecodeError::InvalidValue) }
222223

223224
message_type = Some(msg_type);
224-
match handler.read_custom_message(msg_type, msg_reader) {
225-
Ok(Some(msg)) => {
226-
message = Some(msg);
227-
Ok(true)
225+
match msg_type {
226+
tlv_type if OffersMessage::is_known_type(tlv_type) => {
227+
match OffersMessage::read(msg_reader, tlv_type) {
228+
Ok(msg) => {
229+
message = Some(OnionMessageContents::Offers(msg));
230+
Ok(true)
231+
},
232+
Err(e) => Err(e),
233+
}
234+
},
235+
_ => match handler.read_custom_message(msg_type, msg_reader) {
236+
Ok(Some(msg)) => {
237+
message = Some(OnionMessageContents::Custom(msg));
238+
Ok(true)
239+
},
240+
Ok(None) => Ok(false),
241+
Err(e) => Err(e),
228242
},
229-
Ok(None) => Ok(false),
230-
Err(e) => Err(e),
231243
}
232244
});
233245
rd.eat_remaining().map_err(|_| DecodeError::ShortRead)?;
@@ -245,7 +257,7 @@ impl<H: CustomOnionMessageHandler> ReadableArgs<(SharedSecret, &H)> for Payload<
245257
Ok(Payload::Receive {
246258
control_tlvs: ReceiveControlTlvs::Unblinded(tlvs),
247259
reply_path,
248-
message: OnionMessageContents::Custom(message.unwrap()),
260+
message: message.unwrap(),
249261
})
250262
}
251263
}

0 commit comments

Comments
 (0)