Skip to content

Commit 70ace81

Browse files
Merge pull request #3345 from tankyleo/onion-channel-updates
Stop sending `channel_update` in onion failures
2 parents ff36405 + 9e30f25 commit 70ace81

File tree

4 files changed

+70
-143
lines changed

4 files changed

+70
-143
lines changed

lightning/src/ln/channel.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2521,6 +2521,14 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
25212521
self.is_usable() && !self.channel_state.is_peer_disconnected()
25222522
}
25232523

2524+
/// Returns false if our last broadcasted channel_update message has the "channel disabled" bit set
2525+
pub fn is_enabled(&self) -> bool {
2526+
self.is_usable() && match self.channel_update_status {
2527+
ChannelUpdateStatus::Enabled | ChannelUpdateStatus::DisabledStaged(_) => true,
2528+
ChannelUpdateStatus::Disabled | ChannelUpdateStatus::EnabledStaged(_) => false,
2529+
}
2530+
}
2531+
25242532
// Public utilities:
25252533

25262534
pub fn channel_id(&self) -> ChannelId {

lightning/src/ln/channelmanager.rs

Lines changed: 52 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ use crate::ln::msgs::{ChannelMessageHandler, CommitmentUpdate, DecodeError, Ligh
6262
#[cfg(test)]
6363
use crate::ln::outbound_payment;
6464
use crate::ln::outbound_payment::{OutboundPayments, PendingOutboundPayment, RetryableInvoiceRequest, SendAlongPathArgs, StaleExpiration};
65-
use crate::ln::wire::Encode;
6665
use crate::offers::invoice::{Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice};
6766
use crate::offers::invoice_error::InvoiceError;
6867
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestBuilder};
@@ -697,7 +696,7 @@ pub enum FailureCode {
697696
}
698697

699698
impl Into<u16> for FailureCode {
700-
fn into(self) -> u16 {
699+
fn into(self) -> u16 {
701700
match self {
702701
FailureCode::TemporaryNodeFailure => 0x2000 | 2,
703702
FailureCode::RequiredNodeFeatureMissing => 0x4000 | 0x2000 | 3,
@@ -4120,43 +4119,39 @@ where
41204119

41214120
fn can_forward_htlc_to_outgoing_channel(
41224121
&self, chan: &mut Channel<SP>, msg: &msgs::UpdateAddHTLC, next_packet: &NextPacketDetails
4123-
) -> Result<(), (&'static str, u16, Option<msgs::ChannelUpdate>)> {
4122+
) -> Result<(), (&'static str, u16)> {
41244123
if !chan.context.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
41254124
// Note that the behavior here should be identical to the above block - we
41264125
// should NOT reveal the existence or non-existence of a private channel if
41274126
// we don't allow forwards outbound over them.
4128-
return Err(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));
4127+
return Err(("Refusing to forward to a private channel based on our config.", 0x4000 | 10));
41294128
}
41304129
if chan.context.get_channel_type().supports_scid_privacy() && next_packet.outgoing_scid != chan.context.outbound_scid_alias() {
41314130
// `option_scid_alias` (referred to in LDK as `scid_privacy`) means
41324131
// "refuse to forward unless the SCID alias was used", so we pretend
41334132
// we don't have the channel here.
4134-
return Err(("Refusing to forward over real channel SCID as our counterparty requested.", 0x4000 | 10, None));
4133+
return Err(("Refusing to forward over real channel SCID as our counterparty requested.", 0x4000 | 10));
41354134
}
41364135

41374136
// Note that we could technically not return an error yet here and just hope
41384137
// that the connection is reestablished or monitor updated by the time we get
41394138
// around to doing the actual forward, but better to fail early if we can and
41404139
// hopefully an attacker trying to path-trace payments cannot make this occur
41414140
// on a small/per-node/per-channel scale.
4142-
if !chan.context.is_live() { // channel_disabled
4143-
// If the channel_update we're going to return is disabled (i.e. the
4144-
// peer has been disabled for some time), return `channel_disabled`,
4145-
// otherwise return `temporary_channel_failure`.
4146-
let chan_update_opt = self.get_channel_update_for_onion(next_packet.outgoing_scid, chan).ok();
4147-
if chan_update_opt.as_ref().map(|u| u.contents.channel_flags & 2 == 2).unwrap_or(false) {
4148-
return Err(("Forwarding channel has been disconnected for some time.", 0x1000 | 20, chan_update_opt));
4141+
if !chan.context.is_live() {
4142+
if !chan.context.is_enabled() {
4143+
// channel_disabled
4144+
return Err(("Forwarding channel has been disconnected for some time.", 0x1000 | 20));
41494145
} else {
4150-
return Err(("Forwarding channel is not in a ready state.", 0x1000 | 7, chan_update_opt));
4146+
// temporary_channel_failure
4147+
return Err(("Forwarding channel is not in a ready state.", 0x1000 | 7));
41514148
}
41524149
}
41534150
if next_packet.outgoing_amt_msat < chan.context.get_counterparty_htlc_minimum_msat() { // amount_below_minimum
4154-
let chan_update_opt = self.get_channel_update_for_onion(next_packet.outgoing_scid, chan).ok();
4155-
return Err(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, chan_update_opt));
4151+
return Err(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11));
41564152
}
41574153
if let Err((err, code)) = chan.htlc_satisfies_config(msg, next_packet.outgoing_amt_msat, next_packet.outgoing_cltv_value) {
4158-
let chan_update_opt = self.get_channel_update_for_onion(next_packet.outgoing_scid, chan).ok();
4159-
return Err((err, code, chan_update_opt));
4154+
return Err((err, code));
41604155
}
41614156

41624157
Ok(())
@@ -4188,7 +4183,7 @@ where
41884183

41894184
fn can_forward_htlc(
41904185
&self, msg: &msgs::UpdateAddHTLC, next_packet_details: &NextPacketDetails
4191-
) -> Result<(), (&'static str, u16, Option<msgs::ChannelUpdate>)> {
4186+
) -> Result<(), (&'static str, u16)> {
41924187
match self.do_funded_channel_callback(next_packet_details.outgoing_scid, |chan: &mut Channel<SP>| {
41934188
self.can_forward_htlc_to_outgoing_channel(chan, msg, next_packet_details)
41944189
}) {
@@ -4201,7 +4196,7 @@ where
42014196
fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, next_packet_details.outgoing_scid, &self.chain_hash)) ||
42024197
fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, next_packet_details.outgoing_scid, &self.chain_hash)
42034198
{} else {
4204-
return Err(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
4199+
return Err(("Don't have available channel for forwarding as requested.", 0x4000 | 10));
42054200
}
42064201
}
42074202
}
@@ -4210,23 +4205,20 @@ where
42104205
if let Err((err_msg, err_code)) = check_incoming_htlc_cltv(
42114206
cur_height, next_packet_details.outgoing_cltv_value, msg.cltv_expiry
42124207
) {
4213-
let chan_update_opt = self.do_funded_channel_callback(next_packet_details.outgoing_scid, |chan: &mut Channel<SP>| {
4214-
self.get_channel_update_for_onion(next_packet_details.outgoing_scid, chan).ok()
4215-
}).flatten();
4216-
return Err((err_msg, err_code, chan_update_opt));
4208+
return Err((err_msg, err_code));
42174209
}
42184210

42194211
Ok(())
42204212
}
42214213

42224214
fn htlc_failure_from_update_add_err(
42234215
&self, msg: &msgs::UpdateAddHTLC, counterparty_node_id: &PublicKey, err_msg: &'static str,
4224-
mut err_code: u16, chan_update: Option<msgs::ChannelUpdate>, is_intro_node_blinded_forward: bool,
4216+
err_code: u16, is_intro_node_blinded_forward: bool,
42254217
shared_secret: &[u8; 32]
42264218
) -> HTLCFailureMsg {
4227-
let mut res = VecWriter(Vec::with_capacity(chan_update.serialized_length() + 2 + 8 + 2));
4228-
if chan_update.is_some() && err_code & 0x1000 == 0x1000 {
4229-
let chan_update = chan_update.unwrap();
4219+
// at capacity, we write fields `htlc_msat` and `len`
4220+
let mut res = VecWriter(Vec::with_capacity(8 + 2));
4221+
if err_code & 0x1000 == 0x1000 {
42304222
if err_code == 0x1000 | 11 || err_code == 0x1000 | 12 {
42314223
msg.amount_msat.write(&mut res).expect("Writes cannot fail");
42324224
}
@@ -4237,15 +4229,8 @@ where
42374229
// TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
42384230
0u16.write(&mut res).expect("Writes cannot fail");
42394231
}
4240-
(chan_update.serialized_length() as u16 + 2).write(&mut res).expect("Writes cannot fail");
4241-
msgs::ChannelUpdate::TYPE.write(&mut res).expect("Writes cannot fail");
4242-
chan_update.write(&mut res).expect("Writes cannot fail");
4243-
} else if err_code & 0x1000 == 0x1000 {
4244-
// If we're trying to return an error that requires a `channel_update` but
4245-
// we're forwarding to a phantom or intercept "channel" (i.e. cannot
4246-
// generate an update), just use the generic "temporary_node_failure"
4247-
// instead.
4248-
err_code = 0x2000 | 2;
4232+
// See https://github.com/lightning/bolts/blob/247e83d/04-onion-routing.md?plain=1#L1414-L1415
4233+
(0u16).write(&mut res).expect("Writes cannot fail");
42494234
}
42504235

42514236
log_info!(
@@ -4293,9 +4278,9 @@ where
42934278
// Perform outbound checks here instead of in [`Self::construct_pending_htlc_info`] because we
42944279
// can't hold the outbound peer state lock at the same time as the inbound peer state lock.
42954280
self.can_forward_htlc(&msg, &next_packet_details).map_err(|e| {
4296-
let (err_msg, err_code, chan_update_opt) = e;
4281+
let (err_msg, err_code) = e;
42974282
self.htlc_failure_from_update_add_err(
4298-
msg, counterparty_node_id, err_msg, err_code, chan_update_opt,
4283+
msg, counterparty_node_id, err_msg, err_code,
42994284
next_hop.is_intro_node_blinded_forward(), &shared_secret
43004285
)
43014286
})?;
@@ -4404,20 +4389,10 @@ where
44044389
Some(id) => id,
44054390
};
44064391

4407-
self.get_channel_update_for_onion(short_channel_id, chan)
4408-
}
4409-
4410-
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<SP>) -> Result<msgs::ChannelUpdate, LightningError> {
44114392
let logger = WithChannelContext::from(&self.logger, &chan.context, None);
44124393
log_trace!(logger, "Generating channel update for channel {}", chan.context.channel_id());
44134394
let were_node_one = self.our_network_pubkey.serialize()[..] < chan.context.get_counterparty_node_id().serialize()[..];
4414-
4415-
let enabled = chan.context.is_usable() && match chan.channel_update_status() {
4416-
ChannelUpdateStatus::Enabled => true,
4417-
ChannelUpdateStatus::DisabledStaged(_) => true,
4418-
ChannelUpdateStatus::Disabled => false,
4419-
ChannelUpdateStatus::EnabledStaged(_) => false,
4420-
};
4395+
let enabled = chan.context.is_enabled();
44214396

44224397
let unsigned = msgs::UnsignedChannelUpdate {
44234398
chain_hash: self.chain_hash,
@@ -5605,16 +5580,9 @@ where
56055580
}) {
56065581
Some(Ok(_)) => {},
56075582
Some(Err((err, code))) => {
5608-
let outgoing_chan_update_opt = if let Some(outgoing_scid) = outgoing_scid_opt.as_ref() {
5609-
self.do_funded_channel_callback(*outgoing_scid, |chan: &mut Channel<SP>| {
5610-
self.get_channel_update_for_onion(*outgoing_scid, chan).ok()
5611-
}).flatten()
5612-
} else {
5613-
None
5614-
};
56155583
let htlc_fail = self.htlc_failure_from_update_add_err(
56165584
&update_add_htlc, &incoming_counterparty_node_id, err, code,
5617-
outgoing_chan_update_opt, is_intro_node_blinded_forward, &shared_secret,
5585+
is_intro_node_blinded_forward, &shared_secret,
56185586
);
56195587
let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash);
56205588
htlc_fails.push((htlc_fail, htlc_destination));
@@ -5626,12 +5594,12 @@ where
56265594

56275595
// Now process the HTLC on the outgoing channel if it's a forward.
56285596
if let Some(next_packet_details) = next_packet_details_opt.as_ref() {
5629-
if let Err((err, code, chan_update_opt)) = self.can_forward_htlc(
5597+
if let Err((err, code)) = self.can_forward_htlc(
56305598
&update_add_htlc, next_packet_details
56315599
) {
56325600
let htlc_fail = self.htlc_failure_from_update_add_err(
56335601
&update_add_htlc, &incoming_counterparty_node_id, err, code,
5634-
chan_update_opt, is_intro_node_blinded_forward, &shared_secret,
5602+
is_intro_node_blinded_forward, &shared_secret,
56355603
);
56365604
let htlc_destination = get_failed_htlc_destination(outgoing_scid_opt, update_add_htlc.payment_hash);
56375605
htlc_fails.push((htlc_fail, htlc_destination));
@@ -5912,7 +5880,8 @@ where
59125880
}
59135881

59145882
if let Some(ChannelPhase::Funded(ref mut chan)) = peer_state.channel_by_id.get_mut(&forward_chan_id) {
5915-
let (failure_code, data) = self.get_htlc_temp_fail_err_and_data(0x1000|7, short_chan_id, chan);
5883+
let failure_code = 0x1000|7;
5884+
let data = self.get_htlc_inbound_temp_fail_data(failure_code);
59165885
failed_forwards.push((htlc_source, payment_hash,
59175886
HTLCFailReason::reason(failure_code, data),
59185887
HTLCDestination::NextHopChannel { node_id: Some(chan.context.get_counterparty_node_id()), channel_id: forward_chan_id }
@@ -6678,46 +6647,21 @@ where
66786647
///
66796648
/// This is for failures on the channel on which the HTLC was *received*, not failures
66806649
/// forwarding
6681-
fn get_htlc_inbound_temp_fail_err_and_data(&self, desired_err_code: u16, chan: &Channel<SP>) -> (u16, Vec<u8>) {
6682-
// We can't be sure what SCID was used when relaying inbound towards us, so we have to
6683-
// guess somewhat. If its a public channel, we figure best to just use the real SCID (as
6684-
// we're not leaking that we have a channel with the counterparty), otherwise we try to use
6685-
// an inbound SCID alias before the real SCID.
6686-
let scid_pref = if chan.context.should_announce() {
6687-
chan.context.get_short_channel_id().or(chan.context.latest_inbound_scid_alias())
6688-
} else {
6689-
chan.context.latest_inbound_scid_alias().or(chan.context.get_short_channel_id())
6690-
};
6691-
if let Some(scid) = scid_pref {
6692-
self.get_htlc_temp_fail_err_and_data(desired_err_code, scid, chan)
6693-
} else {
6694-
(0x4000|10, Vec::new())
6695-
}
6696-
}
6697-
6698-
6699-
/// Gets an HTLC onion failure code and error data for an `UPDATE` error, given the error code
6700-
/// that we want to return and a channel.
6701-
fn get_htlc_temp_fail_err_and_data(&self, desired_err_code: u16, scid: u64, chan: &Channel<SP>) -> (u16, Vec<u8>) {
6702-
debug_assert_eq!(desired_err_code & 0x1000, 0x1000);
6703-
if let Ok(upd) = self.get_channel_update_for_onion(scid, chan) {
6704-
let mut enc = VecWriter(Vec::with_capacity(upd.serialized_length() + 6));
6705-
if desired_err_code == 0x1000 | 20 {
6706-
// No flags for `disabled_flags` are currently defined so they're always two zero bytes.
6707-
// See https://github.com/lightning/bolts/blob/341ec84/04-onion-routing.md?plain=1#L1008
6708-
0u16.write(&mut enc).expect("Writes cannot fail");
6709-
}
6710-
(upd.serialized_length() as u16 + 2).write(&mut enc).expect("Writes cannot fail");
6711-
msgs::ChannelUpdate::TYPE.write(&mut enc).expect("Writes cannot fail");
6712-
upd.write(&mut enc).expect("Writes cannot fail");
6713-
(desired_err_code, enc.0)
6714-
} else {
6715-
// If we fail to get a unicast channel_update, it implies we don't yet have an SCID,
6716-
// which means we really shouldn't have gotten a payment to be forwarded over this
6717-
// channel yet, or if we did it's from a route hint. Either way, returning an error of
6718-
// PERM|no_such_channel should be fine.
6719-
(0x4000|10, Vec::new())
6720-
}
6650+
fn get_htlc_inbound_temp_fail_data(&self, err_code: u16) -> Vec<u8> {
6651+
debug_assert_eq!(err_code & 0x1000, 0x1000);
6652+
debug_assert_ne!(err_code, 0x1000|11);
6653+
debug_assert_ne!(err_code, 0x1000|12);
6654+
debug_assert_ne!(err_code, 0x1000|13);
6655+
// at capacity, we write fields `disabled_flags` and `len`
6656+
let mut enc = VecWriter(Vec::with_capacity(4));
6657+
if err_code == 0x1000 | 20 {
6658+
// No flags for `disabled_flags` are currently defined so they're always two zero bytes.
6659+
// See https://github.com/lightning/bolts/blob/341ec84/04-onion-routing.md?plain=1#L1008
6660+
0u16.write(&mut enc).expect("Writes cannot fail");
6661+
}
6662+
// See https://github.com/lightning/bolts/blob/247e83d/04-onion-routing.md?plain=1#L1414-L1415
6663+
(0u16).write(&mut enc).expect("Writes cannot fail");
6664+
enc.0
67216665
}
67226666

67236667
// Fail a list of HTLCs that were just freed from the holding cell. The HTLCs need to be
@@ -6734,8 +6678,10 @@ where
67346678
let peer_state = &mut *peer_state_lock;
67356679
match peer_state.channel_by_id.entry(channel_id) {
67366680
hash_map::Entry::Occupied(chan_phase_entry) => {
6737-
if let ChannelPhase::Funded(chan) = chan_phase_entry.get() {
6738-
self.get_htlc_inbound_temp_fail_err_and_data(0x1000|7, &chan)
6681+
if let ChannelPhase::Funded(_chan) = chan_phase_entry.get() {
6682+
let failure_code = 0x1000|7;
6683+
let data = self.get_htlc_inbound_temp_fail_data(failure_code);
6684+
(failure_code, data)
67396685
} else {
67406686
// We shouldn't be trying to fail holding cell HTLCs on an unfunded channel.
67416687
debug_assert!(false);
@@ -8698,8 +8644,8 @@ where
86988644
let reason = if routing.blinded_failure().is_some() {
86998645
HTLCFailReason::reason(INVALID_ONION_BLINDING, vec![0; 32])
87008646
} else if (error_code & 0x1000) != 0 {
8701-
let (real_code, error_data) = self.get_htlc_inbound_temp_fail_err_and_data(error_code, chan);
8702-
HTLCFailReason::reason(real_code, error_data)
8647+
let error_data = self.get_htlc_inbound_temp_fail_data(error_code);
8648+
HTLCFailReason::reason(error_code, error_data)
87038649
} else {
87048650
HTLCFailReason::from_failure_code(error_code)
87058651
}.get_encrypted_failure_packet(incoming_shared_secret, &None);
@@ -10973,7 +10919,8 @@ where
1097310919
let res = f(channel);
1097410920
if let Ok((channel_ready_opt, mut timed_out_pending_htlcs, announcement_sigs)) = res {
1097510921
for (source, payment_hash) in timed_out_pending_htlcs.drain(..) {
10976-
let (failure_code, data) = self.get_htlc_inbound_temp_fail_err_and_data(0x1000|14 /* expiry_too_soon */, &channel);
10922+
let failure_code = 0x1000|14; /* expiry_too_soon */
10923+
let data = self.get_htlc_inbound_temp_fail_data(failure_code);
1097710924
timed_out_htlcs.push((source, payment_hash, HTLCFailReason::reason(failure_code, data),
1097810925
HTLCDestination::NextHopChannel { node_id: Some(channel.context.get_counterparty_node_id()), channel_id: channel.context.channel_id() }));
1097910926
}

lightning/src/ln/onion_route_tests.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,9 +1397,12 @@ fn test_phantom_failure_modified_cltv() {
13971397
commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false);
13981398

13991399
// Ensure the payment fails with the expected error.
1400+
let mut err_data = Vec::new();
1401+
err_data.extend_from_slice(&update_add.cltv_expiry.to_be_bytes());
1402+
err_data.extend_from_slice(&0u16.to_be_bytes());
14001403
let mut fail_conditions = PaymentFailedConditions::new()
14011404
.blamed_scid(phantom_scid)
1402-
.expected_htlc_error_data(0x2000 | 2, &[]);
1405+
.expected_htlc_error_data(0x1000 | 13, &err_data);
14031406
expect_payment_failed_conditions(&nodes[0], payment_hash, false, fail_conditions);
14041407
}
14051408

@@ -1437,9 +1440,10 @@ fn test_phantom_failure_expires_too_soon() {
14371440
commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false);
14381441

14391442
// Ensure the payment fails with the expected error.
1443+
let err_data = 0u16.to_be_bytes();
14401444
let mut fail_conditions = PaymentFailedConditions::new()
14411445
.blamed_scid(phantom_scid)
1442-
.expected_htlc_error_data(0x2000 | 2, &[]);
1446+
.expected_htlc_error_data(0x1000 | 14, &err_data);
14431447
expect_payment_failed_conditions(&nodes[0], payment_hash, false, fail_conditions);
14441448
}
14451449

@@ -1535,11 +1539,7 @@ fn do_test_phantom_dust_exposure_failure(multiplier_dust_limit: bool) {
15351539
commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false);
15361540

15371541
// Ensure the payment fails with the expected error.
1538-
let mut err_data = Vec::new();
1539-
err_data.extend_from_slice(&(channel.1.serialized_length() as u16 + 2).to_be_bytes());
1540-
err_data.extend_from_slice(&ChannelUpdate::TYPE.to_be_bytes());
1541-
err_data.extend_from_slice(&channel.1.encode());
1542-
1542+
let err_data = 0u16.to_be_bytes();
15431543
let mut fail_conditions = PaymentFailedConditions::new()
15441544
.blamed_scid(route.paths[0].hops.last().as_ref().unwrap().short_channel_id)
15451545
.blamed_chan_closed(false)

0 commit comments

Comments
 (0)