use crate::ln::msgs::{self, DecodeError, OnionMessageHandler};
use super::{BlindedRoute, CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError};
use crate::util::enforcing_trait_impls::EnforcingSigner;
-use crate::util::ser::{MaybeReadableArgs, Writeable, Writer};
+use crate::util::ser::{ Writeable, Writer};
use crate::util::test_utils;
use bitcoin::network::constants::Network;
}
}
-impl MaybeReadableArgs<u64> for TestCustomMessage {
- fn read<R: io::Read>(buffer: &mut R, message_type: u64) -> Result<Option<Self>, DecodeError> where Self: Sized {
+struct TestCustomMessageHandler {}
+
+impl CustomOnionMessageHandler for TestCustomMessageHandler {
+ type CustomMessage = TestCustomMessage;
+ fn handle_custom_message(&self, _msg: Self::CustomMessage) {}
+ fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, DecodeError> where Self: Sized {
if message_type == CUSTOM_MESSAGE_TYPE {
let mut buf = Vec::new();
buffer.read_to_end(&mut buf)?;
}
}
-struct TestCustomMessageHandler {}
-
-impl CustomOnionMessageHandler for TestCustomMessageHandler {
- type CustomMessage = TestCustomMessage;
- fn handle_custom_message(&self, _msg: Self::CustomMessage) {}
-}
-
fn create_nodes(num_messengers: u8) -> Vec<MessengerNode> {
let mut nodes = Vec::new();
for i in 0..num_messengers {
assert_eq!(err, SendError::TooBigPacket);
}
+ #[test]
+ fn we_are_intro_node() {
+ // If we are sending straight to a blinded route and we are the introduction node, we need to
+ // advance the blinded route by 1 hop so the second hop is the new introduction node.
+ let mut nodes = create_nodes(3);
+ let test_msg = TestCustomMessage {};
+
+ let secp_ctx = Secp256k1::new();
+ let blinded_route = BlindedRoute::new(&[nodes[0].get_node_pk(), nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
+
+ nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), OnionMessageContents::Custom(test_msg.clone()), None).unwrap();
+ pass_along_path(&nodes, None);
+
+ // Try with a two-hop blinded route where we are the introduction node.
+ let blinded_route = BlindedRoute::new(&[nodes[0].get_node_pk(), nodes[1].get_node_pk()], &*nodes[1].keys_manager, &secp_ctx).unwrap();
+ nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), OnionMessageContents::Custom(test_msg), None).unwrap();
+ nodes.remove(2);
+ pass_along_path(&nodes, None);
+ }
+
#[test]
fn invalid_blinded_route_error() {
// Make sure we error as expected if a provided blinded route has 0 or 1 hops.
fn write<W: Writer>(&self, _w: &mut W) -> Result<(), io::Error> { unreachable!() }
}
- impl MaybeReadableArgs<u64> for InvalidCustomMessage {
- fn read<R: io::Read>(_buffer: &mut R, _message_type: u64) -> Result<Option<Self>, DecodeError> where Self: Sized {
- unreachable!()
- }
- }
-
let test_msg = OnionMessageContents::Custom(InvalidCustomMessage {});
let err = nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), test_msg, None).unwrap_err();
assert_eq!(err, SendError::InvalidMessage);
use crate::util::ser::Writeable;
use core::ops::Deref;
+use crate::io;
use crate::sync::{Arc, Mutex};
use crate::prelude::*;
/// # use lightning::ln::peer_handler::IgnoringMessageHandler;
/// # use lightning::onion_message::{BlindedRoute, CustomOnionMessageContents, Destination, OnionMessageContents, OnionMessenger};
/// # use lightning::util::logger::{Logger, Record};
-/// # use lightning::util::ser::{MaybeReadableArgs, Writeable, Writer};
+/// # use lightning::util::ser::{Writeable, Writer};
/// # use lightning::io;
/// # use std::sync::Arc;
/// # struct FakeLogger {};
/// your_custom_message_type
/// }
/// }
-/// impl MaybeReadableArgs<u64> for YourCustomMessage {
-/// fn read<R: io::Read>(r: &mut R, message_type: u64) -> Result<Option<Self>, DecodeError> {
-/// # unreachable!()
-/// // Read your custom onion message of type `message_type` from `r`, or return `None`
-/// // if the message type is unknown
-/// }
-/// }
/// // Send a custom onion message to a node id.
/// let intermediate_hops = [hop_node_id1, hop_node_id2];
/// let reply_path = None;
InvalidMessage,
/// Our next-hop peer's buffer was full or our total outbound buffer was full.
BufferFull,
+ /// Failed to retrieve our node id from the provided [`KeysInterface`].
+ ///
+ /// [`KeysInterface`]: crate::chain::keysinterface::KeysInterface
+ GetNodeIdFailed,
+ /// We attempted to send to a blinded route where we are the introduction node, and failed to
+ /// advance the blinded route to make the second hop the new introduction node. Either
+ /// [`KeysInterface::ecdh`] failed, we failed to tweak the current blinding point to get the
+ /// new blinding point, or we were attempting to send to ourselves.
+ BlindedRouteAdvanceFailed,
}
/// Handler for custom onion messages. If you are using [`SimpleArcOnionMessenger`],
type CustomMessage: CustomOnionMessageContents;
/// Called with the custom message that was received.
fn handle_custom_message(&self, msg: Self::CustomMessage);
+ /// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the
+ /// message type is unknown.
+ fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError>;
}
impl<Signer: Sign, K: Deref, L: Deref, CMH: Deref> OnionMessenger<Signer, K, L, CMH>
/// Send an onion message with contents `message` to `destination`, routing it through `intermediate_nodes`.
/// See [`OnionMessenger`] for example usage.
- pub fn send_onion_message<T: CustomOnionMessageContents>(&self, intermediate_nodes: &[PublicKey], destination: Destination, message: OnionMessageContents<T>, reply_path: Option<BlindedRoute>) -> Result<(), SendError> {
+ pub fn send_onion_message<T: CustomOnionMessageContents>(&self, intermediate_nodes: &[PublicKey], mut destination: Destination, message: OnionMessageContents<T>, reply_path: Option<BlindedRoute>) -> Result<(), SendError> {
if let Destination::BlindedRoute(BlindedRoute { ref blinded_hops, .. }) = destination {
if blinded_hops.len() < 2 {
return Err(SendError::TooFewBlindedHops);
let OnionMessageContents::Custom(ref msg) = message;
if msg.tlv_type() < 64 { return Err(SendError::InvalidMessage) }
+ // If we are sending straight to a blinded route and we are the introduction node, we need to
+ // advance the blinded route by 1 hop so the second hop is the new introduction node.
+ if intermediate_nodes.len() == 0 {
+ if let Destination::BlindedRoute(ref mut blinded_route) = destination {
+ let our_node_id = self.keys_manager.get_node_id(Recipient::Node)
+ .map_err(|()| SendError::GetNodeIdFailed)?;
+ if blinded_route.introduction_node_id == our_node_id {
+ blinded_route.advance_by_one(&self.keys_manager, &self.secp_ctx)
+ .map_err(|()| SendError::BlindedRouteAdvanceFailed)?;
+ }
+ }
+ }
+
let blinding_secret_bytes = self.keys_manager.get_secure_random_bytes();
let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted");
let (introduction_node_id, blinding_point) = if intermediate_nodes.len() != 0 {
impl<Signer: Sign, K: Deref, L: Deref, CMH: Deref> OnionMessageHandler for OnionMessenger<Signer, K, L, CMH>
where K::Target: KeysInterface<Signer = Signer>,
L::Target: Logger,
- CMH::Target: CustomOnionMessageHandler,
+ CMH::Target: CustomOnionMessageHandler + Sized,
{
/// Handle an incoming onion message. Currently, if a message was destined for us we will log, but
/// soon we'll delegate the onion message to a handler that can generate invoices or send
}
}
};
- match onion_utils::decode_next_hop(onion_decode_ss, &msg.onion_routing_packet.hop_data[..],
- msg.onion_routing_packet.hmac, control_tlvs_ss)
+ match onion_utils::decode_next_untagged_hop(onion_decode_ss, &msg.onion_routing_packet.hop_data[..],
+ msg.onion_routing_packet.hmac, (control_tlvs_ss, &*self.custom_handler))
{
Ok((Payload::Receive::<<<CMH as Deref>::Target as CustomOnionMessageHandler>::CustomMessage> {
message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path,
next_blinding_override: Some(blinding_pt),
})), control_tlvs_ss));
}
- if let Some(encrypted_payload) = enc_payload_opt {
- payloads.push((Payload::Forward(ForwardControlTlvs::Blinded(encrypted_payload)),
- control_tlvs_ss));
- } else { debug_assert!(false); }
- blinded_path_idx += 1;
- } else if blinded_path_idx < num_blinded_hops - 1 && enc_payload_opt.is_some() {
+ }
+ if blinded_path_idx < num_blinded_hops.saturating_sub(1) && enc_payload_opt.is_some() {
payloads.push((Payload::Forward(ForwardControlTlvs::Blinded(enc_payload_opt.unwrap())),
control_tlvs_ss));
blinded_path_idx += 1;