Merge pull request #3263 from TheBlueMatt/2024-08-bindings-om

Remove message type bound on `ResponseInstruction`
This commit is contained in:
Matt Corallo 2024-08-23 03:04:19 +00:00 committed by GitHub
commit 49dfa5a496
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 274 additions and 307 deletions

View file

@ -16,8 +16,8 @@ use lightning::onion_message::async_payments::{
AsyncPaymentsMessageHandler, HeldHtlcAvailable, ReleaseHeldHtlc, AsyncPaymentsMessageHandler, HeldHtlcAvailable, ReleaseHeldHtlc,
}; };
use lightning::onion_message::messenger::{ use lightning::onion_message::messenger::{
CustomOnionMessageHandler, Destination, MessageRouter, OnionMessagePath, OnionMessenger, CustomOnionMessageHandler, Destination, MessageRouter, MessageSendInstructions,
PendingOnionMessage, Responder, ResponseInstruction, OnionMessagePath, OnionMessenger, Responder, ResponseInstruction,
}; };
use lightning::onion_message::offers::{OffersMessage, OffersMessageHandler}; use lightning::onion_message::offers::{OffersMessage, OffersMessageHandler};
use lightning::onion_message::packet::OnionMessageContents; use lightning::onion_message::packet::OnionMessageContents;
@ -109,8 +109,8 @@ impl OffersMessageHandler for TestOffersMessageHandler {
fn handle_message( fn handle_message(
&self, _message: OffersMessage, _context: Option<OffersContext>, &self, _message: OffersMessage, _context: Option<OffersContext>,
_responder: Option<Responder>, _responder: Option<Responder>,
) -> ResponseInstruction<OffersMessage> { ) -> Option<(OffersMessage, ResponseInstruction)> {
ResponseInstruction::NoResponse None
} }
} }
@ -119,13 +119,15 @@ struct TestAsyncPaymentsMessageHandler {}
impl AsyncPaymentsMessageHandler for TestAsyncPaymentsMessageHandler { impl AsyncPaymentsMessageHandler for TestAsyncPaymentsMessageHandler {
fn held_htlc_available( fn held_htlc_available(
&self, message: HeldHtlcAvailable, responder: Option<Responder>, &self, message: HeldHtlcAvailable, responder: Option<Responder>,
) -> ResponseInstruction<ReleaseHeldHtlc> { ) -> Option<(ReleaseHeldHtlc, ResponseInstruction)> {
let responder = match responder { let responder = match responder {
Some(resp) => resp, Some(resp) => resp,
None => return ResponseInstruction::NoResponse, None => return None,
}; };
responder Some((
.respond(ReleaseHeldHtlc { payment_release_secret: message.payment_release_secret }) ReleaseHeldHtlc { payment_release_secret: message.payment_release_secret },
responder.respond(),
))
} }
fn release_held_htlc(&self, _message: ReleaseHeldHtlc) {} fn release_held_htlc(&self, _message: ReleaseHeldHtlc) {}
} }
@ -158,10 +160,10 @@ impl CustomOnionMessageHandler for TestCustomMessageHandler {
fn handle_custom_message( fn handle_custom_message(
&self, message: Self::CustomMessage, _context: Option<Vec<u8>>, &self, message: Self::CustomMessage, _context: Option<Vec<u8>>,
responder: Option<Responder>, responder: Option<Responder>,
) -> ResponseInstruction<Self::CustomMessage> { ) -> Option<(Self::CustomMessage, ResponseInstruction)> {
match responder { match responder {
Some(responder) => responder.respond(message), Some(responder) => Some((message, responder.respond())),
None => ResponseInstruction::NoResponse, None => None,
} }
} }
fn read_custom_message<R: io::Read>( fn read_custom_message<R: io::Read>(
@ -171,7 +173,7 @@ impl CustomOnionMessageHandler for TestCustomMessageHandler {
buffer.read_to_limit(&mut buf, u64::MAX)?; buffer.read_to_limit(&mut buf, u64::MAX)?;
return Ok(Some(TestCustomMessage {})); return Ok(Some(TestCustomMessage {}));
} }
fn release_pending_custom_messages(&self) -> Vec<PendingOnionMessage<Self::CustomMessage>> { fn release_pending_custom_messages(&self) -> Vec<(TestCustomMessage, MessageSendInstructions)> {
vec![] vec![]
} }
} }

View file

