Skip to content

Commit fe65648

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 a6c9128 commit fe65648

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed

lightning/src/ln/channelmanager.rs

+141
Original file line numberDiff line numberDiff line change
@@ -4304,13 +4304,154 @@ where
43044304
Ok(())
43054305
}
43064306

4307+
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 get_failed_htlc_destination = |outgoing_scid_opt: Option<u64>, payment_hash: PaymentHash| {
4312+
if let Some(outgoing_scid) = outgoing_scid_opt {
4313+
match self.short_to_chan_info.read().unwrap().get(&outgoing_scid) {
4314+
Some((outgoing_counterparty_node_id, outgoing_channel_id)) =>
4315+
HTLCDestination::NextHopChannel {
4316+
node_id: Some(*outgoing_counterparty_node_id),
4317+
channel_id: *outgoing_channel_id,
4318+
},
4319+
None => HTLCDestination::UnknownNextHop {
4320+
requested_forward_scid: outgoing_scid,
4321+
},
4322+
}
4323+
} else {
4324+
HTLCDestination::FailedPayment { payment_hash }
4325+
}
4326+
};
4327+
4328+
'outer_loop: for (incoming_scid, update_add_htlcs) in decode_update_add_htlcs {
4329+
let incoming_channel_details_opt = self.do_funded_channel_callback(incoming_scid, |chan: &mut Channel<SP>| {
4330+
let counterparty_node_id = chan.context.get_counterparty_node_id();
4331+
let channel_id = chan.context.channel_id();
4332+
let funding_txo = chan.context.get_funding_txo().unwrap();
4333+
let user_channel_id = chan.context.get_user_id();
4334+
let accept_underpaying_htlcs = chan.context.config().accept_underpaying_htlcs;
4335+
(counterparty_node_id, channel_id, funding_txo, user_channel_id, accept_underpaying_htlcs)
4336+
});
4337+
let (
4338+
incoming_counterparty_node_id, incoming_channel_id, incoming_funding_txo,
4339+
incoming_user_channel_id, incoming_accept_underpaying_htlcs
4340+
) = if let Some(incoming_channel_details) = incoming_channel_details_opt {
4341+
incoming_channel_details
4342+
} else {
4343+
// The incoming channel no longer exists, HTLCs should be resolved onchain instead.
4344+
continue;
4345+
};
4346+
4347+
let mut htlc_forwards = Vec::new();
4348+
let mut htlc_fails = Vec::new();
4349+
for update_add_htlc in &update_add_htlcs {
4350+
let (next_hop, shared_secret, next_packet_details_opt) = match decode_incoming_update_add_htlc_onion(
4351+
&update_add_htlc, &self.node_signer, &self.logger, &self.secp_ctx
4352+
) {
4353+
Ok(decoded_onion) => decoded_onion,
4354+
Err(htlc_fail) => {
4355+
htlc_fails.push((htlc_fail, HTLCDestination::InvalidOnion));
4356+
continue;
4357+
},
4358+
};
4359+
4360+
let is_intro_node_blinded_forward = next_hop.is_intro_node_blinded_forward();
4361+
let outgoing_scid_opt = next_packet_details_opt.as_ref().map(|d| d.outgoing_scid);
4362+
4363+
// Process the HTLC on the incoming channel.
4364+
match self.do_funded_channel_callback(incoming_scid, |chan: &mut Channel<SP>| {
4365+
let logger = WithChannelContext::from(&self.logger, &chan.context);
4366+
chan.can_accept_incoming_htlc(
4367+
update_add_htlc, &self.fee_estimator, &logger,
4368+
)
4369+
}) {
4370+
Some(Ok(_)) => {},
4371+
Some(Err((err, code))) => {
4372+
let outgoing_chan_update_opt = if let Some(outgoing_scid) = outgoing_scid_opt.as_ref() {
4373+
self.do_funded_channel_callback(*outgoing_scid, |chan: &mut Channel<SP>| {
4374+
self.get_channel_update_for_onion(*outgoing_scid, chan).ok()
4375+
}).flatten()
4376+
} else {
4377+
None
4378+
};
4379+
let htlc_fail = self.htlc_failure_from_update_add_err(
4380+
&update_add_htlc, &incoming_counterparty_node_id, err, code,
4381+
outgoing_chan_update_opt, is_intro_node_blinded_forward, &shared_secret,
4382+
);
4383+
let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash);
4384+
htlc_fails.push((htlc_fail, htlc_destination));
4385+
continue;
4386+
},
4387+
// The incoming channel no longer exists, HTLCs should be resolved onchain instead.
4388+
None => continue 'outer_loop,
4389+
}
4390+
4391+
// Now process the HTLC on the outgoing channel if it's a forward.
4392+
if let Some(next_packet_details) = next_packet_details_opt.as_ref() {
4393+
if let Err((err, code, chan_update_opt)) = self.can_forward_htlc(
4394+
&update_add_htlc, next_packet_details
4395+
) {
4396+
let htlc_fail = self.htlc_failure_from_update_add_err(
4397+
&update_add_htlc, &incoming_counterparty_node_id, err, code,
4398+
chan_update_opt, is_intro_node_blinded_forward, &shared_secret,
4399+
);
4400+
let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash);
4401+
htlc_fails.push((htlc_fail, htlc_destination));
4402+
continue;
4403+
}
4404+
}
4405+
4406+
match self.construct_pending_htlc_status(
4407+
&update_add_htlc, &incoming_counterparty_node_id, shared_secret, next_hop,
4408+
incoming_accept_underpaying_htlcs, next_packet_details_opt.map(|d| d.next_packet_pubkey),
4409+
) {
4410+
PendingHTLCStatus::Forward(htlc_forward) => {
4411+
htlc_forwards.push((htlc_forward, update_add_htlc.htlc_id));
4412+
},
4413+
PendingHTLCStatus::Fail(htlc_fail) => {
4414+
let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash);
4415+
htlc_fails.push((htlc_fail, htlc_destination));
4416+
},
4417+
}
4418+
}
4419+
4420+
// Process all of the forwards and failures for the channel in which the HTLCs were
4421+
// proposed to as a batch.
4422+
let pending_forwards = (incoming_scid, incoming_funding_txo, incoming_channel_id,
4423+
incoming_user_channel_id, htlc_forwards.drain(..).collect());
4424+
self.forward_htlcs_without_forward_event(&mut [pending_forwards]);
4425+
for (htlc_fail, htlc_destination) in htlc_fails.drain(..) {
4426+
let failure = match htlc_fail {
4427+
HTLCFailureMsg::Relay(fail_htlc) => HTLCForwardInfo::FailHTLC {
4428+
htlc_id: fail_htlc.htlc_id,
4429+
err_packet: fail_htlc.reason,
4430+
},
4431+
HTLCFailureMsg::Malformed(fail_malformed_htlc) => HTLCForwardInfo::FailMalformedHTLC {
4432+
htlc_id: fail_malformed_htlc.htlc_id,
4433+
sha256_of_onion: fail_malformed_htlc.sha256_of_onion,
4434+
failure_code: fail_malformed_htlc.failure_code,
4435+
},
4436+
};
4437+
self.forward_htlcs.lock().unwrap().entry(incoming_scid).or_insert(vec![]).push(failure);
4438+
self.pending_events.lock().unwrap().push_back((events::Event::HTLCHandlingFailed {
4439+
prev_channel_id: incoming_channel_id,
4440+
failed_next_destination: htlc_destination,
4441+
}, None));
4442+
}
4443+
}
4444+
}
4445+
43074446
/// Processes HTLCs which are pending waiting on random forward delay.
43084447
///
43094448
/// Should only really ever be called in response to a PendingHTLCsForwardable event.
43104449
/// Will likely generate further events.
43114450
pub fn process_pending_htlc_forwards(&self) {
43124451
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
43134452

4453+
self.process_pending_update_add_htlcs();
4454+
43144455
let mut new_events = VecDeque::new();
43154456
let mut failed_forwards = Vec::new();
43164457
let mut phantom_receives: Vec<(u64, OutPoint, ChannelId, u128, Vec<(PendingHTLCInfo, u64)>)> = Vec::new();

0 commit comments

Comments
 (0)