Skip to content

Commit e2b406e

Browse files
Generate PaymentInterceptedEvent upon interceptable forward
And store the pending intercepted HTLC in pending_intercepted_payments Co-authored-by: John Cantrell <johncantrell97@gmail.com> Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
1 parent 3d03c26 commit e2b406e

File tree

1 file changed

+69
-12
lines changed

1 file changed

+69
-12
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,8 @@ pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L> = ChannelManage
696696
// | |__`id_to_peer`
697697
// | |
698698
// | |__`short_to_chan_info`
699+
// | | |
700+
// | | |__`pending_intercepted_payments`
699701
// | |
700702
// | |__`per_peer_state`
701703
// | |
@@ -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) {
2339+
// phantom or an intercept.
2340+
if fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, *short_channel_id) ||
2341+
fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, *short_channel_id)
2342+
{
23392343
None
23402344
} else {
23412345
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
@@ -5115,28 +5119,81 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
51155119
fn forward_htlcs(&self, per_source_pending_forwards: &mut [(u64, OutPoint, Vec<(PendingHTLCInfo, u64)>)]) {
51165120
for &mut (prev_short_channel_id, prev_funding_outpoint, ref mut pending_forwards) in per_source_pending_forwards {
51175121
let mut forward_event = None;
5122+
let mut new_intercept_events = Vec::new();
5123+
let mut failed_intercept_forwards = Vec::new();
51185124
if !pending_forwards.is_empty() {
51195125
let mut forward_htlcs = self.forward_htlcs.lock().unwrap();
5120-
if forward_htlcs.is_empty() {
5121-
forward_event = Some(Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS))
5122-
}
5126+
let short_to_chan_info = self.short_to_chan_info.read().unwrap();
51235127
for (forward_info, prev_htlc_id) in pending_forwards.drain(..) {
5124-
match forward_htlcs.entry(match forward_info.routing {
5125-
PendingHTLCRouting::Forward { short_channel_id, .. } => short_channel_id,
5126-
PendingHTLCRouting::Receive { .. } => 0,
5127-
PendingHTLCRouting::ReceiveKeysend { .. } => 0,
5128-
}) {
5128+
let scid = match forward_info.routing {
5129+
PendingHTLCRouting::Forward { short_channel_id, .. } => short_channel_id,
5130+
PendingHTLCRouting::Receive { .. } => 0,
5131+
PendingHTLCRouting::ReceiveKeysend { .. } => 0,
5132+
};
5133+
let forward_htlcs_empty = forward_htlcs.is_empty();
5134+
match forward_htlcs.entry(scid) {
51295135
hash_map::Entry::Occupied(mut entry) => {
51305136
entry.get_mut().push(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
51315137
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info }));
51325138
},
51335139
hash_map::Entry::Vacant(entry) => {
5134-
entry.insert(vec!(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
5135-
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info })));
5140+
if !short_to_chan_info.contains_key(&scid) &&
5141+
forward_info.amt_incoming.is_some() &&
5142+
fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, scid)
5143+
{
5144+
let intercept_id = InterceptId(Sha256::hash(&forward_info.incoming_shared_secret).into_inner());
5145+
let mut pending_intercepts = self.pending_intercepted_payments.lock().unwrap();
5146+
match pending_intercepts.entry(intercept_id) {
5147+
hash_map::Entry::Vacant(entry) => {
5148+
new_intercept_events.push(events::Event::PaymentIntercepted {
5149+
short_channel_id: scid,
5150+
payment_hash: forward_info.payment_hash,
5151+
inbound_amount_msat: forward_info.amt_incoming.unwrap(),
5152+
expected_outbound_amount_msat: forward_info.amt_to_forward,
5153+
intercept_id
5154+
});
5155+
entry.insert(PendingAddHTLCInfo {
5156+
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info });
5157+
},
5158+
hash_map::Entry::Occupied(_) => {
5159+
log_info!(self.logger, "Failed to forward incoming HTLC: detected duplicate intercepted payment over short channel id {}", scid);
5160+
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
5161+
short_channel_id: prev_short_channel_id,
5162+
outpoint: prev_funding_outpoint,
5163+
htlc_id: prev_htlc_id,
5164+
incoming_packet_shared_secret: forward_info.incoming_shared_secret,
5165+
phantom_shared_secret: None,
5166+
});
5167+
5168+
failed_intercept_forwards.push((htlc_source, forward_info.payment_hash,
5169+
HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() },
5170+
HTLCDestination::UnknownNextHop { requested_forward_scid: scid },
5171+
));
5172+
}
5173+
}
5174+
} else {
5175+
// We don't want to generate a PendingHTLCsForwardable event if only intercepted
5176+
// payments are being forwarded.
5177+
if forward_htlcs_empty {
5178+
forward_event = Some(Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS));
5179+
}
5180+
entry.insert(vec!(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
5181+
prev_short_channel_id, prev_funding_outpoint, prev_htlc_id, forward_info })));
5182+
}
51365183
}
51375184
}
51385185
}
51395186
}
5187+
5188+
for (htlc_source, payment_hash, failure_reason, destination) in failed_intercept_forwards.drain(..) {
5189+
self.fail_htlc_backwards_internal(htlc_source, &payment_hash, failure_reason, destination);
5190+
}
5191+
5192+
if !new_intercept_events.is_empty() {
5193+
let mut events = self.pending_events.lock().unwrap();
5194+
events.append(&mut new_intercept_events);
5195+
}
5196+
51405197
match forward_event {
51415198
Some(time) => {
51425199
let mut pending_events = self.pending_events.lock().unwrap();

0 commit comments

Comments
 (0)