Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5239,6 +5239,16 @@ impl<
&self.fee_estimator,
&&logger,
);
// Intercept temporary local failures (e.g., HTLC slots full,
// balance constraint) before they go through break_channel_entry!
// which would convert them to ChannelUnavailable. Return
// ChannelBusy instead so the payment can be retried later.
let send_res = match send_res {
Err(ChannelError::Ignore(msg)) => {
return Err(APIError::ChannelBusy { err: msg });
},
other => other,
};
match break_channel_entry!(self, peer_state, send_res, chan_entry) {
Some(monitor_update) => {
let (update_completed, completion_data) = self
Expand Down
30 changes: 24 additions & 6 deletions lightning/src/ln/functional_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8742,12 +8742,24 @@ fn do_test_max_dust_htlc_exposure(
let onion = RecipientOnionFields::secret_only(payment_secret);
let id = PaymentId(payment_hash.0);
let res = nodes[0].node.send_payment_with_route(route, payment_hash, onion, id);
unwrap_send_err!(nodes[0], res, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(
nodes[0],
res,
true,
APIError::ChannelUnavailable { .. } | APIError::ChannelBusy { .. },
{}
);
} else {
let onion = RecipientOnionFields::secret_only(payment_secret);
let id = PaymentId(payment_hash.0);
let res = nodes[0].node.send_payment_with_route(route, payment_hash, onion, id);
unwrap_send_err!(nodes[0], res, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(
nodes[0],
res,
true,
APIError::ChannelUnavailable { .. } | APIError::ChannelBusy { .. },
{}
);
}
} else if exposure_breach_event == ExposureEvent::AtHTLCReception {
let amount_msats = if on_holder_tx {
Expand Down Expand Up @@ -9066,9 +9078,9 @@ pub fn test_nondust_htlc_excess_fees_are_dust() {
let onion = RecipientOnionFields::secret_only(payment_secret_0_1);
let id = PaymentId(payment_hash_0_1.0);
let res = nodes[0].node.send_payment_with_route(route_0_1, payment_hash_0_1, onion, id);
unwrap_send_err!(nodes[0], res, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(nodes[0], res, true, APIError::ChannelBusy { .. }, {});
nodes[0].logger.assert_log("lightning::ln::outbound_payment",
format!("Failed to send along path due to error: Channel unavailable: Cannot send more than our next-HTLC maximum - {} msat", 2325000), 1);
format!("Failed to send along path due to error: Channel busy: Cannot send more than our next-HTLC maximum - {} msat", 2325000), 1);
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());

assert_eq!(nodes[0].node.list_channels().len(), 1);
Expand Down Expand Up @@ -9288,7 +9300,13 @@ fn do_test_nondust_htlc_fees_dust_exposure_delta(features: ChannelTypeFeatures)
let onion = RecipientOnionFields::secret_only(payment_secret_1_0);
let id = PaymentId(payment_hash_1_0.0);
let res = nodes[1].node.send_payment_with_route(route_1_0, payment_hash_1_0, onion, id);
unwrap_send_err!(nodes[1], res, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(
nodes[1],
res,
true,
APIError::ChannelUnavailable { .. } | APIError::ChannelBusy { .. },
{}
);

let (htlc_success_tx_fee_sat, _) =
second_stage_tx_fees_sat(&features, node_1_dust_buffer_feerate as u32);
Expand All @@ -9298,7 +9316,7 @@ fn do_test_nondust_htlc_fees_dust_exposure_delta(features: ChannelTypeFeatures)
MIN_CHAN_DUST_LIMIT_SATOSHIS * 1000
};
nodes[1].logger.assert_log("lightning::ln::outbound_payment",
format!("Failed to send along path due to error: Channel unavailable: Cannot send more than our next-HTLC maximum - {} msat", dust_limit), 1);
format!("Failed to send along path due to error: Channel busy: Cannot send more than our next-HTLC maximum - {} msat", dust_limit), 1);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());

assert_eq!(nodes[0].node.list_channels().len(), 1);
Expand Down
84 changes: 72 additions & 12 deletions lightning/src/ln/htlc_reserve_unit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,13 @@ pub fn test_channel_reserve_holding_cell_htlcs() {
let onion = RecipientOnionFields::secret_only(our_payment_secret);
let id = PaymentId(our_payment_hash.0);
let res = nodes[0].node.send_payment_with_route(route, our_payment_hash, onion, id);
unwrap_send_err!(nodes[0], res, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(
nodes[0],
res,
true,
APIError::ChannelUnavailable { .. } | APIError::ChannelBusy { .. },
{}
);
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
}

Expand Down Expand Up @@ -270,7 +276,13 @@ pub fn test_channel_reserve_holding_cell_htlcs() {
let onion = RecipientOnionFields::secret_only(our_payment_secret);
let id = PaymentId(our_payment_hash.0);
let res = nodes[0].node.send_payment_with_route(route, our_payment_hash, onion, id);
unwrap_send_err!(nodes[0], res, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(
nodes[0],
res,
true,
APIError::ChannelUnavailable { .. } | APIError::ChannelBusy { .. },
{}
);
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
}

Expand Down Expand Up @@ -310,7 +322,13 @@ pub fn test_channel_reserve_holding_cell_htlcs() {
let onion = RecipientOnionFields::secret_only(our_payment_secret);
let id = PaymentId(our_payment_hash.0);
let res = nodes[0].node.send_payment_with_route(route, our_payment_hash, onion, id);
unwrap_send_err!(nodes[0], res, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(
nodes[0],
res,
true,
APIError::ChannelUnavailable { .. } | APIError::ChannelBusy { .. },
{}
);
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
}

Expand Down Expand Up @@ -656,7 +674,13 @@ pub fn holding_cell_htlc_counting() {
let onion = RecipientOnionFields::secret_only(payment_secret_1);
let id = PaymentId(payment_hash_1.0);
let res = nodes[1].node.send_payment_with_route(route, payment_hash_1, onion, id);
unwrap_send_err!(nodes[1], res, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(
nodes[1],
res,
true,
APIError::ChannelUnavailable { .. } | APIError::ChannelBusy { .. },
{}
);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
}

Expand Down Expand Up @@ -770,7 +794,13 @@ pub fn test_basic_channel_reserve() {
let onion = RecipientOnionFields::secret_only(our_payment_secret);
let id = PaymentId(our_payment_hash.0);
let err = nodes[0].node.send_payment_with_route(route, our_payment_hash, onion, id);
unwrap_send_err!(nodes[0], err, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(
nodes[0],
err,
true,
APIError::ChannelUnavailable { .. } | APIError::ChannelBusy { .. },
{}
);
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());

send_payment(&nodes[0], &[&nodes[1]], max_can_send);
Expand Down Expand Up @@ -1017,7 +1047,13 @@ pub fn test_chan_reserve_violation_outbound_htlc_inbound_chan() {
let onion = RecipientOnionFields::secret_only(our_payment_secret);
let id = PaymentId(our_payment_hash.0);
let res = nodes[1].node.send_payment_with_route(route, our_payment_hash, onion, id);
unwrap_send_err!(nodes[1], res, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(
nodes[1],
res,
true,
APIError::ChannelUnavailable { .. } | APIError::ChannelBusy { .. },
{}
);
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
}

Expand Down Expand Up @@ -1145,7 +1181,13 @@ pub fn test_chan_reserve_dust_inbound_htlcs_outbound_chan() {
let onion = RecipientOnionFields::secret_only(our_payment_secret);
let id = PaymentId(our_payment_hash.0);
let res = nodes[1].node.send_payment_with_route(route, our_payment_hash, onion, id);
unwrap_send_err!(nodes[1], res, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(
nodes[1],
res,
true,
APIError::ChannelUnavailable { .. } | APIError::ChannelBusy { .. },
{}
);
}

#[xtest(feature = "_externalize_tests")]
Expand Down Expand Up @@ -1337,7 +1379,13 @@ pub fn test_update_add_htlc_bolt2_sender_value_below_minimum_msat() {
let onion = RecipientOnionFields::secret_only(our_payment_secret);
let id = PaymentId(our_payment_hash.0);
let res = nodes[0].node.send_payment_with_route(route, our_payment_hash, onion, id);
unwrap_send_err!(nodes[0], res, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(
nodes[0],
res,
true,
APIError::ChannelUnavailable { .. } | APIError::ChannelBusy { .. },
{}
);
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
}

Expand All @@ -1358,12 +1406,12 @@ pub fn test_update_add_htlc_bolt2_sender_zero_value_msat() {
let id = PaymentId(our_payment_hash.0);
let res = nodes[0].node.send_payment_with_route(route, our_payment_hash, onion, id);
unwrap_send_err!(nodes[0], res,
true, APIError::ChannelUnavailable { ref err },
true, APIError::ChannelBusy { ref err },
assert_eq!(err, "Cannot send 0-msat HTLC"));

assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
nodes[0].logger.assert_log_contains(
"lightning::ln::channelmanager",
"lightning::ln::outbound_payment",
"Cannot send 0-msat HTLC",
2,
);
Expand Down Expand Up @@ -1489,7 +1537,13 @@ pub fn test_update_add_htlc_bolt2_sender_exceed_max_htlc_num_and_htlc_id_increme
let onion = RecipientOnionFields::secret_only(our_payment_secret);
let id = PaymentId(our_payment_hash.0);
let res = nodes[0].node.send_payment_with_route(route, our_payment_hash, onion, id);
unwrap_send_err!(nodes[0], res, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(
nodes[0],
res,
true,
APIError::ChannelUnavailable { .. } | APIError::ChannelBusy { .. },
{}
);

assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
}
Expand Down Expand Up @@ -1517,7 +1571,13 @@ pub fn test_update_add_htlc_bolt2_sender_exceed_max_htlc_value_in_flight() {
let onion = RecipientOnionFields::secret_only(our_payment_secret);
let id = PaymentId(our_payment_hash.0);
let res = nodes[0].node.send_payment_with_route(route, our_payment_hash, onion, id);
unwrap_send_err!(nodes[0], res, true, APIError::ChannelUnavailable { .. }, {});
unwrap_send_err!(
nodes[0],
res,
true,
APIError::ChannelUnavailable { .. } | APIError::ChannelBusy { .. },
{}
);
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());

send_payment(&nodes[0], &[&nodes[1]], max_in_flight);
Expand Down
Loading
Loading