@ -71,7 +71,7 @@ use crate::offers::parse::Bolt12SemanticError;
use crate::offers::refund::{Refund, RefundBuilder}; use crate::offers::refund::{Refund, RefundBuilder};
use crate::offers::signer; use crate::offers::signer;
use crate::onion_message::async_payments::{AsyncPaymentsMessage, HeldHtlcAvailable, ReleaseHeldHtlc, AsyncPaymentsMessageHandler}; use crate::onion_message::async_payments::{AsyncPaymentsMessage, HeldHtlcAvailable, ReleaseHeldHtlc, AsyncPaymentsMessageHandler};
use crate::onion_message::messenger::{new_pending_onion_message, Destination, MessageRouter, PendingOnionMessage, Responder, ResponseInstruction}; use crate::onion_message::messenger::{Destination, MessageRouter, Responder, ResponseInstruction, MessageSendInstructions};
use crate::onion_message::offers::{OffersMessage, OffersMessageHandler}; use crate::onion_message::offers::{OffersMessage, OffersMessageHandler};
use crate::sign::{EntropySource, NodeSigner, Recipient, SignerProvider}; use crate::sign::{EntropySource, NodeSigner, Recipient, SignerProvider};
use crate::sign::ecdsa::EcdsaChannelSigner; use crate::sign::ecdsa::EcdsaChannelSigner;
@ -2277,9 +2277,9 @@ where
needs_persist_flag: AtomicBool, needs_persist_flag: AtomicBool,
#[cfg(not(any(test, feature = "_test_utils")))] #[cfg(not(any(test, feature = "_test_utils")))]
pending_offers_messages: Mutex<Vec<PendingOnionMessage<OffersMessage>>>, pending_offers_messages: Mutex<Vec<(OffersMessage, MessageSendInstructions)>>,
#[cfg(any(test, feature = "_test_utils"))] #[cfg(any(test, feature = "_test_utils"))]
pub(crate) pending_offers_messages: Mutex<Vec<PendingOnionMessage<OffersMessage>>>, pub(crate) pending_offers_messages: Mutex<Vec<(OffersMessage, MessageSendInstructions)>>,
/// Tracks the message events that are to be broadcasted when we are connected to some peer. /// Tracks the message events that are to be broadcasted when we are connected to some peer.
pending_broadcast_messages: Mutex<Vec<MessageSendEvent>>, pending_broadcast_messages: Mutex<Vec<MessageSendEvent>>,
@ -9068,21 +9068,21 @@ where
.flat_map(|reply_path| offer.paths().iter().map(move |path| (path, reply_path))) .flat_map(|reply_path| offer.paths().iter().map(move |path| (path, reply_path)))
.take(OFFERS_MESSAGE_REQUEST_LIMIT) .take(OFFERS_MESSAGE_REQUEST_LIMIT)
.for_each(|(path, reply_path)| { .for_each(|(path, reply_path)| {
let message = new_pending_onion_message( let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
OffersMessage::InvoiceRequest(invoice_request.clone()), destination: Destination::BlindedPath(path.clone()),
Destination::BlindedPath(path.clone()), reply_path: reply_path.clone(),
Some(reply_path.clone()), };
); let message = OffersMessage::InvoiceRequest(invoice_request.clone());
pending_offers_messages.push(message); pending_offers_messages.push((message, instructions));
}); });
} else if let Some(signing_pubkey) = offer.signing_pubkey() { } else if let Some(signing_pubkey) = offer.signing_pubkey() {
for reply_path in reply_paths { for reply_path in reply_paths {
let message = new_pending_onion_message( let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
OffersMessage::InvoiceRequest(invoice_request.clone()), destination: Destination::Node(signing_pubkey),
Destination::Node(signing_pubkey), reply_path,
Some(reply_path), };
); let message = OffersMessage::InvoiceRequest(invoice_request.clone());
pending_offers_messages.push(message); pending_offers_messages.push((message, instructions));
} }
} else { } else {
debug_assert!(false); debug_assert!(false);
@ -9162,12 +9162,12 @@ where
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap(); let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
if refund.paths().is_empty() { if refund.paths().is_empty() {
for reply_path in reply_paths { for reply_path in reply_paths {
let message = new_pending_onion_message( let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
OffersMessage::Invoice(invoice.clone()), destination: Destination::Node(refund.payer_id()),
Destination::Node(refund.payer_id()), reply_path,
Some(reply_path), };
); let message = OffersMessage::Invoice(invoice.clone());
pending_offers_messages.push(message); pending_offers_messages.push((message, instructions));
} }
} else { } else {
reply_paths reply_paths
@ -9175,12 +9175,12 @@ where
.flat_map(|reply_path| refund.paths().iter().map(move |path| (path, reply_path))) .flat_map(|reply_path| refund.paths().iter().map(move |path| (path, reply_path)))
.take(OFFERS_MESSAGE_REQUEST_LIMIT) .take(OFFERS_MESSAGE_REQUEST_LIMIT)
.for_each(|(path, reply_path)| { .for_each(|(path, reply_path)| {
let message = new_pending_onion_message( let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
OffersMessage::Invoice(invoice.clone()), destination: Destination::BlindedPath(path.clone()),
Destination::BlindedPath(path.clone()), reply_path: reply_path.clone(),
Some(reply_path.clone()), };
); let message = OffersMessage::Invoice(invoice.clone());
pending_offers_messages.push(message); pending_offers_messages.push((message, instructions));
}); });
} }
@ -10749,7 +10749,7 @@ where
{ {
fn handle_message( fn handle_message(
&self, message: OffersMessage, context: Option<OffersContext>, responder: Option<Responder>, &self, message: OffersMessage, context: Option<OffersContext>, responder: Option<Responder>,
) -> ResponseInstruction<OffersMessage> { ) -> Option<(OffersMessage, ResponseInstruction)> {
let secp_ctx = &self.secp_ctx; let secp_ctx = &self.secp_ctx;
let expanded_key = &self.inbound_payment_key; let expanded_key = &self.inbound_payment_key;
@ -10757,13 +10757,13 @@ where
OffersMessage::InvoiceRequest(invoice_request) => { OffersMessage::InvoiceRequest(invoice_request) => {
let responder = match responder { let responder = match responder {
Some(responder) => responder, Some(responder) => responder,
None => return ResponseInstruction::NoResponse, None => return None,
}; };
let nonce = match context { let nonce = match context {
None if invoice_request.metadata().is_some() => None, None if invoice_request.metadata().is_some() => None,
Some(OffersContext::InvoiceRequest { nonce }) => Some(nonce), Some(OffersContext::InvoiceRequest { nonce }) => Some(nonce),
_ => return ResponseInstruction::NoResponse, _ => return None,
}; };
let invoice_request = match nonce { let invoice_request = match nonce {
@ -10771,11 +10771,11 @@ where
nonce, expanded_key, secp_ctx, nonce, expanded_key, secp_ctx,
) { ) {
Ok(invoice_request) => invoice_request, Ok(invoice_request) => invoice_request,
Err(()) => return ResponseInstruction::NoResponse, Err(()) => return None,
}, },
None => match invoice_request.verify_using_metadata(expanded_key, secp_ctx) { None => match invoice_request.verify_using_metadata(expanded_key, secp_ctx) {
Ok(invoice_request) => invoice_request, Ok(invoice_request) => invoice_request,
Err(()) => return ResponseInstruction::NoResponse, Err(()) => return None,
}, },
}; };
@ -10783,7 +10783,7 @@ where
&invoice_request.inner &invoice_request.inner
) { ) {
Ok(amount_msats) => amount_msats, Ok(amount_msats) => amount_msats,
Err(error) => return responder.respond(OffersMessage::InvoiceError(error.into())), Err(error) => return Some((OffersMessage::InvoiceError(error.into()), responder.respond())),
}; };
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32; let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
@ -10793,7 +10793,7 @@ where
Ok((payment_hash, payment_secret)) => (payment_hash, payment_secret), Ok((payment_hash, payment_secret)) => (payment_hash, payment_secret),
Err(()) => { Err(()) => {
let error = Bolt12SemanticError::InvalidAmount; let error = Bolt12SemanticError::InvalidAmount;
return responder.respond(OffersMessage::InvoiceError(error.into())); return Some((OffersMessage::InvoiceError(error.into()), responder.respond()));
}, },
}; };
@ -10807,7 +10807,7 @@ where
Ok(payment_paths) => payment_paths, Ok(payment_paths) => payment_paths,
Err(()) => { Err(()) => {
let error = Bolt12SemanticError::MissingPaths; let error = Bolt12SemanticError::MissingPaths;
return responder.respond(OffersMessage::InvoiceError(error.into())); return Some((OffersMessage::InvoiceError(error.into()), responder.respond()));
}, },
}; };
@ -10852,14 +10852,14 @@ where
}; };
match response { match response {
Ok(invoice) => responder.respond(OffersMessage::Invoice(invoice)), Ok(invoice) => Some((OffersMessage::Invoice(invoice), responder.respond())),
Err(error) => responder.respond(OffersMessage::InvoiceError(error.into())), Err(error) => Some((OffersMessage::InvoiceError(error.into()), responder.respond())),
} }
}, },
OffersMessage::Invoice(invoice) => { OffersMessage::Invoice(invoice) => {
let payment_id = match self.verify_bolt12_invoice(&invoice, context.as_ref()) { let payment_id = match self.verify_bolt12_invoice(&invoice, context.as_ref()) {
Ok(payment_id) => payment_id, Ok(payment_id) => payment_id,
Err(()) => return ResponseInstruction::NoResponse, Err(()) => return None,
}; };
let logger = WithContext::from( let logger = WithContext::from(
@ -10871,7 +10871,7 @@ where
payment_id, invoice, context, responder, payment_id, invoice, context, responder,
}; };
self.pending_events.lock().unwrap().push_back((event, None)); self.pending_events.lock().unwrap().push_back((event, None));
return ResponseInstruction::NoResponse; return None;
} }
let error = match self.send_payment_for_verified_bolt12_invoice( let error = match self.send_payment_for_verified_bolt12_invoice(
@ -10890,14 +10890,14 @@ where
}, },
Err(Bolt12PaymentError::UnexpectedInvoice) Err(Bolt12PaymentError::UnexpectedInvoice)
| Err(Bolt12PaymentError::DuplicateInvoice) | Err(Bolt12PaymentError::DuplicateInvoice)
| Ok(()) => return ResponseInstruction::NoResponse, | Ok(()) => return None,
}; };
match responder { match responder {
Some(responder) => responder.respond(OffersMessage::InvoiceError(error)), Some(responder) => Some((OffersMessage::InvoiceError(error), responder.respond())),
None => { None => {
log_trace!(logger, "No reply path to send error: {:?}", error); log_trace!(logger, "No reply path to send error: {:?}", error);
ResponseInstruction::NoResponse None
}, },
} }
}, },
@ -10905,11 +10905,11 @@ where
OffersMessage::StaticInvoice(_invoice) => { OffersMessage::StaticInvoice(_invoice) => {
match responder { match responder {
Some(responder) => { Some(responder) => {
responder.respond(OffersMessage::InvoiceError( return Some((OffersMessage::InvoiceError(
InvoiceError::from_string("Static invoices not yet supported".to_string()) InvoiceError::from_string("Static invoices not yet supported".to_string())
)) ), responder.respond()));
}, },
None => return ResponseInstruction::NoResponse, None => return None,
} }
}, },
OffersMessage::InvoiceError(invoice_error) => { OffersMessage::InvoiceError(invoice_error) => {
@ -10932,12 +10932,12 @@ where
_ => {}, _ => {},
} }
ResponseInstruction::NoResponse None
}, },
} }
} }
fn release_pending_messages(&self) -> Vec<PendingOnionMessage<OffersMessage>> { fn release_pending_messages(&self) -> Vec<(OffersMessage, MessageSendInstructions)> {
core::mem::take(&mut self.pending_offers_messages.lock().unwrap()) core::mem::take(&mut self.pending_offers_messages.lock().unwrap())
} }
} }
@ -10956,13 +10956,13 @@ where
{ {
fn held_htlc_available( fn held_htlc_available(
&self, _message: HeldHtlcAvailable, _responder: Option<Responder> &self, _message: HeldHtlcAvailable, _responder: Option<Responder>
) -> ResponseInstruction<ReleaseHeldHtlc> { ) -> Option<(ReleaseHeldHtlc, ResponseInstruction)> {
ResponseInstruction::NoResponse None
} }
fn release_held_htlc(&self, _message: ReleaseHeldHtlc) {} fn release_held_htlc(&self, _message: ReleaseHeldHtlc) {}
fn release_pending_messages(&self) -> Vec<PendingOnionMessage<AsyncPaymentsMessage>> { fn release_pending_messages(&self) -> Vec<(AsyncPaymentsMessage, MessageSendInstructions)> {
Vec::new() Vec::new()
} }
} }

View file

