Skip to content

Commit 59bfe6d

Browse files
committed
Decode update_add_htlc onions before forwarding HTLCs
This commit completes all of the groundwork necessary to decode incoming `update_add_htlc` onions once they're fully committed to by both sides. HTLCs are tracked in batches per-channel on the channel they were received on. While this path is unreachable for now, until `InboundHTLCResolution::Resolved` is replaced with `InboundHTLCResolution::Pending`, it will allow us to obtain `HTLCHandlingFailed` events for _any_ failed HTLC that comes across a channel.
1 parent c532f20 commit 59bfe6d

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed

lightning/src/ln/channelmanager.rs

+153
Original file line numberDiff line numberDiff line change
@@ -4295,13 +4295,166 @@ where
42954295
Ok(())
42964296
}
42974297

4298+
pub(crate) fn process_pending_update_add_htlcs(&self) {
4299+
let mut decode_update_add_htlcs = new_hash_map();
4300+
mem::swap(&mut decode_update_add_htlcs, &mut self.decode_update_add_htlcs.lock().unwrap());
4301+
4302+
let mut incoming_channel_htlc_fails = new_hash_map();
4303+
let mut htlc_forwards = Vec::new();
4304+
let mut htlc_fails = Vec::new();
4305+
for (incoming_scid, update_add_htlcs) in decode_update_add_htlcs {
4306+
let (incoming_counterparty_node_id, incoming_channel_id) =
4307+
match self.short_to_chan_info.read().unwrap().get(&incoming_scid).cloned() {
4308+
Some((cp_id, channel_id)) => (cp_id, channel_id),
4309+
None => continue,
4310+
};
4311+
let per_peer_state = self.per_peer_state.read().unwrap();
4312+
let peer_state_mutex_opt = per_peer_state.get(&incoming_counterparty_node_id);
4313+
if peer_state_mutex_opt.is_none() {
4314+
continue;
4315+
}
4316+
let mut peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
4317+
let peer_state = &mut *peer_state_lock;
4318+
let incoming_channel = match peer_state.channel_by_id.get_mut(&incoming_channel_id).map(
4319+
|chan_phase| if let ChannelPhase::Funded(chan) = chan_phase { Some(chan) } else { None }
4320+
).flatten() {
4321+
None => continue,
4322+
Some(chan) => chan,
4323+
};
4324+
4325+
// Since recursive locks are not allowed, we opt to process all the HTLCs in the
4326+
// incoming channel first, even though onion failures usually come first. If any of the
4327+
// HTLCs fail to be accepted, we temporarily track their failure until we decode their
4328+
// onion below.
4329+
let incoming_funding_txo = incoming_channel.context.get_funding_txo().unwrap();
4330+
let incoming_user_channel_id = incoming_channel.context.get_user_id();
4331+
let incoming_accept_underpaying_htlcs = incoming_channel.context.config().accept_underpaying_htlcs;
4332+
for update_add_htlc in &update_add_htlcs {
4333+
let logger = WithChannelContext::from(&self.logger, &incoming_channel.context);
4334+
if let Err((err, code)) = incoming_channel.can_accept_incoming_htlc(
4335+
update_add_htlc, &self.fee_estimator, &logger,
4336+
) {
4337+
incoming_channel_htlc_fails.insert(update_add_htlc.htlc_id, (err, code));
4338+
}
4339+
}
4340+
mem::drop(peer_state_lock);
4341+
mem::drop(per_peer_state);
4342+
4343+
for update_add_htlc in &update_add_htlcs {
4344+
// Retrieve the failure for the HTLC on the incoming channel if one exists. Onion
4345+
// failures and forwarding check failures take precedence over it.
4346+
let incoming_channel_htlc_fail = incoming_channel_htlc_fails.remove(&update_add_htlc.htlc_id);
4347+
4348+
let (next_hop, shared_secret, next_packet_details_opt) = match decode_incoming_update_add_htlc_onion(
4349+
&update_add_htlc, &self.node_signer, &self.logger, &self.secp_ctx
4350+
) {
4351+
Ok(decoded_onion) => decoded_onion,
4352+
Err(htlc_fail) => {
4353+
htlc_fails.push((htlc_fail, update_add_htlc.payment_hash, true, None));
4354+
continue;
4355+
},
4356+
};
4357+
4358+
let is_intro_node_blinded_forward = next_hop.is_intro_node_blinded_forward();
4359+
let outgoing_channel_packet_scid_opt = next_packet_details_opt.as_ref().map(|d| d.outgoing_scid);
4360+
4361+
// Now process the HTLC on the outgoing channel if it's a forward.
4362+
let outgoing_channel_update_opt = match next_packet_details_opt.as_ref() {
4363+
Some(next_packet_details) => match self.can_forward_htlc(
4364+
&update_add_htlc, &next_packet_details
4365+
) {
4366+
Ok(chan_update_opt) => chan_update_opt,
4367+
Err((err, code, chan_update_opt)) => {
4368+
let htlc_fail = self.htlc_failure_from_update_add_err(
4369+
&update_add_htlc, &incoming_counterparty_node_id, err, code,
4370+
chan_update_opt, is_intro_node_blinded_forward, &shared_secret,
4371+
);
4372+
htlc_fails.push((htlc_fail, update_add_htlc.payment_hash, false, outgoing_channel_packet_scid_opt));
4373+
continue;
4374+
},
4375+
}
4376+
None => None,
4377+
};
4378+
4379+
// With the HTLC accepted by the outgoing channel and (potentially) the incoming
4380+
// channel, we can gather all of the info required internally to forward it.
4381+
match self.construct_pending_htlc_status(
4382+
&update_add_htlc, &incoming_counterparty_node_id, shared_secret, next_hop,
4383+
incoming_accept_underpaying_htlcs, next_packet_details_opt.map(|d| d.next_packet_pubkey),
4384+
) {
4385+
PendingHTLCStatus::Forward(htlc_forward) => {
4386+
// Now that we know we can forward it for sure, check if we had a failure on
4387+
// the incoming channel.
4388+
if let Some((err, code)) = incoming_channel_htlc_fail {
4389+
let htlc_fail = self.htlc_failure_from_update_add_err(
4390+
&update_add_htlc, &incoming_counterparty_node_id, err, code,
4391+
outgoing_channel_update_opt, is_intro_node_blinded_forward, &shared_secret,
4392+
);
4393+
htlc_fails.push((htlc_fail, update_add_htlc.payment_hash, false, outgoing_channel_packet_scid_opt));
4394+
} else {
4395+
htlc_forwards.push((htlc_forward, update_add_htlc.htlc_id));
4396+
}
4397+
},
4398+
PendingHTLCStatus::Fail(htlc_fail) => {
4399+
htlc_fails.push((htlc_fail, update_add_htlc.payment_hash, false, outgoing_channel_packet_scid_opt));
4400+
},
4401+
}
4402+
}
4403+
debug_assert!(incoming_channel_htlc_fails.is_empty());
4404+
4405+
// Process all of the forwards and failures for the channel in which the HTLCs were
4406+
// proposed to as a batch.
4407+
let pending_forwards = (incoming_scid, incoming_funding_txo, incoming_channel_id,
4408+
incoming_user_channel_id, htlc_forwards.drain(..).collect());
4409+
self.forward_htlcs_without_forward_event(&mut [pending_forwards]);
4410+
4411+
for (htlc_fail, payment_hash, is_invalid_onion, outgoing_scid) in htlc_fails.drain(..) {
4412+
let failure = match htlc_fail {
4413+
HTLCFailureMsg::Relay(fail_htlc) => HTLCForwardInfo::FailHTLC {
4414+
htlc_id: fail_htlc.htlc_id,
4415+
err_packet: fail_htlc.reason,
4416+
},
4417+
HTLCFailureMsg::Malformed(fail_malformed_htlc) => HTLCForwardInfo::FailMalformedHTLC {
4418+
htlc_id: fail_malformed_htlc.htlc_id,
4419+
sha256_of_onion: fail_malformed_htlc.sha256_of_onion,
4420+
failure_code: fail_malformed_htlc.failure_code,
4421+
},
4422+
};
4423+
let destination = if is_invalid_onion {
4424+
HTLCDestination::InvalidOnion
4425+
} else if let Some(outgoing_scid) = outgoing_scid {
4426+
match self.short_to_chan_info.read().unwrap().get(&outgoing_scid) {
4427+
Some((outgoing_counterparty_node_id, outgoing_channel_id)) =>
4428+
HTLCDestination::NextHopChannel {
4429+
node_id: Some(*outgoing_counterparty_node_id),
4430+
channel_id: *outgoing_channel_id,
4431+
},
4432+
None => HTLCDestination::UnknownNextHop {
4433+
requested_forward_scid: outgoing_scid,
4434+
},
4435+
}
4436+
} else {
4437+
HTLCDestination::FailedPayment { payment_hash }
4438+
};
4439+
4440+
self.forward_htlcs.lock().unwrap().entry(incoming_scid).or_insert(vec![]).push(failure);
4441+
self.pending_events.lock().unwrap().push_back((events::Event::HTLCHandlingFailed {
4442+
prev_channel_id: incoming_channel_id,
4443+
failed_next_destination: destination,
4444+
}, None));
4445+
}
4446+
}
4447+
}
4448+
42984449
/// Processes HTLCs which are pending waiting on random forward delay.
42994450
///
43004451
/// Should only really ever be called in response to a PendingHTLCsForwardable event.
43014452
/// Will likely generate further events.
43024453
pub fn process_pending_htlc_forwards(&self) {
43034454
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
43044455

4456+
self.process_pending_update_add_htlcs();
4457+
43054458
let mut new_events = VecDeque::new();
43064459
let mut failed_forwards = Vec::new();
43074460
let mut phantom_receives: Vec<(u64, OutPoint, ChannelId, u128, Vec<(PendingHTLCInfo, u64)>)> = Vec::new();

0 commit comments

Comments
 (0)