use super::utils;
use util::events::OnionMessageProvider;
use util::logger::Logger;
+use util::ser::Writeable;
use core::ops::Deref;
use sync::{Arc, Mutex};
TooFewBlindedHops,
/// Our next-hop peer was offline or does not support onion message forwarding.
InvalidFirstHop,
+ /// Our next-hop peer's buffer was full or our total outbound buffer was full.
+ BufferFull,
}
impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
packet_payloads, packet_keys, prng_seed).map_err(|()| SendError::TooBigPacket)?;
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) => {
}
}
+fn outbound_buffer_full(peer_node_id: &PublicKey, buffer: &HashMap<PublicKey, VecDeque<msgs::OnionMessage>>) -> bool {
+ const MAX_TOTAL_BUFFER_SIZE: usize = (1 << 20) * 128;
+ const MAX_PER_PEER_BUFFER_SIZE: usize = (1 << 10) * 256;
+ let mut total_buffered_bytes = 0;
+ let mut peer_buffered_bytes = 0;
+ for (pk, peer_buf) in buffer {
+ for om in peer_buf {
+ let om_len = om.serialized_length();
+ if pk == peer_node_id {
+ peer_buffered_bytes += om_len;
+ }
+ total_buffered_bytes += om_len;
+
+ if total_buffered_bytes >= MAX_TOTAL_BUFFER_SIZE ||
+ peer_buffered_bytes >= MAX_PER_PEER_BUFFER_SIZE
+ {
+ return true
+ }
+ }
+ }
+ false
+}
+
impl<Signer: Sign, K: Deref, L: Deref> OnionMessageHandler for OnionMessenger<Signer, K, L>
where K::Target: KeysInterface<Signer = Signer>,
L::Target: Logger,
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 => {
+ 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()) {
+ Ok(bp) => bp,
+ Err(e) => {
+ log_trace!(self.logger, "Failed to compute next blinding point: {}", e);
+ return
+ }
+ }
+ },
+ },
+ onion_routing_packet: outgoing_packet,
+ };
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);
+ return
+ }
#[cfg(fuzzing)]
pending_per_peer_msgs.entry(next_node_id).or_insert_with(VecDeque::new);
return
},
hash_map::Entry::Occupied(mut e) => {
- e.get_mut().push_back(
- msgs::OnionMessage {
- 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()) {
- Ok(bp) => bp,
- Err(e) => {
- log_trace!(self.logger, "Failed to compute next blinding point: {}", e);
- return
- }
- }
- },
- },
- onion_routing_packet: outgoing_packet,
- },
- );
+ e.get_mut().push_back(onion_message);
log_trace!(self.logger, "Forwarding an onion message to peer {}", next_node_id);
}
};