Skip to content

Commit d387400

Browse files
committed
Make all callsites to get_channel_update_for_unicast fallible
This reduces unwraps in channelmanager by a good bit, providing robustness for the upcoming 0conf changes which allow SCIDs to be missing after a channel is in use, making `get_channel_update_for_unicast` more fallible.
1 parent 0a97e0d commit d387400

File tree

1 file changed

+54
-51
lines changed

1 file changed

+54
-51
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 54 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,9 +2413,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
24132413
};
24142414
let (chan_update_opt, forwardee_cltv_expiry_delta) = if let Some(forwarding_id) = forwarding_id_opt {
24152415
let chan = channel_state.as_mut().unwrap().by_id.get_mut(&forwarding_id).unwrap();
2416-
// Leave channel updates as None for private channels.
2417-
let chan_update_opt = if chan.should_announce() {
2418-
Some(self.get_channel_update_for_unicast(chan).unwrap()) } else { None };
2416+
let chan_update_opt = self.get_channel_update_for_broadcast(chan).ok();
24192417
if !chan.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
24202418
// Note that the behavior here should be identical to the above block - we
24212419
// should NOT reveal the existence or non-existence of a private channel if
@@ -3215,9 +3213,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
32153213
} else {
32163214
panic!("Stated return value requirements in send_htlc() were not met");
32173215
}
3218-
let chan_update = self.get_channel_update_for_unicast(chan.get()).unwrap();
3216+
let (failure_code, data) = self.get_htlc_temp_fail_err_and_data(0x1000|7, chan.get());
32193217
failed_forwards.push((htlc_source, payment_hash,
3220-
HTLCFailReason::Reason { failure_code: 0x1000 | 7, data: chan_update.encode_with_len() }
3218+
HTLCFailReason::Reason { failure_code, data }
32213219
));
32223220
continue;
32233221
},
@@ -3713,6 +3711,28 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
37133711
} else { false }
37143712
}
37153713