@ -59,7 +59,7 @@ use crate::offers::invoice_error::InvoiceError;
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields}; use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields};
use crate::offers::nonce::Nonce; use crate::offers::nonce::Nonce;
use crate::offers::parse::Bolt12SemanticError; use crate::offers::parse::Bolt12SemanticError;
use crate::onion_message::messenger::{Destination, PeeledOnion, new_pending_onion_message}; use crate::onion_message::messenger::{Destination, PeeledOnion, MessageSendInstructions};
use crate::onion_message::offers::OffersMessage; use crate::onion_message::offers::OffersMessage;
use crate::onion_message::packet::ParsedOnionMessageContents; use crate::onion_message::packet::ParsedOnionMessageContents;
use crate::routing::gossip::{NodeAlias, NodeId}; use crate::routing::gossip::{NodeAlias, NodeId};
@ -1313,13 +1313,10 @@ fn fails_authentication_when_handling_invoice_request() {
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
connect_peers(david, alice); connect_peers(david, alice);
#[cfg(not(c_bindings))] { match &mut david.node.pending_offers_messages.lock().unwrap().first_mut().unwrap().1 {
david.node.pending_offers_messages.lock().unwrap().first_mut().unwrap().destination = MessageSendInstructions::WithSpecifiedReplyPath { destination, .. } =>
Destination::Node(alice_id); *destination = Destination::Node(alice_id),
} _ => panic!(),
#[cfg(c_bindings)] {
david.node.pending_offers_messages.lock().unwrap().first_mut().unwrap().1 =
Destination::Node(alice_id);
} }
let onion_message = david.onion_messenger.next_onion_message_for_peer(alice_id).unwrap(); let onion_message = david.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
@ -1341,13 +1338,10 @@ fn fails_authentication_when_handling_invoice_request() {
.unwrap(); .unwrap();
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id); expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
#[cfg(not(c_bindings))] { match &mut david.node.pending_offers_messages.lock().unwrap().first_mut().unwrap().1 {
david.node.pending_offers_messages.lock().unwrap().first_mut().unwrap().destination = MessageSendInstructions::WithSpecifiedReplyPath { destination, .. } =>
Destination::BlindedPath(invalid_path); *destination = Destination::BlindedPath(invalid_path),
} _ => panic!(),
#[cfg(c_bindings)] {
david.node.pending_offers_messages.lock().unwrap().first_mut().unwrap().1 =
Destination::BlindedPath(invalid_path);
} }
connect_peers(david, bob); connect_peers(david, bob);
@ -1427,11 +1421,9 @@ fn fails_authentication_when_handling_invoice_for_offer() {
let mut pending_offers_messages = david.node.pending_offers_messages.lock().unwrap(); let mut pending_offers_messages = david.node.pending_offers_messages.lock().unwrap();
let pending_invoice_request = pending_offers_messages.pop().unwrap(); let pending_invoice_request = pending_offers_messages.pop().unwrap();
pending_offers_messages.clear(); pending_offers_messages.clear();
#[cfg(not(c_bindings))] { match pending_invoice_request.1 {
pending_invoice_request.reply_path MessageSendInstructions::WithSpecifiedReplyPath { reply_path, .. } => reply_path,
} _ => panic!(),
#[cfg(c_bindings)] {
pending_invoice_request.2
} }
}; };
@ -1445,11 +1437,10 @@ fn fails_authentication_when_handling_invoice_for_offer() {
{ {
let mut pending_offers_messages = david.node.pending_offers_messages.lock().unwrap(); let mut pending_offers_messages = david.node.pending_offers_messages.lock().unwrap();
let mut pending_invoice_request = pending_offers_messages.first_mut().unwrap(); let mut pending_invoice_request = pending_offers_messages.first_mut().unwrap();
#[cfg(not(c_bindings))] { match &mut pending_invoice_request.1 {
pending_invoice_request.reply_path = invalid_reply_path; MessageSendInstructions::WithSpecifiedReplyPath { reply_path, .. } =>
} *reply_path = invalid_reply_path,
#[cfg(c_bindings)] { _ => panic!(),
pending_invoice_request.2 = invalid_reply_path;
} }
} }
@ -1531,13 +1522,10 @@ fn fails_authentication_when_handling_invoice_for_refund() {
let expected_invoice = alice.node.request_refund_payment(&refund).unwrap(); let expected_invoice = alice.node.request_refund_payment(&refund).unwrap();
connect_peers(david, alice); connect_peers(david, alice);
#[cfg(not(c_bindings))] { match &mut alice.node.pending_offers_messages.lock().unwrap().first_mut().unwrap().1 {
alice.node.pending_offers_messages.lock().unwrap().first_mut().unwrap().destination = MessageSendInstructions::WithSpecifiedReplyPath { destination, .. } =>
Destination::Node(david_id); *destination = Destination::Node(david_id),
} _ => panic!(),
#[cfg(c_bindings)] {
alice.node.pending_offers_messages.lock().unwrap().first_mut().unwrap().1 =
Destination::Node(david_id);
} }
let onion_message = alice.onion_messenger.next_onion_message_for_peer(david_id).unwrap(); let onion_message = alice.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
@ -1565,13 +1553,10 @@ fn fails_authentication_when_handling_invoice_for_refund() {
let expected_invoice = alice.node.request_refund_payment(&refund).unwrap(); let expected_invoice = alice.node.request_refund_payment(&refund).unwrap();
#[cfg(not(c_bindings))] { match &mut alice.node.pending_offers_messages.lock().unwrap().first_mut().unwrap().1 {
alice.node.pending_offers_messages.lock().unwrap().first_mut().unwrap().destination = MessageSendInstructions::WithSpecifiedReplyPath { destination, .. } =>
Destination::BlindedPath(invalid_path); *destination = Destination::BlindedPath(invalid_path),
} _ => panic!(),
#[cfg(c_bindings)] {
alice.node.pending_offers_messages.lock().unwrap().first_mut().unwrap().1 =
Destination::BlindedPath(invalid_path);
} }
connect_peers(alice, charlie); connect_peers(alice, charlie);
@ -2155,10 +2140,11 @@ fn fails_paying_invoice_with_unknown_required_features() {
.build_and_sign(&secp_ctx).unwrap(); .build_and_sign(&secp_ctx).unwrap();
// Enqueue an onion message containing the new invoice. // Enqueue an onion message containing the new invoice.
let pending_message = new_pending_onion_message( let instructions = MessageSendInstructions::WithoutReplyPath {
OffersMessage::Invoice(invoice), Destination::BlindedPath(reply_path), None destination: Destination::BlindedPath(reply_path),
); };
alice.node.pending_offers_messages.lock().unwrap().push(pending_message); let message = OffersMessage::Invoice(invoice);
alice.node.pending_offers_messages.lock().unwrap().push((message, instructions));
let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap(); let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap();
charlie.onion_messenger.handle_onion_message(&alice_id, &onion_message); charlie.onion_messenger.handle_onion_message(&alice_id, &onion_message);

View file

@ -30,7 +30,7 @@ use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor, NextNoiseStep, Mes
use crate::ln::wire; use crate::ln::wire;
use crate::ln::wire::{Encode, Type}; use crate::ln::wire::{Encode, Type};
use crate::onion_message::async_payments::{AsyncPaymentsMessageHandler, HeldHtlcAvailable, ReleaseHeldHtlc}; use crate::onion_message::async_payments::{AsyncPaymentsMessageHandler, HeldHtlcAvailable, ReleaseHeldHtlc};
use crate::onion_message::messenger::{CustomOnionMessageHandler, PendingOnionMessage, Responder, ResponseInstruction}; use crate::onion_message::messenger::{CustomOnionMessageHandler, Responder, ResponseInstruction, MessageSendInstructions};
use crate::onion_message::offers::{OffersMessage, OffersMessageHandler}; use crate::onion_message::offers::{OffersMessage, OffersMessageHandler};
use crate::onion_message::packet::OnionMessageContents; use crate::onion_message::packet::OnionMessageContents;
use crate::routing::gossip::{NodeId, NodeAlias}; use crate::routing::gossip::{NodeId, NodeAlias};
@ -142,28 +142,28 @@ impl OnionMessageHandler for IgnoringMessageHandler {
} }
impl OffersMessageHandler for IgnoringMessageHandler { impl OffersMessageHandler for IgnoringMessageHandler {
fn handle_message(&self, _message: OffersMessage, _context: Option<OffersContext>, _responder: Option<Responder>) -> ResponseInstruction<OffersMessage> { fn handle_message(&self, _message: OffersMessage, _context: Option<OffersContext>, _responder: Option<Responder>) -> Option<(OffersMessage, ResponseInstruction)> {
ResponseInstruction::NoResponse None
} }
} }
impl AsyncPaymentsMessageHandler for IgnoringMessageHandler { impl AsyncPaymentsMessageHandler for IgnoringMessageHandler {
fn held_htlc_available( fn held_htlc_available(
&self, _message: HeldHtlcAvailable, _responder: Option<Responder>, &self, _message: HeldHtlcAvailable, _responder: Option<Responder>,
) -> ResponseInstruction<ReleaseHeldHtlc> { ) -> Option<(ReleaseHeldHtlc, ResponseInstruction)> {
ResponseInstruction::NoResponse None
} }
fn release_held_htlc(&self, _message: ReleaseHeldHtlc) {} fn release_held_htlc(&self, _message: ReleaseHeldHtlc) {}
} }
impl CustomOnionMessageHandler for IgnoringMessageHandler { impl CustomOnionMessageHandler for IgnoringMessageHandler {
type CustomMessage = Infallible; type CustomMessage = Infallible;
fn handle_custom_message(&self, _message: Self::CustomMessage, _context: Option<Vec<u8>>, _responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage> { fn handle_custom_message(&self, _message: Self::CustomMessage, _context: Option<Vec<u8>>, _responder: Option<Responder>) -> Option<(Infallible, ResponseInstruction)> {
// Since we always return `None` in the read the handle method should never be called. // Since we always return `None` in the read the handle method should never be called.
unreachable!(); unreachable!();
} }
fn read_custom_message<R: io::Read>(&self, _msg_type: u64, _buffer: &mut R) -> Result<Option<Infallible>, msgs::DecodeError> where Self: Sized { fn read_custom_message<R: io::Read>(&self, _msg_type: u64, _buffer: &mut R) -> Result<Option<Infallible>, msgs::DecodeError> where Self: Sized {
Ok(None) Ok(None)
} }
fn release_pending_custom_messages(&self) -> Vec<PendingOnionMessage<Infallible>> { fn release_pending_custom_messages(&self) -> Vec<(Infallible, MessageSendInstructions)> {
vec![] vec![]
} }
} }

View file

@ -11,9 +11,7 @@
use crate::io; use crate::io;
use crate::ln::msgs::DecodeError; use crate::ln::msgs::DecodeError;
#[cfg(not(c_bindings))] use crate::onion_message::messenger::{MessageSendInstructions, Responder, ResponseInstruction};
use crate::onion_message::messenger::PendingOnionMessage;
use crate::onion_message::messenger::{Responder, ResponseInstruction};
use crate::onion_message::packet::OnionMessageContents; use crate::onion_message::packet::OnionMessageContents;
use crate::prelude::*; use crate::prelude::*;
use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer}; use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer};
@ -30,7 +28,7 @@ pub trait AsyncPaymentsMessageHandler {
/// the held funds. /// the held funds.
fn held_htlc_available( fn held_htlc_available(
&self, message: HeldHtlcAvailable, responder: Option<Responder>, &self, message: HeldHtlcAvailable, responder: Option<Responder>,
) -> ResponseInstruction<ReleaseHeldHtlc>; ) -> Option<(ReleaseHeldHtlc, ResponseInstruction)>;
/// Handle a [`ReleaseHeldHtlc`] message. If authentication of the message succeeds, an HTLC /// Handle a [`ReleaseHeldHtlc`] message. If authentication of the message succeeds, an HTLC
/// should be released to the corresponding payee. /// should be released to the corresponding payee.
@ -40,23 +38,7 @@ pub trait AsyncPaymentsMessageHandler {
/// ///
/// Typically, this is used for messages initiating an async payment flow rather than in response /// Typically, this is used for messages initiating an async payment flow rather than in response
/// to another message. /// to another message.
#[cfg(not(c_bindings))] fn release_pending_messages(&self) -> Vec<(AsyncPaymentsMessage, MessageSendInstructions)> {
fn release_pending_messages(&self) -> Vec<PendingOnionMessage<AsyncPaymentsMessage>> {
vec![]
}
/// Release any [`AsyncPaymentsMessage`]s that need to be sent.
///
/// Typically, this is used for messages initiating a payment flow rather than in response to
/// another message.
#[cfg(c_bindings)]
fn release_pending_messages(
&self,
) -> Vec<(
AsyncPaymentsMessage,
crate::onion_message::messenger::Destination,
Option<crate::blinded_path::message::BlindedMessagePath>,
)> {
vec![] vec![]
} }
} }

