Skip to content

Commit f0f2ed2

Browse files
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>
1 parent a1bab1d commit f0f2ed2

File tree

1 file changed

+68
-12
lines changed

1 file changed

+68
-12
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,8 @@ pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L> = ChannelManage
691691
// |
692692
// |__`forward_htlcs`
693693
// |
694+
// |__`pending_intercepted_payments`
695+
// |
694696
// |__`channel_state`
695697
// | |
696698
// | |__`id_to_peer`
@@ -2334,8 +2336,10 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
23342336
let forwarding_id_opt = match id_option {
23352337
None => { // unknown_next_peer
23362338
// Note that this is likely a timing oracle for detecting whether an scid is a
2337-
// phantom.
2338-
if fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash) {
2339+
// phantom or an intercept.
2340+
if fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash) ||
2341+
fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash)
2342+
{
23392343
None
23402344
} else {
23412345
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
@@ -5113,28 +5117,80 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
51135117
fn forward_htlcs(&self, per_source_pending_forwards: &mut [(u64, OutPoint, Vec<(PendingHTLCInfo, u64)>)]) {
51145118
for &mut (prev_short_channel_id, prev_funding_outpoint, ref mut pending_forwards) in per_source_pending_forwards {
51155119
let mut forward_event = None;
5120+
let mut new_intercept_events = Vec::new();
5121+
let mut failed_intercept_forwards = Vec::new();
51165122
if !pending_forwards.is_empty() {
51175123
let mut forward_htlcs = self.forward_htlcs.lock().unwrap();
5118-
if forward_htlcs.is_empty() {
5119-
forward_event = Some(Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS))
5120-
}
51215124
for (forward_info, prev_htlc_id) in pending_forwards.drain(..) {
5122-
match forward_htlcs.entry(match forward_info.routing {
5123-
PendingHTLCRouting::Forward { short_channel_id, .. } => short_channel_id,
5124-
PendingHTLCRouting::Receive { .. } => 0,
5125-
PendingHTLCRouting::ReceiveKeysend { .. } => 0,
5126-
}) {
5125+
let scid = match forward_info.routing {
5126+
PendingHTLCRouting::Forward { short_channel_id, .. } => short_channel_id,
5127+
PendingHTLCRouting::Receive { .. } => 0,
5128+
PendingHTLCRouting::ReceiveKeysend { .. } => 0,
5129+
};
5130+
let forward_htlcs_empty = forward_htlcs.is_empty();
5131+
match forward_htlcs.entry(scid) {
51275132
hash_map::Entry::Occupied(mut entry) => {
51285133
entry.get_mut().push(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
51295134
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info }));
51305135
},
51315136
hash_map::Entry::Vacant(entry) => {
5132-
entry.insert(vec!(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
5133-
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info })));
5137+
if !self.short_to_chan_info.read().unwrap().contains_key(&scid) &&
5138+
forward_info.amt_incoming.is_some() &&
5139+
fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, scid, &self.genesis_hash)
5140+
{
5141+
let intercept_id = InterceptId(Sha256::hash(&forward_info.incoming_shared_secret).into_inner());
5142+
let mut pending_intercepts = self.pending_intercepted_htlcs.lock().unwrap();
5143+
match pending_intercepts.entry(intercept_id) {
5144+
hash_map::Entry::Vacant(entry) => {
5145+
new_intercept_events.push(events::Event::HTLCIntercepted {
5146+
requested_next_hop_scid: scid,
5147+
payment_hash: forward_info.payment_hash,
5148+
inbound_amount_msat: forward_info.amt_incoming.unwrap(),
5149+
expected_outbound_amount_msat: forward_info.amt_to_forward,
5150+
intercept_id
5151+
});
5152+
entry.insert(PendingAddHTLCInfo {
5153+
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info });
5154+
},
5155+
hash_map::Entry::Occupied(_) => {
5156+
log_info!(self.logger, "Failed to forward incoming HTLC: detected duplicate intercepted payment over short channel id {}", scid);
5157+
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
5158+
short_channel_id: prev_short_channel_id,
5159+
outpoint: prev_funding_outpoint,
5160+
htlc_id: prev_htlc_id,
5161+
incoming_packet_shared_secret: forward_info.incoming_shared_secret,
5162+
phantom_shared_secret: None,
5163+
});
5164+
5165+
failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
5166+
HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() },
5167+
HTLCDestination::UnknownNextHop { requested_forward_scid: scid },
5168+
));
5169+
}
5170+
}
5171+
} else {
5172+
// We don't want to generate a PendingHTLCsForwardable event if only intercepted
5173+
// payments are being forwarded.
5174+
if forward_htlcs_empty {
5175+
forward_event = Some(Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS));
5176+
}
5177+
entry.insert(vec!(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
5178+
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info })));
5179+
}
51345180
}
51355181
}
51365182
}
51375183
}
5184+
5185+
for (htlc_source, payment_hash, failure_reason, destination) in failed_intercept_forwards.drain(..) {
5186+
self.fail_htlc_backwards_internal(htlc_source, &payment_hash, failure_reason, destination);
5187+
}
5188+
5189+
if !new_intercept_events.is_empty() {
5190+
let mut events = self.pending_events.lock().unwrap();
5191+
events.append(&mut new_intercept_events);
5192+
}
5193+
51385194
match forward_event {
51395195
Some(time) => {
51405196
let mut pending_events = self.pending_events.lock().unwrap();

0 commit comments

Comments
 (0)