From: Matt Corallo <649246+TheBlueMatt@users.noreply.github.com> Date: Tue, 1 Nov 2022 21:12:30 +0000 (+0000) Subject: Merge pull request #1791 from valentinewallace/2022-10-we-are-intro-node X-Git-Tag: v0.0.113~63 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=6ca49948c169a297144d5d1474a2cef3827237e1;hp=-c;p=rust-lightning Merge pull request #1791 from valentinewallace/2022-10-we-are-intro-node Onion messages: fix edge case where we are the intro node --- 6ca49948c169a297144d5d1474a2cef3827237e1 diff --combined lightning/src/onion_message/functional_tests.rs index d1e892de0,81826a62c..bd0a884a8 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@@ -14,7 -14,7 +14,7 @@@ use crate::ln::features::InitFeatures 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; @@@ -54,12 -54,8 +54,12 @@@ impl Writeable for TestCustomMessage } } -impl MaybeReadableArgs for TestCustomMessage { - fn read(buffer: &mut R, message_type: u64) -> Result, 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(&self, message_type: u64, buffer: &mut R) -> Result, DecodeError> where Self: Sized { if message_type == CUSTOM_MESSAGE_TYPE { let mut buf = Vec::new(); buffer.read_to_end(&mut buf)?; @@@ -70,6 -66,13 +70,6 @@@ } } -struct TestCustomMessageHandler {} - -impl CustomOnionMessageHandler for TestCustomMessageHandler { - type CustomMessage = TestCustomMessage; - fn handle_custom_message(&self, _msg: Self::CustomMessage) {} -} - fn create_nodes(num_messengers: u8) -> Vec { let mut nodes = Vec::new(); for i in 0..num_messengers { @@@ -167,6 -170,26 +167,26 @@@ fn too_big_packet_error() 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. @@@ -230,6 -253,12 +250,6 @@@ fn invalid_custom_message_type() fn write(&self, _w: &mut W) -> Result<(), io::Error> { unreachable!() } } - impl MaybeReadableArgs for InvalidCustomMessage { - fn read(_buffer: &mut R, _message_type: u64) -> Result, 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); diff --combined lightning/src/onion_message/messenger.rs index a80715e16,70a0842c7..a09c942be --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@@ -29,7 -29,6 +29,7 @@@ use crate::util::logger::Logger use crate::util::ser::Writeable; use core::ops::Deref; +use crate::io; use crate::sync::{Arc, Mutex}; use crate::prelude::*; @@@ -48,7 -47,7 +48,7 @@@ /// # 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 {}; @@@ -82,6 -81,13 +82,6 @@@ /// your_custom_message_type /// } /// } -/// impl MaybeReadableArgs for YourCustomMessage { -/// fn read(r: &mut R, message_type: u64) -> Result, 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; @@@ -154,6 -160,15 +154,15 @@@ pub enum SendError 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`], @@@ -172,9 -187,6 +181,9 @@@ pub trait CustomOnionMessageHandler 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(&self, message_type: u64, buffer: &mut R) -> Result, msgs::DecodeError>; } impl OnionMessenger @@@ -198,7 -210,7 +207,7 @@@ /// Send an onion message with contents `message` to `destination`, routing it through `intermediate_nodes`. /// See [`OnionMessenger`] for example usage. - pub fn send_onion_message(&self, intermediate_nodes: &[PublicKey], destination: Destination, message: OnionMessageContents, reply_path: Option) -> Result<(), SendError> { + pub fn send_onion_message(&self, intermediate_nodes: &[PublicKey], mut destination: Destination, message: OnionMessageContents, reply_path: Option) -> Result<(), SendError> { if let Destination::BlindedRoute(BlindedRoute { ref blinded_hops, .. }) = destination { if blinded_hops.len() < 2 { return Err(SendError::TooFewBlindedHops); @@@ -207,6 -219,19 +216,19 @@@ 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 { @@@ -276,7 -301,7 +298,7 @@@ fn outbound_buffer_full(peer_node_id: & impl OnionMessageHandler for OnionMessenger where K::Target: KeysInterface, 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 @@@ -305,8 -330,8 +327,8 @@@ } } }; - 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::<<::Target as CustomOnionMessageHandler>::CustomMessage> { message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path, @@@ -488,12 -513,8 +510,8 @@@ fn packet_payloads_and_keys