View file

@ -20,7 +20,7 @@ use crate::sign::{NodeSigner, Recipient};
use crate::util::ser::{FixedLengthReader, LengthReadable, Writeable, Writer}; use crate::util::ser::{FixedLengthReader, LengthReadable, Writeable, Writer};
use crate::util::test_utils; use crate::util::test_utils;
use super::async_payments::{AsyncPaymentsMessageHandler, HeldHtlcAvailable, ReleaseHeldHtlc}; use super::async_payments::{AsyncPaymentsMessageHandler, HeldHtlcAvailable, ReleaseHeldHtlc};
use super::messenger::{CustomOnionMessageHandler, DefaultMessageRouter, Destination, OnionMessagePath, OnionMessenger, PendingOnionMessage, Responder, ResponseInstruction, SendError, SendSuccess}; use super::messenger::{CustomOnionMessageHandler, DefaultMessageRouter, Destination, OnionMessagePath, OnionMessenger, Responder, ResponseInstruction, MessageSendInstructions, SendError, SendSuccess};
use super::offers::{OffersMessage, OffersMessageHandler}; use super::offers::{OffersMessage, OffersMessageHandler};
use super::packet::{OnionMessageContents, Packet}; use super::packet::{OnionMessageContents, Packet};
@ -74,8 +74,8 @@ impl Drop for MessengerNode {
struct TestOffersMessageHandler {} struct TestOffersMessageHandler {}
impl OffersMessageHandler for TestOffersMessageHandler { impl OffersMessageHandler for TestOffersMessageHandler {
fn handle_message(&self, _message: OffersMessage, _context: Option<OffersContext>, _responder: Option<Responder>) -> ResponseInstruction<OffersMessage> { fn handle_message(&self, _message: OffersMessage, _context: Option<OffersContext>, _responder: Option<Responder>) -> Option<(OffersMessage, ResponseInstruction)> {
ResponseInstruction::NoResponse None
} }
} }
@ -84,8 +84,8 @@ struct TestAsyncPaymentsMessageHandler {}
impl AsyncPaymentsMessageHandler for TestAsyncPaymentsMessageHandler { impl AsyncPaymentsMessageHandler for TestAsyncPaymentsMessageHandler {
fn held_htlc_available( fn held_htlc_available(
&self, _message: HeldHtlcAvailable, _responder: Option<Responder>, &self, _message: HeldHtlcAvailable, _responder: Option<Responder>,
) -> ResponseInstruction<ReleaseHeldHtlc> { ) -> Option<(ReleaseHeldHtlc, ResponseInstruction)> {
ResponseInstruction::NoResponse None
} }
fn release_held_htlc(&self, _message: ReleaseHeldHtlc) {} fn release_held_htlc(&self, _message: ReleaseHeldHtlc) {}
} }
@ -170,7 +170,7 @@ impl Drop for TestCustomMessageHandler {
impl CustomOnionMessageHandler for TestCustomMessageHandler { impl CustomOnionMessageHandler for TestCustomMessageHandler {
type CustomMessage = TestCustomMessage; type CustomMessage = TestCustomMessage;
fn handle_custom_message(&self, msg: Self::CustomMessage, context: Option<Vec<u8>>, responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage> { fn handle_custom_message(&self, msg: Self::CustomMessage, context: Option<Vec<u8>>, responder: Option<Responder>) -> Option<(Self::CustomMessage, ResponseInstruction)> {
let expectation = self.get_next_expectation(); let expectation = self.get_next_expectation();
assert_eq!(msg, expectation.expect); assert_eq!(msg, expectation.expect);
@ -186,10 +186,10 @@ impl CustomOnionMessageHandler for TestCustomMessageHandler {
match responder { match responder {
Some(responder) if expectation.include_reply_path => { Some(responder) if expectation.include_reply_path => {
responder.respond_with_reply_path(response, MessageContext::Custom(context.unwrap_or_else(Vec::new))) Some((response, responder.respond_with_reply_path(MessageContext::Custom(context.unwrap_or_else(Vec::new)))))
}, },
Some(responder) => responder.respond(response), Some(responder) => Some((response, responder.respond())),
None => ResponseInstruction::NoResponse, None => None
} }
} }
fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, DecodeError> where Self: Sized { fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, DecodeError> where Self: Sized {
@ -207,7 +207,7 @@ impl CustomOnionMessageHandler for TestCustomMessageHandler {
_ => Ok(None), _ => Ok(None),
} }
} }
fn release_pending_custom_messages(&self) -> Vec<PendingOnionMessage<Self::CustomMessage>> { fn release_pending_custom_messages(&self) -> Vec<(Self::CustomMessage, MessageSendInstructions)> {
vec![] vec![]
} }
} }
@ -341,7 +341,8 @@ fn one_unblinded_hop() {
let test_msg = TestCustomMessage::Pong; let test_msg = TestCustomMessage::Pong;
let destination = Destination::Node(nodes[1].node_id); let destination = Destination::Node(nodes[1].node_id);
nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap(); let instructions = MessageSendInstructions::WithoutReplyPath { destination };
nodes[0].messenger.send_onion_message(test_msg, instructions).unwrap();
nodes[1].custom_message_handler.expect_message(TestCustomMessage::Pong); nodes[1].custom_message_handler.expect_message(TestCustomMessage::Pong);
pass_along_path(&nodes); pass_along_path(&nodes);
} }
@ -371,7 +372,8 @@ fn one_blinded_hop() {
let context = MessageContext::Custom(Vec::new()); let context = MessageContext::Custom(Vec::new());
let blinded_path = BlindedMessagePath::new(&[], nodes[1].node_id, context, &*nodes[1].entropy_source, &secp_ctx).unwrap(); let blinded_path = BlindedMessagePath::new(&[], nodes[1].node_id, context, &*nodes[1].entropy_source, &secp_ctx).unwrap();
let destination = Destination::BlindedPath(blinded_path); let destination = Destination::BlindedPath(blinded_path);
nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap(); let instructions = MessageSendInstructions::WithoutReplyPath { destination };
nodes[0].messenger.send_onion_message(test_msg, instructions).unwrap();
nodes[1].custom_message_handler.expect_message(TestCustomMessage::Pong); nodes[1].custom_message_handler.expect_message(TestCustomMessage::Pong);
pass_along_path(&nodes); pass_along_path(&nodes);
} }
@ -409,8 +411,9 @@ fn three_blinded_hops() {
let context = MessageContext::Custom(Vec::new()); let context = MessageContext::Custom(Vec::new());
let blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[3].node_id, context, &*nodes[3].entropy_source, &secp_ctx).unwrap(); let blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[3].node_id, context, &*nodes[3].entropy_source, &secp_ctx).unwrap();
let destination = Destination::BlindedPath(blinded_path); let destination = Destination::BlindedPath(blinded_path);
let instructions = MessageSendInstructions::WithoutReplyPath { destination };
nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap(); nodes[0].messenger.send_onion_message(test_msg, instructions).unwrap();
nodes[3].custom_message_handler.expect_message(TestCustomMessage::Pong); nodes[3].custom_message_handler.expect_message(TestCustomMessage::Pong);
pass_along_path(&nodes); pass_along_path(&nodes);
} }
@ -440,9 +443,10 @@ fn async_response_over_one_blinded_hop() {
let response_instruction = nodes[0].custom_message_handler.handle_custom_message(message, None, responder); let response_instruction = nodes[0].custom_message_handler.handle_custom_message(message, None, responder);
// 6. Simulate Alice asynchronously responding back to Bob with a response. // 6. Simulate Alice asynchronously responding back to Bob with a response.
let (msg, instructions) = response_instruction.unwrap();
assert_eq!( assert_eq!(
nodes[0].messenger.handle_onion_message_response(response_instruction), nodes[0].messenger.handle_onion_message_response(msg, instructions),
Ok(Some(SendSuccess::Buffered)), Ok(SendSuccess::Buffered),
); );
bob.custom_message_handler.expect_message(TestCustomMessage::Pong); bob.custom_message_handler.expect_message(TestCustomMessage::Pong);
@ -473,9 +477,10 @@ fn async_response_with_reply_path_succeeds() {
alice.custom_message_handler.expect_message_and_response(message.clone()); alice.custom_message_handler.expect_message_and_response(message.clone());
let response_instruction = alice.custom_message_handler.handle_custom_message(message, None, Some(responder)); let response_instruction = alice.custom_message_handler.handle_custom_message(message, None, Some(responder));
let (msg, instructions) = response_instruction.unwrap();
assert_eq!( assert_eq!(
alice.messenger.handle_onion_message_response(response_instruction), alice.messenger.handle_onion_message_response(msg, instructions),
Ok(Some(SendSuccess::Buffered)), Ok(SendSuccess::Buffered),
); );
// Set Bob's expectation and pass the Onion Message along the path. // Set Bob's expectation and pass the Onion Message along the path.
@ -512,8 +517,9 @@ fn async_response_with_reply_path_fails() {
alice.custom_message_handler.expect_message_and_response(message.clone()); alice.custom_message_handler.expect_message_and_response(message.clone());
let response_instruction = alice.custom_message_handler.handle_custom_message(message, None, Some(responder)); let response_instruction = alice.custom_message_handler.handle_custom_message(message, None, Some(responder));
let (msg, instructions) = response_instruction.unwrap();
assert_eq!( assert_eq!(
alice.messenger.handle_onion_message_response(response_instruction), alice.messenger.handle_onion_message_response(msg, instructions),
Err(SendError::PathNotFound), Err(SendError::PathNotFound),
); );
} }
@ -550,8 +556,9 @@ fn we_are_intro_node() {
let context = MessageContext::Custom(Vec::new()); let context = MessageContext::Custom(Vec::new());
let blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[2].node_id, context, &*nodes[2].entropy_source, &secp_ctx).unwrap(); let blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[2].node_id, context, &*nodes[2].entropy_source, &secp_ctx).unwrap();
let destination = Destination::BlindedPath(blinded_path); let destination = Destination::BlindedPath(blinded_path);
let instructions = MessageSendInstructions::WithoutReplyPath { destination };
nodes[0].messenger.send_onion_message(test_msg.clone(), destination, None).unwrap(); nodes[0].messenger.send_onion_message(test_msg.clone(), instructions).unwrap();
nodes[2].custom_message_handler.expect_message(TestCustomMessage::Pong); nodes[2].custom_message_handler.expect_message(TestCustomMessage::Pong);
pass_along_path(&nodes); pass_along_path(&nodes);
@ -560,7 +567,9 @@ fn we_are_intro_node() {
let context = MessageContext::Custom(Vec::new()); let context = MessageContext::Custom(Vec::new());
let blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[1].node_id, context, &*nodes[1].entropy_source, &secp_ctx).unwrap(); let blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[1].node_id, context, &*nodes[1].entropy_source, &secp_ctx).unwrap();
let destination = Destination::BlindedPath(blinded_path); let destination = Destination::BlindedPath(blinded_path);
nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap(); let instructions = MessageSendInstructions::WithoutReplyPath { destination };
nodes[0].messenger.send_onion_message(test_msg, instructions).unwrap();
nodes[1].custom_message_handler.expect_message(TestCustomMessage::Pong); nodes[1].custom_message_handler.expect_message(TestCustomMessage::Pong);
nodes.remove(2); nodes.remove(2);
pass_along_path(&nodes); pass_along_path(&nodes);
@ -578,7 +587,9 @@ fn invalid_blinded_path_error() {
let mut blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[2].node_id, context, &*nodes[2].entropy_source, &secp_ctx).unwrap(); let mut blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[2].node_id, context, &*nodes[2].entropy_source, &secp_ctx).unwrap();
blinded_path.clear_blinded_hops(); blinded_path.clear_blinded_hops();
let destination = Destination::BlindedPath(blinded_path); let destination = Destination::BlindedPath(blinded_path);
let err = nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap_err(); let instructions = MessageSendInstructions::WithoutReplyPath { destination };
let err = nodes[0].messenger.send_onion_message(test_msg, instructions).unwrap_err();
assert_eq!(err, SendError::TooFewBlindedHops); assert_eq!(err, SendError::TooFewBlindedHops);
} }
@ -622,8 +633,9 @@ fn reply_path() {
]; ];
let context = MessageContext::Custom(Vec::new()); let context = MessageContext::Custom(Vec::new());
let reply_path = BlindedMessagePath::new(&intermediate_nodes, nodes[0].node_id, context, &*nodes[0].entropy_source, &secp_ctx).unwrap(); let reply_path = BlindedMessagePath::new(&intermediate_nodes, nodes[0].node_id, context, &*nodes[0].entropy_source, &secp_ctx).unwrap();
let instructions = MessageSendInstructions::WithSpecifiedReplyPath { destination, reply_path };
nodes[0].messenger.send_onion_message(test_msg, destination, Some(reply_path)).unwrap(); nodes[0].messenger.send_onion_message(test_msg, instructions).unwrap();
nodes[3].custom_message_handler.expect_message(TestCustomMessage::Ping); nodes[3].custom_message_handler.expect_message(TestCustomMessage::Ping);
pass_along_path(&nodes); pass_along_path(&nodes);
@ -655,7 +667,9 @@ fn invalid_custom_message_type() {
let test_msg = InvalidCustomMessage {}; let test_msg = InvalidCustomMessage {};
let destination = Destination::Node(nodes[1].node_id); let destination = Destination::Node(nodes[1].node_id);
let err = nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap_err(); let instructions = MessageSendInstructions::WithoutReplyPath { destination };
let err = nodes[0].messenger.send_onion_message(test_msg, instructions).unwrap_err();
assert_eq!(err, SendError::InvalidMessage); assert_eq!(err, SendError::InvalidMessage);
} }
@ -664,10 +678,12 @@ fn peer_buffer_full() {
let nodes = create_nodes(2); let nodes = create_nodes(2);
let test_msg = TestCustomMessage::Ping; let test_msg = TestCustomMessage::Ping;
let destination = Destination::Node(nodes[1].node_id); let destination = Destination::Node(nodes[1].node_id);
let instructions = MessageSendInstructions::WithoutReplyPath { destination };
for _ in 0..188 { // Based on MAX_PER_PEER_BUFFER_SIZE in OnionMessenger for _ in 0..188 { // Based on MAX_PER_PEER_BUFFER_SIZE in OnionMessenger
nodes[0].messenger.send_onion_message(test_msg.clone(), destination.clone(), None).unwrap(); nodes[0].messenger.send_onion_message(test_msg.clone(), instructions.clone()).unwrap();
} }
let err = nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap_err(); let err = nodes[0].messenger.send_onion_message(test_msg, instructions.clone()).unwrap_err();
assert_eq!(err, SendError::BufferFull); assert_eq!(err, SendError::BufferFull);
} }
@ -707,9 +723,10 @@ fn requests_peer_connection_for_buffered_messages() {
&intermediate_nodes, nodes[2].node_id, context, &*nodes[0].entropy_source, &secp_ctx &intermediate_nodes, nodes[2].node_id, context, &*nodes[0].entropy_source, &secp_ctx
).unwrap(); ).unwrap();
let destination = Destination::BlindedPath(blinded_path); let destination = Destination::BlindedPath(blinded_path);
let instructions = MessageSendInstructions::WithoutReplyPath { destination };
// Buffer an onion message for a connected peer // Buffer an onion message for a connected peer
nodes[0].messenger.send_onion_message(message.clone(), destination.clone(), None).unwrap(); nodes[0].messenger.send_onion_message(message.clone(), instructions.clone()).unwrap();
assert!(release_events(&nodes[0]).is_empty()); assert!(release_events(&nodes[0]).is_empty());
assert!(nodes[0].messenger.next_onion_message_for_peer(nodes[1].node_id).is_some()); assert!(nodes[0].messenger.next_onion_message_for_peer(nodes[1].node_id).is_some());
assert!(nodes[0].messenger.next_onion_message_for_peer(nodes[1].node_id).is_none()); assert!(nodes[0].messenger.next_onion_message_for_peer(nodes[1].node_id).is_none());
@ -717,7 +734,7 @@ fn requests_peer_connection_for_buffered_messages() {
// Buffer an onion message for a disconnected peer // Buffer an onion message for a disconnected peer
disconnect_peers(&nodes[0], &nodes[1]); disconnect_peers(&nodes[0], &nodes[1]);
assert!(nodes[0].messenger.next_onion_message_for_peer(nodes[1].node_id).is_none()); assert!(nodes[0].messenger.next_onion_message_for_peer(nodes[1].node_id).is_none());
nodes[0].messenger.send_onion_message(message, destination, None).unwrap(); nodes[0].messenger.send_onion_message(message, instructions).unwrap();
// Check that a ConnectionNeeded event for the peer is provided // Check that a ConnectionNeeded event for the peer is provided
let events = release_events(&nodes[0]); let events = release_events(&nodes[0]);
@ -746,10 +763,11 @@ fn drops_buffered_messages_waiting_for_peer_connection() {
&intermediate_nodes, nodes[2].node_id, context, &*nodes[0].entropy_source, &secp_ctx &intermediate_nodes, nodes[2].node_id, context, &*nodes[0].entropy_source, &secp_ctx
).unwrap(); ).unwrap();
let destination = Destination::BlindedPath(blinded_path); let destination = Destination::BlindedPath(blinded_path);
let instructions = MessageSendInstructions::WithoutReplyPath { destination };
// Buffer an onion message for a disconnected peer // Buffer an onion message for a disconnected peer
disconnect_peers(&nodes[0], &nodes[1]); disconnect_peers(&nodes[0], &nodes[1]);
nodes[0].messenger.send_onion_message(message, destination, None).unwrap(); nodes[0].messenger.send_onion_message(message, instructions).unwrap();
// Release the event so the timer can start ticking // Release the event so the timer can start ticking
let events = release_events(&nodes[0]); let events = release_events(&nodes[0]);
@ -797,10 +815,11 @@ fn intercept_offline_peer_oms() {
&intermediate_nodes, nodes[2].node_id, context, &*nodes[2].entropy_source, &secp_ctx &intermediate_nodes, nodes[2].node_id, context, &*nodes[2].entropy_source, &secp_ctx
).unwrap(); ).unwrap();
let destination = Destination::BlindedPath(blinded_path); let destination = Destination::BlindedPath(blinded_path);
let instructions = MessageSendInstructions::WithoutReplyPath { destination };
// Disconnect the peers to ensure we intercept the OM. // Disconnect the peers to ensure we intercept the OM.
disconnect_peers(&nodes[1], &nodes[2]); disconnect_peers(&nodes[1], &nodes[2]);
nodes[0].messenger.send_onion_message(message, destination, None).unwrap(); nodes[0].messenger.send_onion_message(message, instructions).unwrap();
let mut final_node_vec = nodes.split_off(2); let mut final_node_vec = nodes.split_off(2);
pass_along_path(&nodes); pass_along_path(&nodes);