3714+
/// Gets an HTLC onion failure code and error data for an `UPDATE` error, given the error code
3715+
/// that we want to return and a channel.
3716+
fn get_htlc_temp_fail_err_and_data(&self, desired_err_code: u16, chan: &Channel<Signer>) -> (u16, Vec<u8>) {
3717+
debug_assert_eq!(desired_err_code & 0x1000, 0x1000);
3718+
if let Ok(upd) = self.get_channel_update_for_unicast(chan) {
3719+
let enc = if desired_err_code == 0x1000 | 20 {
3720+
let mut res = Vec::new();
3721+
// TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
3722+
res.extend_from_slice(&byte_utils::be16_to_array(0));
3723+
res.extend_from_slice(&upd.encode_with_len());
3724+
res
3725+
} else { upd.encode_with_len() };
3726+
(desired_err_code, enc)
3727+
} else {
3728+
// If we fail to get a unicast channel_update, it implies we don't yet have an SCID,
3729+
// which means we really shouldn't have gotten a payment to be forwarded over this
3730+
// channel yet, or if we did its from a route hint. Either way, returning an error of
3731+
// PERM|no_such_channel should be fine.
3732+
(0x4000|10, Vec::new())
3733+
}
3734+
}
3735+
37163736
// Fail a list of HTLCs that were just freed from the holding cell. The HTLCs need to be
37173737
// failed backwards or, if they were one of our outgoing HTLCs, then their failure needs to
37183738
// be surfaced to the user.
@@ -3723,11 +3743,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
37233743
let (failure_code, onion_failure_data) =
37243744
match self.channel_state.lock().unwrap().by_id.entry(channel_id) {
37253745
hash_map::Entry::Occupied(chan_entry) => {
3726-
if let Ok(upd) = self.get_channel_update_for_unicast(&chan_entry.get()) {
3727-
(0x1000|7, upd.encode_with_len())
3728-
} else {
3729-
(0x4000|10, Vec::new())
3730-
}
3746+
self.get_htlc_temp_fail_err_and_data(0x1000|7, &chan_entry.get())
37313747
},
37323748
hash_map::Entry::Vacant(_) => (0x4000|10, Vec::new())
37333749
};
@@ -4240,10 +4256,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
42404256
// channel_update later through the announcement_signatures process for public
42414257
// channels, but there's no reason not to just inform our counterparty of our fees
42424258
// now.
4243-
Some(events::MessageSendEvent::SendChannelUpdate {
4244-
node_id: channel.get().get_counterparty_node_id(),
4245-
msg: self.get_channel_update_for_unicast(channel.get()).unwrap(),
4246-
})
4259+
if let Ok(msg) = self.get_channel_update_for_unicast(channel.get()) {
4260+
Some(events::MessageSendEvent::SendChannelUpdate {
4261+
node_id: channel.get().get_counterparty_node_id(),
4262+
msg,
4263+
})
4264+
} else { None }
42474265
} else { None };
42484266
chan_restoration_res = handle_chan_restoration_locked!(self, channel_lock, channel_state, channel, updates.raa, updates.commitment_update, updates.order, None, updates.accepted_htlcs, updates.funding_broadcastable, updates.funding_locked, updates.announcement_sigs);
42494267
if let Some(upd) = channel_update {
@@ -4479,10 +4497,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
44794497
// channel_update here if the channel is not public, i.e. we're not sending an
44804498
// announcement_signatures.
44814499
log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().channel_id()));
4482-
channel_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate {
4483-
node_id: counterparty_node_id.clone(),
4484-
msg: self.get_channel_update_for_unicast(chan.get()).unwrap(),
4485-
});
4500+
if let Ok(msg) = self.get_channel_update_for_unicast(chan.get()) {
4501+
channel_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate {
4502+
node_id: counterparty_node_id.clone(),
4503+
msg,
4504+
});
4505+
}
44864506
}
44874507
Ok(())
44884508
},
@@ -4613,28 +4633,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
46134633
match pending_forward_info {
46144634
PendingHTLCStatus::Forward(PendingHTLCInfo { ref incoming_shared_secret, .. }) => {
46154635
let reason = if (error_code & 0x1000) != 0 {
4616-
if let Ok(upd) = self.get_channel_update_for_unicast(chan) {
4617-
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &{
4618-
let mut res = Vec::with_capacity(8 + 128);
4619-
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
4620-
if error_code == 0x1000 | 20 {
4621-
res.extend_from_slice(&byte_utils::be16_to_array(0));
4622-
}
4623-
res.extend_from_slice(&upd.encode_with_len()[..]);
4624-
res
4625-
}[..])
4626-
} else {
4627-
// The only case where we'd be unable to
4628-
// successfully get a channel update is if the
4629-
// channel isn't in the fully-funded state yet,
4630-
// implying our counterparty is trying to route
4631-
// payments over the channel back to themselves
4632-
// (because no one else should know the short_id
4633-
// is a lightning channel yet). We should have
4634-
// no problem just calling this
4635-
// unknown_next_peer (0x4000|10).
4636-
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, 0x4000|10, &[])
4637-
}
4636+
let (real_code, error_data) = self.get_htlc_temp_fail_err_and_data(error_code, chan);
4637+
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, real_code, &error_data)
46384638
} else {
46394639
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &[])
46404640
};
@@ -4956,10 +4956,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
49564956
// If the channel is in a usable state (ie the channel is not being shut
49574957
// down), send a unicast channel_update to our counterparty to make sure
49584958
// they have the latest channel parameters.
4959-
channel_update = Some(events::MessageSendEvent::SendChannelUpdate {
4960-
node_id: chan.get().get_counterparty_node_id(),
4961-
msg: self.get_channel_update_for_unicast(chan.get()).unwrap(),
4962-
});
4959+
if let Ok(msg) = self.get_channel_update_for_unicast(chan.get()) {
4960+
channel_update = Some(events::MessageSendEvent::SendChannelUpdate {
4961+
node_id: chan.get().get_counterparty_node_id(),
4962+
msg,
4963+
});
4964+
}
49634965
}
49644966
let need_lnd_workaround = chan.get_mut().workaround_lnd_bug_4006.take();
49654967
chan_restoration_res = handle_chan_restoration_locked!(
@@ -5622,20 +5624,21 @@ where
56225624
let res = f(channel);
56235625
if let Ok((funding_locked_opt, mut timed_out_pending_htlcs, announcement_sigs)) = res {
56245626
for (source, payment_hash) in timed_out_pending_htlcs.drain(..) {
5625-
let chan_update = self.get_channel_update_for_unicast(&channel).map(|u| u.encode_with_len()).unwrap(); // Cannot add/recv HTLCs before we have a short_id so unwrap is safe
5627+
let (failure_code, data) = self.get_htlc_temp_fail_err_and_data(0x1000|14 /* expiry_too_soon */, &channel);
56265628
timed_out_htlcs.push((source, payment_hash, HTLCFailReason::Reason {
5627-
failure_code: 0x1000 | 14, // expiry_too_soon, or at least it is now
5628-
data: chan_update,
5629+
failure_code, data,
56295630
}));
56305631
}
56315632
if let Some(funding_locked) = funding_locked_opt {
56325633
send_funding_locked!(short_to_id, pending_msg_events, channel, funding_locked);
56335634
if channel.is_usable() {
56345635
log_trace!(self.logger, "Sending funding_locked with private initial channel_update for our counterparty on channel {}", log_bytes!(channel.channel_id()));
5635-
pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate {
5636-
node_id: channel.get_counterparty_node_id(),
5637-
msg: self.get_channel_update_for_unicast(channel).unwrap(),
5638-
});
5636+
if let Ok(msg) = self.get_channel_update_for_unicast(channel) {
5637+
pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate {
5638+
node_id: channel.get_counterparty_node_id(),
5639+
msg,
5640+
});
5641+
}
56395642
} else {
56405643
log_trace!(self.logger, "Sending funding_locked WITHOUT channel_update for {}", log_bytes!(channel.channel_id()));
56415644
}

0 commit comments

Comments
 (0)