X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fonion_message%2Fmessenger.rs;h=03dc6a5b002f01be6e706396190f1eddeb84f839;hb=0ce1c5a674f4ba27345634d529db5cdd758b8319;hp=07cb0bc1e9896df5241c05a0b80a2b03e89eb995;hpb=a71000f35dd23949d26fffd421d6f6478f0cd6b5;p=rust-lightning diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 07cb0bc1..03dc6a5b 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -15,7 +15,9 @@ use bitcoin::hashes::hmac::{Hmac, HmacEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey}; -use crate::blinded_path::{BlindedPath, ForwardTlvs, ReceiveTlvs, utils}; +use crate::blinded_path::BlindedPath; +use crate::blinded_path::message::{advance_path_by_one, ForwardTlvs, ReceiveTlvs}; +use crate::blinded_path::utils; use crate::sign::{EntropySource, KeysManager, NodeSigner, Recipient}; use crate::events::OnionMessageProvider; use crate::ln::features::{InitFeatures, NodeFeatures}; @@ -152,6 +154,17 @@ pub trait MessageRouter { ) -> Result; } +/// A [`MessageRouter`] that always fails. +pub struct DefaultMessageRouter; + +impl MessageRouter for DefaultMessageRouter { + fn find_path( + &self, _sender: PublicKey, _peers: Vec, _destination: Destination + ) -> Result { + Err(()) + } +} + /// A path for sending an [`msgs::OnionMessage`]. #[derive(Clone)] pub struct OnionMessagePath { @@ -224,13 +237,73 @@ pub trait CustomOnionMessageHandler { /// The message known to the handler. To support multiple message types, you may want to make this /// an enum with a variant for each supported message. type CustomMessage: CustomOnionMessageContents; - /// Called with the custom message that was received. - fn handle_custom_message(&self, msg: Self::CustomMessage); + + /// Called with the custom message that was received, returning a response to send, if any. + fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option; + /// 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>; } + +/// Create an onion message with contents `message` to the destination of `path`. +/// Returns (introduction_node_id, onion_msg) +pub fn create_onion_message( + entropy_source: &ES, node_signer: &NS, secp_ctx: &Secp256k1, + path: OnionMessagePath, message: OnionMessageContents, reply_path: Option, +) -> Result<(PublicKey, msgs::OnionMessage), SendError> +where + ES::Target: EntropySource, + NS::Target: NodeSigner, +{ + let OnionMessagePath { intermediate_nodes, mut destination } = path; + if let Destination::BlindedPath(BlindedPath { ref blinded_hops, .. }) = destination { + if blinded_hops.len() < 2 { + return Err(SendError::TooFewBlindedHops); + } + } + + if message.tlv_type() < 64 { return Err(SendError::InvalidMessage) } + + // If we are sending straight to a blinded path and we are the introduction node, we need to + // advance the blinded path by 1 hop so the second hop is the new introduction node. + if intermediate_nodes.len() == 0 { + if let Destination::BlindedPath(ref mut blinded_path) = destination { + let our_node_id = node_signer.get_node_id(Recipient::Node) + .map_err(|()| SendError::GetNodeIdFailed)?; + if blinded_path.introduction_node_id == our_node_id { + advance_path_by_one(blinded_path, node_signer, &secp_ctx) + .map_err(|()| SendError::BlindedPathAdvanceFailed)?; + } + } + } + + let blinding_secret_bytes = entropy_source.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 { + (intermediate_nodes[0], PublicKey::from_secret_key(&secp_ctx, &blinding_secret)) + } else { + match destination { + Destination::Node(pk) => (pk, PublicKey::from_secret_key(&secp_ctx, &blinding_secret)), + Destination::BlindedPath(BlindedPath { introduction_node_id, blinding_point, .. }) => + (introduction_node_id, blinding_point), + } + }; + let (packet_payloads, packet_keys) = packet_payloads_and_keys( + &secp_ctx, &intermediate_nodes, destination, message, reply_path, &blinding_secret) + .map_err(|e| SendError::Secp256k1(e))?; + + let prng_seed = entropy_source.get_secure_random_bytes(); + let onion_routing_packet = construct_onion_message_packet( + packet_payloads, packet_keys, prng_seed).map_err(|()| SendError::TooBigPacket)?; + + Ok((introduction_node_id, msgs::OnionMessage { + blinding_point, + onion_routing_packet + })) +} + impl OnionMessenger where @@ -268,58 +341,72 @@ where &self, path: OnionMessagePath, message: OnionMessageContents, reply_path: Option ) -> Result<(), SendError> { - let OnionMessagePath { intermediate_nodes, mut destination } = path; - if let Destination::BlindedPath(BlindedPath { ref blinded_hops, .. }) = destination { - if blinded_hops.len() < 2 { - return Err(SendError::TooFewBlindedHops); - } - } - - if message.tlv_type() < 64 { return Err(SendError::InvalidMessage) } - - // If we are sending straight to a blinded path and we are the introduction node, we need to - // advance the blinded path by 1 hop so the second hop is the new introduction node. - if intermediate_nodes.len() == 0 { - if let Destination::BlindedPath(ref mut blinded_path) = destination { - let our_node_id = self.node_signer.get_node_id(Recipient::Node) - .map_err(|()| SendError::GetNodeIdFailed)?; - if blinded_path.introduction_node_id == our_node_id { - blinded_path.advance_message_path_by_one(&self.node_signer, &self.secp_ctx) - .map_err(|()| SendError::BlindedPathAdvanceFailed)?; - } - } - } - - let blinding_secret_bytes = self.entropy_source.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 { - (intermediate_nodes[0], PublicKey::from_secret_key(&self.secp_ctx, &blinding_secret)) - } else { - match destination { - Destination::Node(pk) => (pk, PublicKey::from_secret_key(&self.secp_ctx, &blinding_secret)), - Destination::BlindedPath(BlindedPath { introduction_node_id, blinding_point, .. }) => - (introduction_node_id, blinding_point), - } - }; - let (packet_payloads, packet_keys) = packet_payloads_and_keys( - &self.secp_ctx, &intermediate_nodes, destination, message, reply_path, &blinding_secret) - .map_err(|e| SendError::Secp256k1(e))?; - - let prng_seed = self.entropy_source.get_secure_random_bytes(); - let onion_routing_packet = construct_onion_message_packet( - packet_payloads, packet_keys, prng_seed).map_err(|()| SendError::TooBigPacket)?; + let (introduction_node_id, onion_msg) = create_onion_message( + &self.entropy_source, &self.node_signer, &self.secp_ctx, + path, message, reply_path + )?; let mut pending_per_peer_msgs = self.pending_messages.lock().unwrap(); if outbound_buffer_full(&introduction_node_id, &pending_per_peer_msgs) { return Err(SendError::BufferFull) } match pending_per_peer_msgs.entry(introduction_node_id) { hash_map::Entry::Vacant(_) => Err(SendError::InvalidFirstHop), hash_map::Entry::Occupied(mut e) => { - e.get_mut().push_back(msgs::OnionMessage { blinding_point, onion_routing_packet }); + e.get_mut().push_back(onion_msg); Ok(()) } } } + fn respond_with_onion_message( + &self, response: OnionMessageContents, path_id: Option<[u8; 32]>, + reply_path: Option + ) { + let sender = match self.node_signer.get_node_id(Recipient::Node) { + Ok(node_id) => node_id, + Err(_) => { + log_warn!( + self.logger, "Unable to retrieve node id when responding to onion message with \ + path_id {:02x?}", path_id + ); + return; + } + }; + + let peers = self.pending_messages.lock().unwrap().keys().copied().collect(); + + let destination = match reply_path { + Some(reply_path) => Destination::BlindedPath(reply_path), + None => { + log_trace!( + self.logger, "Missing reply path when responding to onion message with path_id \ + {:02x?}", path_id + ); + return; + }, + }; + + let path = match self.message_router.find_path(sender, peers, destination) { + Ok(path) => path, + Err(()) => { + log_trace!( + self.logger, "Failed to find path when responding to onion message with \ + path_id {:02x?}", path_id + ); + return; + }, + }; + + log_trace!(self.logger, "Responding to onion message with path_id {:02x?}", path_id); + + if let Err(e) = self.send_onion_message(path, response, None) { + log_trace!( + self.logger, "Failed responding to onion message with path_id {:02x?}: {:?}", + path_id, e + ); + return; + } + } + #[cfg(test)] pub(super) fn release_pending_msgs(&self) -> HashMap> { let mut pending_msgs = self.pending_messages.lock().unwrap(); @@ -364,7 +451,7 @@ where L::Target: Logger, MR::Target: MessageRouter, OMH::Target: OffersMessageHandler, - CMH::Target: CustomOnionMessageHandler + Sized, + CMH::Target: CustomOnionMessageHandler, { /// 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 @@ -400,12 +487,23 @@ where Ok((Payload::Receive::<<::Target as CustomOnionMessageHandler>::CustomMessage> { message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path, }, None)) => { - log_info!(self.logger, + log_trace!(self.logger, "Received an onion message with path_id {:02x?} and {} reply_path", path_id, if reply_path.is_some() { "a" } else { "no" }); - match message { - OnionMessageContents::Offers(msg) => self.offers_handler.handle_message(msg), - OnionMessageContents::Custom(msg) => self.custom_handler.handle_custom_message(msg), + + let response = match message { + OnionMessageContents::Offers(msg) => { + self.offers_handler.handle_message(msg) + .map(|msg| OnionMessageContents::Offers(msg)) + }, + OnionMessageContents::Custom(msg) => { + self.custom_handler.handle_custom_message(msg) + .map(|msg| OnionMessageContents::Custom(msg)) + }, + }; + + if let Some(response) = response { + self.respond_with_onion_message(response, path_id, reply_path); } }, Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs { @@ -416,7 +514,7 @@ where // unwrapping the onion layers to get to the final payload. Since we don't have the option // of creating blinded paths with dummy hops currently, we should be ok to not handle this // for now. - let new_pubkey = match onion_utils::next_hop_packet_pubkey(&self.secp_ctx, msg.onion_routing_packet.public_key, &onion_decode_ss) { + let new_pubkey = match onion_utils::next_hop_pubkey(&self.secp_ctx, msg.onion_routing_packet.public_key, &onion_decode_ss) { Ok(pk) => pk, Err(e) => { log_trace!(self.logger, "Failed to compute next hop packet pubkey: {}", e); @@ -433,21 +531,16 @@ where blinding_point: match next_blinding_override { Some(blinding_point) => blinding_point, None => { - let blinding_factor = { - let mut sha = Sha256::engine(); - sha.input(&msg.blinding_point.serialize()[..]); - sha.input(control_tlvs_ss.as_ref()); - Sha256::from_engine(sha).into_inner() - }; - let next_blinding_point = msg.blinding_point; - match next_blinding_point.mul_tweak(&self.secp_ctx, &Scalar::from_be_bytes(blinding_factor).unwrap()) { + match onion_utils::next_hop_pubkey( + &self.secp_ctx, msg.blinding_point, control_tlvs_ss.as_ref() + ) { Ok(bp) => bp, Err(e) => { log_trace!(self.logger, "Failed to compute next blinding point: {}", e); return } } - }, + } }, onion_routing_packet: outgoing_packet, }; @@ -535,11 +628,11 @@ where /// /// [`SimpleArcChannelManager`]: crate::ln::channelmanager::SimpleArcChannelManager /// [`SimpleArcPeerManager`]: crate::ln::peer_handler::SimpleArcPeerManager -pub type SimpleArcOnionMessenger = OnionMessenger< +pub type SimpleArcOnionMessenger = OnionMessenger< Arc, Arc, Arc, - Arc, + Arc, IgnoringMessageHandler, IgnoringMessageHandler >; @@ -551,11 +644,11 @@ pub type SimpleArcOnionMessenger = OnionMessenger< /// /// [`SimpleRefChannelManager`]: crate::ln::channelmanager::SimpleRefChannelManager /// [`SimpleRefPeerManager`]: crate::ln::peer_handler::SimpleRefPeerManager -pub type SimpleRefOnionMessenger<'a, 'b, 'c, L, R> = OnionMessenger< +pub type SimpleRefOnionMessenger<'a, 'b, 'c, L> = OnionMessenger< &'a KeysManager, &'a KeysManager, &'b L, - &'c R, + &'c DefaultMessageRouter, IgnoringMessageHandler, IgnoringMessageHandler >; @@ -579,46 +672,48 @@ fn packet_payloads_and_keys