use bitcoin::secp256k1::schnorr;
use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
+use lightning::blinded_path::message::{MessageContext, OffersContext};
use lightning::blinded_path::{BlindedPath, EmptyNodeIdLookUp};
use lightning::ln::features::InitFeatures;
use lightning::ln::msgs::{self, DecodeError, OnionMessageHandler};
impl OffersMessageHandler for TestOffersMessageHandler {
fn handle_message(
- &self, _message: OffersMessage, _responder: Option<Responder>,
+ &self, _message: OffersMessage, _responder: Option<Responder>, _context: OffersContext,
) -> ResponseInstruction<OffersMessage> {
ResponseInstruction::NoResponse
}
impl CustomOnionMessageHandler for TestCustomMessageHandler {
type CustomMessage = TestCustomMessage;
fn handle_custom_message(
- &self, message: Self::CustomMessage, responder: Option<Responder>,
+ &self, message: Self::CustomMessage, responder: Option<Responder>, _context: Vec<u8>,
) -> ResponseInstruction<Self::CustomMessage> {
match responder {
Some(responder) => responder.respond(message),
super::do_test(&<Vec<u8>>::from_hex(one_hop_om).unwrap(), &logger);
{
let log_entries = logger.lines.lock().unwrap();
- assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(),
- "Received an onion message with path_id None and a reply_path: Custom(TestCustomMessage)"
- .to_string())), Some(&1));
+ assert_eq!(
+ log_entries.get(&(
+ "lightning::onion_message::messenger".to_string(),
+ "Received an onion message with a reply_path: Custom(TestCustomMessage)"
+ .to_string()
+ )),
+ Some(&1)
+ );
assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(),
"Constructing onion message when responding with Custom Message to an onion message: TestCustomMessage".to_string())), Some(&1));
assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(),
use bitcoin::secp256k1::Secp256k1;
use bitcoin::{secp256k1, Sequence};
+use crate::blinded_path::message::OffersContext;
use crate::blinded_path::{BlindedPath, NodeIdLookUp};
use crate::blinded_path::message::ForwardNode;
use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, ReceiveTlvs};
R::Target: Router,
L::Target: Logger,
{
- fn handle_message(&self, message: OffersMessage, responder: Option<Responder>) -> ResponseInstruction<OffersMessage> {
+ fn handle_message(&self, message: OffersMessage, responder: Option<Responder>, context: OffersContext) -> ResponseInstruction<OffersMessage> {
let secp_ctx = &self.secp_ctx;
let expanded_key = &self.inbound_payment_key;
+ let abandon_if_payment = |context| {
+ match context {
+ OffersContext::OutboundPayment { payment_id } => self.abandon_payment(payment_id),
+ _ => {},
+ }
+ };
+
match message {
OffersMessage::InvoiceRequest(invoice_request) => {
let responder = match responder {
};
match result {
- Ok(()) => ResponseInstruction::NoResponse,
- Err(e) => match responder {
- Some(responder) => responder.respond(OffersMessage::InvoiceError(e)),
- None => {
- log_trace!(self.logger, "No reply path for sending invoice error: {:?}", e);
- ResponseInstruction::NoResponse
- },
- },
+ Err(err) => {
+ match responder {
+ Some(responder) => {
+ abandon_if_payment(context);
+ responder.respond(OffersMessage::InvoiceError(err))
+ }
+ None => {
+ abandon_if_payment(context);
+ log_trace!(
+ self.logger,
+ "A error response was generated, but there is no reply_path specified \
+ for sending the response. Error: {}",
+ err
+ );
+ return ResponseInstruction::NoResponse;
+ }
+ }
+ }
+ Ok(_) => return ResponseInstruction::NoResponse,
}
},
#[cfg(async_payments)]
}
},
OffersMessage::InvoiceError(invoice_error) => {
+ abandon_if_payment(context);
log_trace!(self.logger, "Received invoice_error: {}", invoice_error);
ResponseInstruction::NoResponse
},
use bitcoin::blockdata::constants::ChainHash;
use bitcoin::secp256k1::{self, Secp256k1, SecretKey, PublicKey};
+use crate::blinded_path::message::OffersContext;
use crate::sign::{NodeSigner, Recipient};
use crate::events::{MessageSendEvent, MessageSendEventsProvider};
use crate::ln::types::ChannelId;
}
impl OffersMessageHandler for IgnoringMessageHandler {
- fn handle_message(&self, _message: OffersMessage, _responder: Option<Responder>) -> ResponseInstruction<OffersMessage> {
+ fn handle_message(&self, _message: OffersMessage, _responder: Option<Responder>, _context: OffersContext) -> ResponseInstruction<OffersMessage> {
ResponseInstruction::NoResponse
}
}
}
impl CustomOnionMessageHandler for IgnoringMessageHandler {
type CustomMessage = Infallible;
- fn handle_custom_message(&self, _message: Self::CustomMessage, _responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage> {
+ fn handle_custom_message(&self, _message: Self::CustomMessage, _responder: Option<Responder>, _context: Vec<u8>) -> ResponseInstruction<Self::CustomMessage> {
// Since we always return `None` in the read the handle method should never be called.
unreachable!();
}
//! Onion message testing and test utilities live here.
use crate::blinded_path::{BlindedPath, EmptyNodeIdLookUp};
-use crate::blinded_path::message::ForwardNode;
+use crate::blinded_path::message::{ForwardNode, OffersContext};
use crate::events::{Event, EventsProvider};
use crate::ln::features::{ChannelFeatures, InitFeatures};
use crate::ln::msgs::{self, DecodeError, OnionMessageHandler};
struct TestOffersMessageHandler {}
impl OffersMessageHandler for TestOffersMessageHandler {
- fn handle_message(&self, _message: OffersMessage, _responder: Option<Responder>) -> ResponseInstruction<OffersMessage> {
+ fn handle_message(&self, _message: OffersMessage, _responder: Option<Responder>, _context: OffersContext) -> ResponseInstruction<OffersMessage> {
ResponseInstruction::NoResponse
}
}
impl CustomOnionMessageHandler for TestCustomMessageHandler {
type CustomMessage = TestCustomMessage;
- fn handle_custom_message(&self, msg: Self::CustomMessage, responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage> {
+ fn handle_custom_message(&self, msg: Self::CustomMessage, responder: Option<Responder>, _context: Vec<u8>) -> ResponseInstruction<Self::CustomMessage> {
let expectation = self.get_next_expectation();
assert_eq!(msg, expectation.expect);
// 5. Expect Alice to receive the message and create a response instruction for it.
alice.custom_message_handler.expect_message(message.clone());
- let response_instruction = nodes[0].custom_message_handler.handle_custom_message(message, responder);
+ let response_instruction = nodes[0].custom_message_handler.handle_custom_message(message, responder, Vec::new());
// 6. Simulate Alice asynchronously responding back to Bob with a response.
assert_eq!(
// Alice asynchronously responds to Bob, expecting a response back from him.
let responder = Responder::new(reply_path);
alice.custom_message_handler.expect_message_and_response(message.clone());
- let response_instruction = alice.custom_message_handler.handle_custom_message(message, Some(responder));
+ let response_instruction = alice.custom_message_handler.handle_custom_message(message, Some(responder), Vec::new());
assert_eq!(
alice.messenger.handle_onion_message_response(response_instruction),
disconnect_peers(alice, bob);
let responder = Responder::new(reply_path);
alice.custom_message_handler.expect_message_and_response(message.clone());
- let response_instruction = alice.custom_message_handler.handle_custom_message(message, Some(responder));
+ let response_instruction = alice.custom_message_handler.handle_custom_message(message, Some(responder), Vec::new());
assert_eq!(
alice.messenger.handle_onion_message_response(response_instruction),
use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
use crate::blinded_path::{BlindedPath, IntroductionNode, NextMessageHop, NodeIdLookUp};
-use crate::blinded_path::message::{advance_path_by_one, ForwardNode, ForwardTlvs, ReceiveTlvs, MessageContext};
+use crate::blinded_path::message::{advance_path_by_one, ForwardNode, ForwardTlvs, MessageContext, OffersContext, ReceiveTlvs};
use crate::blinded_path::utils;
use crate::events::{Event, EventHandler, EventsProvider};
use crate::sign::{EntropySource, NodeSigner, Recipient};
/// 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`].
- fn handle_custom_message(&self, message: Self::CustomMessage, responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage>;
+ fn handle_custom_message(&self, message: Self::CustomMessage, responder: Option<Responder>, context: Vec<u8>) -> ResponseInstruction<Self::CustomMessage>;
/// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the
/// message type is unknown.
fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage) {
let logger = WithContext::from(&self.logger, Some(*peer_node_id), None, None);
match self.peel_onion_message(msg) {
- Ok(PeeledOnion::Receive(message, _recipient_data, reply_path)) => {
+ Ok(PeeledOnion::Receive(message, context, reply_path)) => {
log_trace!(
logger,
"Received an onion message with {} reply_path: {:?}",
let responder = reply_path.map(Responder::new);
match message {
ParsedOnionMessageContents::Offers(msg) => {
- let response_instructions = self.offers_handler.handle_message(msg, responder);
+ let context = match context {
+ None => OffersContext::Unknown {},
+ Some(MessageContext::Offers(context)) => context,
+ Some(MessageContext::Custom(_)) => {
+ debug_assert!(false, "Shouldn't have triggered this case.");
+ return
+ }
+ };
+ let response_instructions = self.offers_handler.handle_message(msg, responder, context);
let _ = self.handle_onion_message_response(response_instructions);
},
#[cfg(async_payments)]
self.async_payments_handler.release_held_htlc(msg);
},
ParsedOnionMessageContents::Custom(msg) => {
- let response_instructions = self.custom_handler.handle_custom_message(msg, responder);
+ let context = match context {
+ None => vec![],
+ Some(MessageContext::Custom(data)) => data,
+ Some(MessageContext::Offers(_)) => {
+ debug_assert!(false, "Shouldn't have triggered this case.");
+ return
+ }
+ };
+ let response_instructions = self.custom_handler.handle_custom_message(msg, responder, context);
let _ = self.handle_onion_message_response(response_instructions);
},
}
//! Message handling for BOLT 12 Offers.
use core::fmt;
+use crate::blinded_path::message::OffersContext;
use crate::io::{self, Read};
use crate::ln::msgs::DecodeError;
use crate::offers::invoice_error::InvoiceError;
/// The returned [`OffersMessage`], if any, is enqueued to be sent by [`OnionMessenger`].
///
/// [`OnionMessenger`]: crate::onion_message::messenger::OnionMessenger
- fn handle_message(&self, message: OffersMessage, responder: Option<Responder>) -> ResponseInstruction<OffersMessage>;
+ fn handle_message(&self, message: OffersMessage, responder: Option<Responder>, context: OffersContext) -> ResponseInstruction<OffersMessage>;
/// Releases any [`OffersMessage`]s that need to be sent.
///