Skip to content

Commit 588617e

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 8173dd7 commit 588617e

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed

lightning/src/ln/channelmanager.rs

+160
Original file line numberDiff line numberDiff line change
@@ -4299,13 +4299,173 @@ where
42994299
Ok(())
43004300
}
43014301

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

4467+
self.process_pending_update_add_htlcs();
4468+
43094469
let mut new_events = VecDeque::new();
43104470
let mut failed_forwards = Vec::new();
43114471
let mut phantom_receives: Vec<(u64, OutPoint, ChannelId, u128, Vec<(PendingHTLCInfo, u64)>)> = Vec::new();

0 commit comments

Comments
 (0)