mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-24 23:08:36 +01:00
Merge pull request #2599 from Evanfeenstra/peel-onion
public static peel_onion method on OnionMessenger
This commit is contained in:
commit
28602d9dd8
2 changed files with 112 additions and 78 deletions
|
@ -246,6 +246,14 @@ pub trait CustomOnionMessageHandler {
|
|||
fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError>;
|
||||
}
|
||||
|
||||
/// A processed incoming onion message, containing either a Forward (another onion message)
|
||||
/// or a Receive payload with decrypted contents.
|
||||
pub enum PeeledOnion<CM: CustomOnionMessageContents> {
|
||||
/// Forwarded onion, with the next node id and a new onion
|
||||
Forward(PublicKey, msgs::OnionMessage),
|
||||
/// Received onion message, with decrypted contents, path_id, and reply path
|
||||
Receive(OnionMessageContents<CM>, Option<[u8; 32]>, Option<BlindedPath>)
|
||||
}
|
||||
|
||||
/// Create an onion message with contents `message` to the destination of `path`.
|
||||
/// Returns (introduction_node_id, onion_msg)
|
||||
|
@ -304,6 +312,101 @@ where
|
|||
}))
|
||||
}
|
||||
|
||||
/// Decode one layer of an incoming onion message
|
||||
/// Returns either a Forward (another onion message), or Receive (decrypted content)
|
||||
pub fn peel_onion<NS: Deref, L: Deref, CMH: Deref>(
|
||||
node_signer: NS, secp_ctx: &Secp256k1<secp256k1::All>, logger: L, custom_handler: CMH,
|
||||
msg: &msgs::OnionMessage,
|
||||
) -> Result<PeeledOnion<<<CMH>::Target as CustomOnionMessageHandler>::CustomMessage>, ()>
|
||||
where
|
||||
NS::Target: NodeSigner,
|
||||
L::Target: Logger,
|
||||
CMH::Target: CustomOnionMessageHandler,
|
||||
{
|
||||
let control_tlvs_ss = match node_signer.ecdh(Recipient::Node, &msg.blinding_point, None) {
|
||||
Ok(ss) => ss,
|
||||
Err(e) => {
|
||||
log_error!(logger, "Failed to retrieve node secret: {:?}", e);
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
let onion_decode_ss = {
|
||||
let blinding_factor = {
|
||||
let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
|
||||
hmac.input(control_tlvs_ss.as_ref());
|
||||
Hmac::from_engine(hmac).into_inner()
|
||||
};
|
||||
match node_signer.ecdh(Recipient::Node, &msg.onion_routing_packet.public_key,
|
||||
Some(&Scalar::from_be_bytes(blinding_factor).unwrap()))
|
||||
{
|
||||
Ok(ss) => ss.secret_bytes(),
|
||||
Err(()) => {
|
||||
log_trace!(logger, "Failed to compute onion packet shared secret");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
};
|
||||
match onion_utils::decode_next_untagged_hop(
|
||||
onion_decode_ss, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac,
|
||||
(control_tlvs_ss, custom_handler.deref(), logger.deref())
|
||||
) {
|
||||
Ok((Payload::Receive::<<<CMH as Deref>::Target as CustomOnionMessageHandler>::CustomMessage> {
|
||||
message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path,
|
||||
}, None)) => {
|
||||
Ok(PeeledOnion::Receive(message, path_id, reply_path))
|
||||
},
|
||||
Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
|
||||
next_node_id, next_blinding_override
|
||||
})), Some((next_hop_hmac, new_packet_bytes)))) => {
|
||||
// TODO: we need to check whether `next_node_id` is our node, in which case this is a dummy
|
||||
// blinded hop and this onion message is destined for us. In this situation, we should keep
|
||||
// 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_pubkey(&secp_ctx, msg.onion_routing_packet.public_key, &onion_decode_ss) {
|
||||
Ok(pk) => pk,
|
||||
Err(e) => {
|
||||
log_trace!(logger, "Failed to compute next hop packet pubkey: {}", e);
|
||||
return Err(())
|
||||
}
|
||||
};
|
||||
let outgoing_packet = Packet {
|
||||
version: 0,
|
||||
public_key: new_pubkey,
|
||||
hop_data: new_packet_bytes,
|
||||
hmac: next_hop_hmac,
|
||||
};
|
||||
let onion_message = msgs::OnionMessage {
|
||||
blinding_point: match next_blinding_override {
|
||||
Some(blinding_point) => blinding_point,
|
||||
None => {
|
||||
match onion_utils::next_hop_pubkey(
|
||||
&secp_ctx, msg.blinding_point, control_tlvs_ss.as_ref()
|
||||
) {
|
||||
Ok(bp) => bp,
|
||||
Err(e) => {
|
||||
log_trace!(logger, "Failed to compute next blinding point: {}", e);
|
||||
return Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onion_routing_packet: outgoing_packet,
|
||||
};
|
||||
|
||||
Ok(PeeledOnion::Forward(next_node_id, onion_message))
|
||||
},
|
||||
Err(e) => {
|
||||
log_trace!(logger, "Errored decoding onion message packet: {:?}", e);
|
||||
Err(())
|
||||
},
|
||||
_ => {
|
||||
log_trace!(logger, "Received bogus onion message packet, either the sender encoded a final hop as a forwarding hop or vice versa");
|
||||
Err(())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl<ES: Deref, NS: Deref, L: Deref, MR: Deref, OMH: Deref, CMH: Deref>
|
||||
OnionMessenger<ES, NS, L, MR, OMH, CMH>
|
||||
where
|
||||
|
@ -457,40 +560,13 @@ where
|
|||
/// soon we'll delegate the onion message to a handler that can generate invoices or send
|
||||
/// payments.
|
||||
fn handle_onion_message(&self, _peer_node_id: &PublicKey, msg: &msgs::OnionMessage) {
|
||||
let control_tlvs_ss = match self.node_signer.ecdh(Recipient::Node, &msg.blinding_point, None) {
|
||||
Ok(ss) => ss,
|
||||
Err(e) => {
|
||||
log_error!(self.logger, "Failed to retrieve node secret: {:?}", e);
|
||||
return
|
||||
}
|
||||
};
|
||||
let onion_decode_ss = {
|
||||
let blinding_factor = {
|
||||
let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
|
||||
hmac.input(control_tlvs_ss.as_ref());
|
||||
Hmac::from_engine(hmac).into_inner()
|
||||
};
|
||||
match self.node_signer.ecdh(Recipient::Node, &msg.onion_routing_packet.public_key,
|
||||
Some(&Scalar::from_be_bytes(blinding_factor).unwrap()))
|
||||
{
|
||||
Ok(ss) => ss.secret_bytes(),
|
||||
Err(()) => {
|
||||
log_trace!(self.logger, "Failed to compute onion packet shared secret");
|
||||
return
|
||||
}
|
||||
}
|
||||
};
|
||||
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, &*self.logger)
|
||||
match peel_onion(
|
||||
&*self.node_signer, &self.secp_ctx, &*self.logger, &*self.custom_handler, msg
|
||||
) {
|
||||
Ok((Payload::Receive::<<<CMH as Deref>::Target as CustomOnionMessageHandler>::CustomMessage> {
|
||||
message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path,
|
||||
}, None)) => {
|
||||
Ok(PeeledOnion::Receive(message, path_id, reply_path)) => {
|
||||
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" });
|
||||
|
||||
let response = match message {
|
||||
OnionMessageContents::Offers(msg) => {
|
||||
self.offers_handler.handle_message(msg)
|
||||
|
@ -501,50 +577,11 @@ where
|
|||
.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 {
|
||||
next_node_id, next_blinding_override
|
||||
})), Some((next_hop_hmac, new_packet_bytes)))) => {
|
||||
// TODO: we need to check whether `next_node_id` is our node, in which case this is a dummy
|
||||
// blinded hop and this onion message is destined for us. In this situation, we should keep
|
||||
// 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_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);
|
||||
return
|
||||
}
|
||||
};
|
||||
let outgoing_packet = Packet {
|
||||
version: 0,
|
||||
public_key: new_pubkey,
|
||||
hop_data: new_packet_bytes,
|
||||
hmac: next_hop_hmac,
|
||||
};
|
||||
let onion_message = msgs::OnionMessage {
|
||||
blinding_point: match next_blinding_override {
|
||||
Some(blinding_point) => blinding_point,
|
||||
None => {
|
||||
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,
|
||||
};
|
||||
|
||||
Ok(PeeledOnion::Forward(next_node_id, onion_message)) => {
|
||||
let mut pending_per_peer_msgs = self.pending_messages.lock().unwrap();
|
||||
if outbound_buffer_full(&next_node_id, &pending_per_peer_msgs) {
|
||||
log_trace!(self.logger, "Dropping forwarded onion message to peer {:?}: outbound buffer full", next_node_id);
|
||||
|
@ -563,15 +600,12 @@ where
|
|||
e.get_mut().push_back(onion_message);
|
||||
log_trace!(self.logger, "Forwarding an onion message to peer {}", next_node_id);
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log_trace!(self.logger, "Errored decoding onion message packet: {:?}", e);
|
||||
},
|
||||
_ => {
|
||||
log_trace!(self.logger, "Received bogus onion message packet, either the sender encoded a final hop as a forwarding hop or vice versa");
|
||||
},
|
||||
};
|
||||
log_error!(self.logger, "Failed to process onion message {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn peer_connected(&self, their_node_id: &PublicKey, init: &msgs::Init, _inbound: bool) -> Result<(), ()> {
|
||||
|
|
|
@ -27,7 +27,7 @@ mod packet;
|
|||
mod functional_tests;
|
||||
|
||||
// Re-export structs so they can be imported with just the `onion_message::` module prefix.
|
||||
pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, DefaultMessageRouter, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
|
||||
pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, DefaultMessageRouter, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger, PeeledOnion, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
|
||||
pub use self::offers::{OffersMessage, OffersMessageHandler};
|
||||
pub use self::packet::Packet;
|
||||
pub(crate) use self::packet::ControlTlvs;
|
||||
|
|
Loading…
Add table
Reference in a new issue