View file

@ -151,7 +151,7 @@ for OnionMessenger<ES, NS, L, NL, MR, OMH, APH, CMH> where
/// # use lightning::blinded_path::message::{BlindedMessagePath, MessageForwardNode, MessageContext}; /// # use lightning::blinded_path::message::{BlindedMessagePath, MessageForwardNode, MessageContext};
/// # use lightning::sign::{EntropySource, KeysManager}; /// # use lightning::sign::{EntropySource, KeysManager};
/// # use lightning::ln::peer_handler::IgnoringMessageHandler; /// # use lightning::ln::peer_handler::IgnoringMessageHandler;
/// # use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath, OnionMessenger}; /// # use lightning::onion_message::messenger::{Destination, MessageRouter, MessageSendInstructions, OnionMessagePath, OnionMessenger};
/// # use lightning::onion_message::packet::OnionMessageContents; /// # use lightning::onion_message::packet::OnionMessageContents;
/// # use lightning::util::logger::{Logger, Record}; /// # use lightning::util::logger::{Logger, Record};
/// # use lightning::util::ser::{Writeable, Writer}; /// # use lightning::util::ser::{Writeable, Writer};
@ -218,9 +218,9 @@ for OnionMessenger<ES, NS, L, NL, MR, OMH, APH, CMH> where
/// } /// }
/// // Send a custom onion message to a node id. /// // Send a custom onion message to a node id.
/// let destination = Destination::Node(destination_node_id); /// let destination = Destination::Node(destination_node_id);
/// let reply_path = None; /// let instructions = MessageSendInstructions::WithoutReplyPath { destination };
/// # let message = YourCustomMessage {}; /// # let message = YourCustomMessage {};
/// onion_messenger.send_onion_message(message, destination, reply_path); /// onion_messenger.send_onion_message(message, instructions);
/// ///
/// // Create a blinded path to yourself, for someone to send an onion message to. /// // Create a blinded path to yourself, for someone to send an onion message to.
/// # let your_node_id = hop_node_id1; /// # let your_node_id = hop_node_id1;
@ -233,9 +233,9 @@ for OnionMessenger<ES, NS, L, NL, MR, OMH, APH, CMH> where
/// ///
/// // Send a custom onion message to a blinded path. /// // Send a custom onion message to a blinded path.
/// let destination = Destination::BlindedPath(blinded_path); /// let destination = Destination::BlindedPath(blinded_path);
/// let reply_path = None; /// let instructions = MessageSendInstructions::WithoutReplyPath { destination };
/// # let message = YourCustomMessage {}; /// # let message = YourCustomMessage {};
/// onion_messenger.send_onion_message(message, destination, reply_path); /// onion_messenger.send_onion_message(message, instructions);
/// ``` /// ```
/// ///
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
@ -342,8 +342,8 @@ impl OnionMessageRecipient {
} }
/// The `Responder` struct creates an appropriate [`ResponseInstruction`] /// The `Responder` struct creates an appropriate [`ResponseInstruction`] for responding to a
/// for responding to a message. /// message.
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Responder { pub struct Responder {
/// The path along which a response can be sent. /// The path along which a response can be sent.
@ -362,75 +362,74 @@ impl Responder {
} }
} }
/// Creates a [`ResponseInstruction::WithoutReplyPath`] for a given response. /// Creates a [`ResponseInstruction`] for responding without including a reply path.
/// ///
/// Use when the recipient doesn't need to send back a reply to us. /// Use when the recipient doesn't need to send back a reply to us.
pub fn respond<T: OnionMessageContents>(self, response: T) -> ResponseInstruction<T> { pub fn respond(self) -> ResponseInstruction {
ResponseInstruction::WithoutReplyPath(OnionMessageResponse { ResponseInstruction {
message: response, destination: Destination::BlindedPath(self.reply_path),
reply_path: self.reply_path, context: None,
}) }
} }
/// Creates a [`ResponseInstruction::WithReplyPath`] for a given response. /// Creates a [`ResponseInstruction`] for responding including a reply path.
/// ///
/// Use when the recipient needs to send back a reply to us. /// Use when the recipient needs to send back a reply to us.
pub fn respond_with_reply_path<T: OnionMessageContents>(self, response: T, context: MessageContext) -> ResponseInstruction<T> { pub fn respond_with_reply_path(self, context: MessageContext) -> ResponseInstruction {
ResponseInstruction::WithReplyPath(OnionMessageResponse { ResponseInstruction {
message: response, destination: Destination::BlindedPath(self.reply_path),
reply_path: self.reply_path, context: Some(context),
}, context) }
} }
} }
/// This struct contains the information needed to reply to a received message. /// Instructions for how and where to send the response to an onion message.
pub struct OnionMessageResponse<T: OnionMessageContents> { #[derive(Clone)]
message: T, pub struct ResponseInstruction {
/// The destination in a response is always a [`Destination::BlindedPath`] but using a
/// [`Destination`] rather than an explicit [`BlindedMessagePath`] simplifies the logic in
/// [`OnionMessenger::send_onion_message_internal`] somewhat.
destination: Destination,
context: Option<MessageContext>,
}
impl ResponseInstruction {
fn into_instructions(self) -> MessageSendInstructions {
MessageSendInstructions::ForReply { instructions: self }
}
}
/// Instructions for how and where to send a message.
#[derive(Clone)]
pub enum MessageSendInstructions {
/// Indicates that a message should be sent including the provided reply path for the recipient
/// to respond.
WithSpecifiedReplyPath {
/// The destination where we need to send our message.
destination: Destination,
/// The reply path which should be included in the message.
reply_path: BlindedMessagePath, reply_path: BlindedMessagePath,
} },
/// Indicates that a message should be sent including a reply path for the recipient to
/// `ResponseInstruction` represents instructions for responding to received messages. /// respond.
pub enum ResponseInstruction<T: OnionMessageContents> { WithReplyPath {
/// Indicates that a response should be sent including a reply path for /// The destination where we need to send our message.
/// the recipient to respond back. destination: Destination,
WithReplyPath(OnionMessageResponse<T>, MessageContext), /// The context to include in the reply path we'll give the recipient so they can respond
/// Indicates that a response should be sent without including a reply path /// to us.
/// for the recipient to respond back. context: MessageContext,
WithoutReplyPath(OnionMessageResponse<T>), },
/// Indicates that there's no response to send back. /// Indicates that a message should be sent without including a reply path, preventing the
NoResponse, /// recipient from responding.
} WithoutReplyPath {
/// The destination where we need to send our message.
/// An [`OnionMessage`] for [`OnionMessenger`] to send. destination: Destination,
/// },
/// These are obtained when released from [`OnionMessenger`]'s handlers after which they are /// Indicates that a message is being sent as a reply to a received message.
/// enqueued for sending. ForReply {
#[cfg(not(c_bindings))] /// The instructions provided by the [`Responder`].
pub struct PendingOnionMessage<T: OnionMessageContents> { instructions: ResponseInstruction,
/// The message contents to send in an [`OnionMessage`]. },
pub contents: T,
/// The destination of the message.
pub destination: Destination,
/// A reply path to include in the [`OnionMessage`] for a response.
pub reply_path: Option<BlindedMessagePath>,
}
#[cfg(c_bindings)]
/// An [`OnionMessage`] for [`OnionMessenger`] to send.
///
/// These are obtained when released from [`OnionMessenger`]'s handlers after which they are
/// enqueued for sending.
pub type PendingOnionMessage<T> = (T, Destination, Option<BlindedMessagePath>);
pub(crate) fn new_pending_onion_message<T: OnionMessageContents>(
contents: T, destination: Destination, reply_path: Option<BlindedMessagePath>
) -> PendingOnionMessage<T> {
#[cfg(not(c_bindings))]
return PendingOnionMessage { contents, destination, reply_path };
#[cfg(c_bindings)]
return (contents, destination, reply_path);
} }
/// A trait defining behavior for routing an [`OnionMessage`]. /// A trait defining behavior for routing an [`OnionMessage`].
@ -799,7 +798,9 @@ pub trait CustomOnionMessageHandler {
/// Called with the custom message that was received, returning a response to send, if any. /// Called with the custom message that was received, returning a response to send, if any.
/// ///
/// The returned [`Self::CustomMessage`], if any, is enqueued to be sent by [`OnionMessenger`]. /// The returned [`Self::CustomMessage`], if any, is enqueued to be sent by [`OnionMessenger`].
fn handle_custom_message(&self, message: Self::CustomMessage, context: Option<Vec<u8>>, responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage>; fn handle_custom_message(
&self, message: Self::CustomMessage, context: Option<Vec<u8>>, responder: Option<Responder>
) -> Option<(Self::CustomMessage, ResponseInstruction)>;
/// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the /// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the
/// message type is unknown. /// message type is unknown.
@ -809,15 +810,7 @@ pub trait CustomOnionMessageHandler {
/// ///
/// Typically, this is used for messages initiating a message flow rather than in response to /// Typically, this is used for messages initiating a message flow rather than in response to
/// another message. The latter should use the return value of [`Self::handle_custom_message`]. /// another message. The latter should use the return value of [`Self::handle_custom_message`].
#[cfg(not(c_bindings))] fn release_pending_custom_messages(&self) -> Vec<(Self::CustomMessage, MessageSendInstructions)>;
fn release_pending_custom_messages(&self) -> Vec<PendingOnionMessage<Self::CustomMessage>>;
/// Releases any [`Self::CustomMessage`]s that need to be sent.
///
/// Typically, this is used for messages initiating a message flow rather than in response to
/// another message. The latter should use the return value of [`Self::handle_custom_message`].
#[cfg(c_bindings)]
fn release_pending_custom_messages(&self) -> Vec<(Self::CustomMessage, Destination, Option<BlindedMessagePath>)>;
} }
/// A processed incoming onion message, containing either a Forward (another onion message) /// A processed incoming onion message, containing either a Forward (another onion message)
@ -1160,21 +1153,39 @@ where
self.offers_handler = offers_handler; self.offers_handler = offers_handler;
} }
/// Sends an [`OnionMessage`] with the given `contents` to `destination`. /// Sends an [`OnionMessage`] based on its [`MessageSendInstructions`].
///
/// See [`OnionMessenger`] for example usage.
pub fn send_onion_message<T: OnionMessageContents>( pub fn send_onion_message<T: OnionMessageContents>(
&self, contents: T, destination: Destination, reply_path: Option<BlindedMessagePath> &self, contents: T, instructions: MessageSendInstructions,
) -> Result<SendSuccess, SendError> { ) -> Result<SendSuccess, SendError> {
self.find_path_and_enqueue_onion_message( self.send_onion_message_internal(contents, instructions, format_args!(""))
contents, destination, reply_path, format_args!("")
)
} }
fn find_path_and_enqueue_onion_message<T: OnionMessageContents>( fn send_onion_message_internal<T: OnionMessageContents>(
&self, contents: T, destination: Destination, reply_path: Option<BlindedMessagePath>, &self, contents: T, instructions: MessageSendInstructions, log_suffix: fmt::Arguments,
log_suffix: fmt::Arguments
) -> Result<SendSuccess, SendError> { ) -> Result<SendSuccess, SendError> {
let (destination, reply_path) = match instructions {
MessageSendInstructions::WithSpecifiedReplyPath { destination, reply_path } =>
(destination, Some(reply_path)),
MessageSendInstructions::WithReplyPath { destination, context }
|MessageSendInstructions::ForReply { instructions: ResponseInstruction { destination, context: Some(context) } } =>
{
match self.create_blinded_path(context) {
Ok(reply_path) => (destination, Some(reply_path)),
Err(err) => {
log_trace!(
self.logger,
"Failed to create reply path {}: {:?}",
log_suffix, err
);
return Err(err);
}
}
},
MessageSendInstructions::WithoutReplyPath { destination }
|MessageSendInstructions::ForReply { instructions: ResponseInstruction { destination, context: None } } =>
(destination, None),
};
let mut logger = WithContext::from(&self.logger, None, None, None); let mut logger = WithContext::from(&self.logger, None, None, None);
let result = self.find_path(destination).and_then(|path| { let result = self.find_path(destination).and_then(|path| {
let first_hop = path.intermediate_nodes.get(0).map(|p| *p); let first_hop = path.intermediate_nodes.get(0).map(|p| *p);
@ -1318,42 +1329,21 @@ where
/// enqueueing any response for sending. /// enqueueing any response for sending.
/// ///
/// This function is useful for asynchronous handling of [`OnionMessage`]s. /// This function is useful for asynchronous handling of [`OnionMessage`]s.
/// Handlers have the option to return [`ResponseInstruction::NoResponse`], indicating that /// Handlers have the option to return `None`, indicating that no immediate response should be
/// no immediate response should be sent. Then, they can transfer the associated [`Responder`] /// sent. Then, they can transfer the associated [`Responder`] to another task responsible for
/// to another task responsible for generating the response asynchronously. Subsequently, when /// generating the response asynchronously. Subsequently, when the response is prepared and
/// the response is prepared and ready for sending, that task can invoke this method to enqueue /// ready for sending, that task can invoke this method to enqueue the response for delivery.
/// the response for delivery.
pub fn handle_onion_message_response<T: OnionMessageContents>( pub fn handle_onion_message_response<T: OnionMessageContents>(
&self, response: ResponseInstruction<T> &self, response: T, instructions: ResponseInstruction,
) -> Result<Option<SendSuccess>, SendError> { ) -> Result<SendSuccess, SendError> {
let (response, context) = match response { let message_type = response.msg_type();
ResponseInstruction::WithReplyPath(response, context) => (response, Some(context)), self.send_onion_message_internal(
ResponseInstruction::WithoutReplyPath(response) => (response, None), response, instructions.into_instructions(),
ResponseInstruction::NoResponse => return Ok(None),
};
let message_type = response.message.msg_type();
let reply_path = if let Some(context) = context {
match self.create_blinded_path(context) {
Ok(reply_path) => Some(reply_path),
Err(err) => {
log_trace!(
self.logger,
"Failed to create reply path when responding with {} to an onion message: {:?}",
message_type, err
);
return Err(err);
}
}
} else { None };
self.find_path_and_enqueue_onion_message(
response.message, Destination::BlindedPath(response.reply_path), reply_path,
format_args!( format_args!(
"when responding with {} to an onion message", "when responding with {} to an onion message",
message_type, message_type,
) )
).map(|result| Some(result)) )
} }
#[cfg(test)] #[cfg(test)]
@ -1603,14 +1593,18 @@ where
} }
}; };
let response_instructions = self.offers_handler.handle_message(msg, context, responder); let response_instructions = self.offers_handler.handle_message(msg, context, responder);
let _ = self.handle_onion_message_response(response_instructions); if let Some((msg, instructions)) = response_instructions {
let _ = self.handle_onion_message_response(msg, instructions);
}
}, },
#[cfg(async_payments)] #[cfg(async_payments)]
ParsedOnionMessageContents::AsyncPayments(AsyncPaymentsMessage::HeldHtlcAvailable(msg)) => { ParsedOnionMessageContents::AsyncPayments(AsyncPaymentsMessage::HeldHtlcAvailable(msg)) => {
let response_instructions = self.async_payments_handler.held_htlc_available( let response_instructions = self.async_payments_handler.held_htlc_available(
msg, responder msg, responder
); );
let _ = self.handle_onion_message_response(response_instructions); if let Some((msg, instructions)) = response_instructions {
let _ = self.handle_onion_message_response(msg, instructions);
}
}, },
#[cfg(async_payments)] #[cfg(async_payments)]
ParsedOnionMessageContents::AsyncPayments(AsyncPaymentsMessage::ReleaseHeldHtlc(msg)) => { ParsedOnionMessageContents::AsyncPayments(AsyncPaymentsMessage::ReleaseHeldHtlc(msg)) => {
@ -1626,7 +1620,9 @@ where
} }
}; };
let response_instructions = self.custom_handler.handle_custom_message(msg, context, responder); let response_instructions = self.custom_handler.handle_custom_message(msg, context, responder);
let _ = self.handle_onion_message_response(response_instructions); if let Some((msg, instructions)) = response_instructions {
let _ = self.handle_onion_message_response(msg, instructions);
}
}, },
} }
}, },
@ -1751,24 +1747,16 @@ where
// node, and then enqueue the message for sending to the first peer in the full path. // node, and then enqueue the message for sending to the first peer in the full path.
fn next_onion_message_for_peer(&self, peer_node_id: PublicKey) -> Option<OnionMessage> { fn next_onion_message_for_peer(&self, peer_node_id: PublicKey) -> Option<OnionMessage> {
// Enqueue any initiating `OffersMessage`s to send. // Enqueue any initiating `OffersMessage`s to send.
for message in self.offers_handler.release_pending_messages() { for (message, instructions) in self.offers_handler.release_pending_messages() {
#[cfg(not(c_bindings))] let _ = self.send_onion_message_internal(
let PendingOnionMessage { contents, destination, reply_path } = message; message, instructions, format_args!("when sending OffersMessage")
#[cfg(c_bindings)]
let (contents, destination, reply_path) = message;
let _ = self.find_path_and_enqueue_onion_message(
contents, destination, reply_path, format_args!("when sending OffersMessage")
); );
} }
// Enqueue any initiating `CustomMessage`s to send. // Enqueue any initiating `CustomMessage`s to send.
for message in self.custom_handler.release_pending_custom_messages() { for (message, instructions) in self.custom_handler.release_pending_custom_messages() {
#[cfg(not(c_bindings))] let _ = self.send_onion_message_internal(
let PendingOnionMessage { contents, destination, reply_path } = message; message, instructions, format_args!("when sending CustomMessage")
#[cfg(c_bindings)]
let (contents, destination, reply_path) = message;
let _ = self.find_path_and_enqueue_onion_message(
contents, destination, reply_path, format_args!("when sending CustomMessage")
); );
} }

