mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-24 23:08:36 +01:00
Generate HTLCIntercepted event upon interceptable forward
And store the pending intercepted HTLC in pending_intercepted_htlcs Co-authored-by: John Cantrell <johncantrell97@gmail.com> Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
This commit is contained in:
parent
5efc1976cd
commit
8fe7cbe921
2 changed files with 83 additions and 16 deletions
|
@ -92,8 +92,8 @@ use core::ops::Deref;
|
|||
pub(super) enum PendingHTLCRouting {
|
||||
Forward {
|
||||
onion_packet: msgs::OnionPacket,
|
||||
/// The SCID from the onion that we should forward to. This could be a "real" SCID, an
|
||||
/// outbound SCID alias, or a phantom node SCID.
|
||||
/// The SCID from the onion that we should forward to. This could be a real SCID or a fake one
|
||||
/// generated using `get_fake_scid` from the scid_utils::fake_scid module.
|
||||
short_channel_id: u64, // This should be NonZero<u64> eventually when we bump MSRV
|
||||
},
|
||||
Receive {
|
||||
|
@ -684,6 +684,8 @@ pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L> = ChannelManage
|
|||
// `total_consistency_lock`
|
||||
// |
|
||||
// |__`forward_htlcs`
|
||||
// | |
|
||||
// | |__`pending_intercepted_htlcs`
|
||||
// |
|
||||
// |__`pending_inbound_payments`
|
||||
// | |
|
||||
|
@ -2230,8 +2232,10 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
|
|||
let forwarding_id_opt = match id_option {
|
||||
None => { // unknown_next_peer
|
||||
// Note that this is likely a timing oracle for detecting whether an scid is a
|
||||
// phantom.
|
||||
if fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash) {
|
||||
// phantom or an intercept.
|
||||
if fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash) ||
|
||||
fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash)
|
||||
{
|
||||
None
|
||||
} else {
|
||||
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
|
||||
|
@ -5091,28 +5095,82 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
|
|||
fn forward_htlcs(&self, per_source_pending_forwards: &mut [(u64, OutPoint, u128, Vec<(PendingHTLCInfo, u64)>)]) {
|
||||
for &mut (prev_short_channel_id, prev_funding_outpoint, prev_user_channel_id, ref mut pending_forwards) in per_source_pending_forwards {
|
||||
let mut forward_event = None;
|
||||
let mut new_intercept_events = Vec::new();
|
||||
let mut failed_intercept_forwards = Vec::new();
|
||||
if !pending_forwards.is_empty() {
|
||||
let mut forward_htlcs = self.forward_htlcs.lock().unwrap();
|
||||
if forward_htlcs.is_empty() {
|
||||
forward_event = Some(Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS))
|
||||
}
|
||||
for (forward_info, prev_htlc_id) in pending_forwards.drain(..) {
|
||||
match forward_htlcs.entry(match forward_info.routing {
|
||||
let scid = match forward_info.routing {
|
||||
PendingHTLCRouting::Forward { short_channel_id, .. } => short_channel_id,
|
||||
PendingHTLCRouting::Receive { .. } => 0,
|
||||
PendingHTLCRouting::ReceiveKeysend { .. } => 0,
|
||||
}) {
|
||||
};
|
||||
// Pull this now to avoid introducing a lock order with `forward_htlcs`.
|
||||
let is_our_scid = self.short_to_chan_info.read().unwrap().contains_key(&scid);
|
||||
|
||||
let mut forward_htlcs = self.forward_htlcs.lock().unwrap();
|
||||
let forward_htlcs_empty = forward_htlcs.is_empty();
|
||||
match forward_htlcs.entry(scid) {
|
||||
hash_map::Entry::Occupied(mut entry) => {
|
||||
entry.get_mut().push(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
|
||||
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, prev_user_channel_id, forward_info }));
|
||||
},
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
if !is_our_scid && forward_info.incoming_amt_msat.is_some() &&
|
||||
fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, scid, &self.genesis_hash)
|
||||
{
|
||||
let intercept_id = InterceptId(Sha256::hash(&forward_info.incoming_shared_secret).into_inner());
|
||||
let mut pending_intercepts = self.pending_intercepted_htlcs.lock().unwrap();
|
||||
match pending_intercepts.entry(intercept_id) {
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
new_intercept_events.push(events::Event::HTLCIntercepted {
|
||||
requested_next_hop_scid: scid,
|
||||
payment_hash: forward_info.payment_hash,
|
||||
inbound_amount_msat: forward_info.incoming_amt_msat.unwrap(),
|
||||
expected_outbound_amount_msat: forward_info.outgoing_amt_msat,
|
||||
intercept_id
|
||||
});
|
||||
entry.insert(PendingAddHTLCInfo {
|
||||
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, prev_user_channel_id, forward_info });
|
||||
},
|
||||
hash_map::Entry::Occupied(_) => {
|
||||
log_info!(self.logger, "Failed to forward incoming HTLC: detected duplicate intercepted payment over short channel id {}", scid);
|
||||
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
|
||||
short_channel_id: prev_short_channel_id,
|
||||
outpoint: prev_funding_outpoint,
|
||||
htlc_id: prev_htlc_id,
|
||||
incoming_packet_shared_secret: forward_info.incoming_shared_secret,
|
||||
phantom_shared_secret: None,
|
||||
});
|
||||
|
||||
failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
|
||||
HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() },
|
||||
HTLCDestination::InvalidForward { requested_forward_scid: scid },
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We don't want to generate a PendingHTLCsForwardable event if only intercepted
|
||||
// payments are being processed.
|
||||
if forward_htlcs_empty {
|
||||
forward_event = Some(Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS));
|
||||
}
|
||||
entry.insert(vec!(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
|
||||
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, prev_user_channel_id, forward_info })));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (htlc_source, payment_hash, failure_reason, destination) in failed_intercept_forwards.drain(..) {
|
||||
self.fail_htlc_backwards_internal(htlc_source, &payment_hash, failure_reason, destination);
|
||||
}
|
||||
|
||||
if !new_intercept_events.is_empty() {
|
||||
let mut events = self.pending_events.lock().unwrap();
|
||||
events.append(&mut new_intercept_events);
|
||||
}
|
||||
|
||||
match forward_event {
|
||||
Some(time) => {
|
||||
let mut pending_events = self.pending_events.lock().unwrap();
|
||||
|
|
|
@ -182,6 +182,12 @@ pub enum HTLCDestination {
|
|||
/// Short channel id we are requesting to forward an HTLC to.
|
||||
requested_forward_scid: u64,
|
||||
},
|
||||
/// We couldn't forward to the outgoing scid. An example would be attempting to send a duplicate
|
||||
/// intercept HTLC.
|
||||
InvalidForward {
|
||||
/// Short channel id we are requesting to forward an HTLC to.
|
||||
requested_forward_scid: u64
|
||||
},
|
||||
/// Failure scenario where an HTLC may have been forwarded to be intended for us,
|
||||
/// but is invalid for some reason, so we reject it.
|
||||
///
|
||||
|
@ -200,12 +206,15 @@ impl_writeable_tlv_based_enum_upgradable!(HTLCDestination,
|
|||
(0, node_id, required),
|
||||
(2, channel_id, required),
|
||||
},
|
||||
(1, InvalidForward) => {
|
||||
(0, requested_forward_scid, required),
|
||||
},
|
||||
(2, UnknownNextHop) => {
|
||||
(0, requested_forward_scid, required),
|
||||
},
|
||||
(4, FailedPayment) => {
|
||||
(0, payment_hash, required),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
#[cfg(anchors)]
|
||||
|
|
Loading…
Add table
Reference in a new issue