mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-25 07:17:40 +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 {
|
pub(super) enum PendingHTLCRouting {
|
||||||
Forward {
|
Forward {
|
||||||
onion_packet: msgs::OnionPacket,
|
onion_packet: msgs::OnionPacket,
|
||||||
/// The SCID from the onion that we should forward to. This could be a "real" SCID, an
|
/// The SCID from the onion that we should forward to. This could be a real SCID or a fake one
|
||||||
/// outbound SCID alias, or a phantom node SCID.
|
/// 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
|
short_channel_id: u64, // This should be NonZero<u64> eventually when we bump MSRV
|
||||||
},
|
},
|
||||||
Receive {
|
Receive {
|
||||||
|
@ -684,6 +684,8 @@ pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L> = ChannelManage
|
||||||
// `total_consistency_lock`
|
// `total_consistency_lock`
|
||||||
// |
|
// |
|
||||||
// |__`forward_htlcs`
|
// |__`forward_htlcs`
|
||||||
|
// | |
|
||||||
|
// | |__`pending_intercepted_htlcs`
|
||||||
// |
|
// |
|
||||||
// |__`pending_inbound_payments`
|
// |__`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 {
|
let forwarding_id_opt = match id_option {
|
||||||
None => { // unknown_next_peer
|
None => { // unknown_next_peer
|
||||||
// Note that this is likely a timing oracle for detecting whether an scid is a
|
// Note that this is likely a timing oracle for detecting whether an scid is a
|
||||||
// phantom.
|
// phantom or an intercept.
|
||||||
if fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash) {
|
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
|
None
|
||||||
} else {
|
} else {
|
||||||
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
|
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)>)]) {
|
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 {
|
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 forward_event = None;
|
||||||
|
let mut new_intercept_events = Vec::new();
|
||||||
|
let mut failed_intercept_forwards = Vec::new();
|
||||||
if !pending_forwards.is_empty() {
|
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(..) {
|
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::Forward { short_channel_id, .. } => short_channel_id,
|
||||||
PendingHTLCRouting::Receive { .. } => 0,
|
PendingHTLCRouting::Receive { .. } => 0,
|
||||||
PendingHTLCRouting::ReceiveKeysend { .. } => 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) => {
|
hash_map::Entry::Occupied(mut entry) => {
|
||||||
entry.get_mut().push(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
|
entry.get_mut().push(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
|
||||||
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, prev_user_channel_id, forward_info }));
|
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, prev_user_channel_id, forward_info }));
|
||||||
},
|
},
|
||||||
hash_map::Entry::Vacant(entry) => {
|
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 {
|
entry.insert(vec!(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
|
||||||
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, prev_user_channel_id, forward_info })));
|
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 {
|
match forward_event {
|
||||||
Some(time) => {
|
Some(time) => {
|
||||||
let mut pending_events = self.pending_events.lock().unwrap();
|
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.
|
/// Short channel id we are requesting to forward an HTLC to.
|
||||||
requested_forward_scid: u64,
|
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,
|
/// Failure scenario where an HTLC may have been forwarded to be intended for us,
|
||||||
/// but is invalid for some reason, so we reject it.
|
/// 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),
|
(0, node_id, required),
|
||||||
(2, channel_id, required),
|
(2, channel_id, required),
|
||||||
},
|
},
|
||||||
|
(1, InvalidForward) => {
|
||||||
|
(0, requested_forward_scid, required),
|
||||||
|
},
|
||||||
(2, UnknownNextHop) => {
|
(2, UnknownNextHop) => {
|
||||||
(0, requested_forward_scid, required),
|
(0, requested_forward_scid, required),
|
||||||
},
|
},
|
||||||
(4, FailedPayment) => {
|
(4, FailedPayment) => {
|
||||||
(0, payment_hash, required),
|
(0, payment_hash, required),
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(anchors)]
|
#[cfg(anchors)]
|
||||||
|
|
Loading…
Add table
Reference in a new issue