Skip to content

Commit 8ba7bf7

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 8ba7bf7

File tree

1 file changed

+71
-13
lines changed

1 file changed

+71
-13
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 71 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,8 @@ pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L> = ChannelManage
690690
// `total_consistency_lock`
691691
// |
692692
// |__`forward_htlcs`
693+
// | |
694+
// | |__`pending_intercepted_payments`
693695
// |
694696
// |__`channel_state`
695697
// | |
@@ -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,82 @@ 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() {
5117-
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-
}
51215123
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-
}) {
5124+
let scid = match forward_info.routing {
5125+
PendingHTLCRouting::Forward { short_channel_id, .. } => short_channel_id,
5126+
PendingHTLCRouting::Receive { .. } => 0,
5127+
PendingHTLCRouting::ReceiveKeysend { .. } => 0,
5128+
};
5129+
// Pull this now to avoid introducing a lock order with `forward_htlcs`.
5130+
let our_scid = self.short_to_chan_info.read().unwrap().contains_key(&scid);
5131+
5132+
let mut forward_htlcs = self.forward_htlcs.lock().unwrap();
5133+
let forward_htlcs_empty = forward_htlcs.is_empty();
5134+
match forward_htlcs.entry(scid) {
51275135
hash_map::Entry::Occupied(mut entry) => {
51285136
entry.get_mut().push(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
51295137
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info }));
51305138
},
51315139
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 })));
5140+
if fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, scid, &self.genesis_hash)
5141+
&& !our_scid && forward_info.amt_incoming.is_some()
5142+
{
5143+
let intercept_id = InterceptId(Sha256::hash(&forward_info.incoming_shared_secret).into_inner());
5144+
let mut pending_intercepts = self.pending_intercepted_htlcs.lock().unwrap();
5145+
match pending_intercepts.entry(intercept_id) {
5146+
hash_map::Entry::Vacant(entry) => {
5147+
new_intercept_events.push(events::Event::HTLCIntercepted {
5148+
requested_next_hop_scid: scid,
5149+
payment_hash: forward_info.payment_hash,
5150+
inbound_amount_msat: forward_info.amt_incoming.unwrap(),
5151+
expected_outbound_amount_msat: forward_info.amt_to_forward,
5152+
intercept_id
5153+
});
5154+
entry.insert(PendingAddHTLCInfo {
5155+
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info });
5156+
},
5157+
hash_map::Entry::Occupied(_) => {
5158+
log_info!(self.logger, "Failed to forward incoming HTLC: detected duplicate intercepted payment over short channel id {}", scid);
5159+
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
5160+
short_channel_id: prev_short_channel_id,
5161+
outpoint: prev_funding_outpoint,
5162+
htlc_id: prev_htlc_id,
5163+
incoming_packet_shared_secret: forward_info.incoming_shared_secret,
5164+
phantom_shared_secret: None,
5165+
});
5166+
5167+
failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
5168+
HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() },
5169+
HTLCDestination::UnknownNextHop { requested_forward_scid: scid },
5170+
));
5171+
}
5172+
}
5173+
} else {
5174+
// We don't want to generate a PendingHTLCsForwardable event if only intercepted
5175+
// payments are being forwarded.
5176+
if forward_htlcs_empty {
5177+
forward_event = Some(Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS));
5178+
}
5179+
entry.insert(vec!(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
5180+
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info })));
5181+
}
51345182
}
51355183
}
51365184
}
51375185
}
5186+
5187+
for (htlc_source, payment_hash, failure_reason, destination) in failed_intercept_forwards.drain(..) {
5188+
self.fail_htlc_backwards_internal(htlc_source, &payment_hash, failure_reason, destination);
5189+
}
5190+
5191+
if !new_intercept_events.is_empty() {
5192+
let mut events = self.pending_events.lock().unwrap();
5193+
events.append(&mut new_intercept_events);
5194+
}
5195+
51385196
match forward_event {
51395197
Some(time) => {
51405198
let mut pending_events = self.pending_events.lock().unwrap();

0 commit comments

Comments
 (0)