View file

@ -22,9 +22,7 @@ use crate::offers::static_invoice::StaticInvoice;
use crate::onion_message::packet::OnionMessageContents; use crate::onion_message::packet::OnionMessageContents;
use crate::util::logger::Logger; use crate::util::logger::Logger;
use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer}; use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer};
use crate::onion_message::messenger::{ResponseInstruction, Responder}; use crate::onion_message::messenger::{ResponseInstruction, Responder, MessageSendInstructions};
#[cfg(not(c_bindings))]
use crate::onion_message::messenger::PendingOnionMessage;
use crate::prelude::*; use crate::prelude::*;
@ -47,21 +45,13 @@ pub trait OffersMessageHandler {
/// [`OnionMessenger`]: crate::onion_message::messenger::OnionMessenger /// [`OnionMessenger`]: crate::onion_message::messenger::OnionMessenger
fn handle_message( fn handle_message(
&self, message: OffersMessage, context: Option<OffersContext>, responder: Option<Responder>, &self, message: OffersMessage, context: Option<OffersContext>, responder: Option<Responder>,
) -> ResponseInstruction<OffersMessage>; ) -> Option<(OffersMessage, ResponseInstruction)>;
/// Releases any [`OffersMessage`]s that need to be sent. /// Releases any [`OffersMessage`]s that need to be sent.
/// ///
/// Typically, this is used for messages initiating a payment flow rather than in response to /// Typically, this is used for messages initiating a payment flow rather than in response to
/// another message. The latter should use the return value of [`Self::handle_message`]. /// another message. The latter should use the return value of [`Self::handle_message`].
#[cfg(not(c_bindings))] fn release_pending_messages(&self) -> Vec<(OffersMessage, MessageSendInstructions)> { vec![] }
fn release_pending_messages(&self) -> Vec<PendingOnionMessage<OffersMessage>> { vec![] }
/// Releases any [`OffersMessage`]s that need to be sent.
///
/// Typically, this is used for messages initiating a payment flow rather than in response to
/// another message. The latter should use the return value of [`Self::handle_message`].
#[cfg(c_bindings)]
fn release_pending_messages(&self) -> Vec<(OffersMessage, crate::onion_message::messenger::Destination, Option<crate::blinded_path::message::BlindedMessagePath>)> { vec![] }
} }
/// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`]. /// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`].