Skip to content

Commit d1e9231

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 857d225 commit d1e9231

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
@@ -4304,13 +4304,173 @@ where
43044304
Ok(())
43054305
}
43064306

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

4472+
self.process_pending_update_add_htlcs();
4473+
43144474
let mut new_events = VecDeque::new();
43154475
let mut failed_forwards = Vec::new();
43164476
let mut phantom_receives: Vec<(u64, OutPoint, ChannelId, u128, Vec<(PendingHTLCInfo, u64)>)> = Vec::new();

0 commit comments

Comments
 (0)