Skip to content

Commit 809a3f5

Browse files
committed
Remove spurious debug assertion added in 0.2
In 20877b3 we added a `debug_assert`ion to validate that if we call `maybe_free_holding_cell_htlcs` and it doesn't manage to generate a new commitment (implying `!can_generate_new_commitment()`) that we don't have any HTLCs to fail, but there was no reason for that, and its reachable. Here we simply remove the spurious debug assertion and add a test that exercises it.
1 parent c5d7b13 commit 809a3f5

File tree

3 files changed

+156
-3
lines changed

3 files changed

+156
-3
lines changed

lightning/src/ln/channel.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8981,7 +8981,6 @@ where
89818981
update_fail_htlcs.len() + update_fail_malformed_htlcs.len(),
89828982
&self.context.channel_id);
89838983
} else {
8984-
debug_assert!(htlcs_to_fail.is_empty());
89858984
let reason = if self.context.channel_state.is_local_stfu_sent() {
89868985
"exits quiescence"
89878986
} else if self.context.channel_state.is_monitor_update_in_progress() {

lightning/src/ln/functional_test_utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,7 @@ pub fn get_revoke_commit_msgs<CM: AChannelManager, H: NodeHolder<CM = CM>>(
971971
assert_eq!(node_id, recipient);
972972
(*msg).clone()
973973
},
974-
_ => panic!("Unexpected event"),
974+
_ => panic!("Unexpected event: {events:?}"),
975975
},
976976
match events[1] {
977977
MessageSendEvent::UpdateHTLCs { ref node_id, ref channel_id, ref updates } => {
@@ -984,7 +984,7 @@ pub fn get_revoke_commit_msgs<CM: AChannelManager, H: NodeHolder<CM = CM>>(
984984
assert!(updates.commitment_signed.iter().all(|cs| cs.channel_id == *channel_id));
985985
updates.commitment_signed.clone()
986986
},
987-
_ => panic!("Unexpected event"),
987+
_ => panic!("Unexpected event: {events:?}"),
988988
},
989989
)
990990
}

lightning/src/ln/functional_tests.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9900,3 +9900,157 @@ pub fn test_multi_post_event_actions() {
99009900
do_test_multi_post_event_actions(true);
99019901
do_test_multi_post_event_actions(false);
99029902
}
9903+
9904+
#[xtest(feature = "_externalize_tests")]
9905+
pub fn test_dust_exposure_holding_cell_assertion() {
9906+
// Test that we properly move forward if we pop an HTLC-add from the holding cell but fail to
9907+
// add it to the channel. In 0.2 this cause a (harmless in prod) debug assertion failure. We
9908+
// try to ensure that this won't happen by checking that an HTLC will be able to be added
9909+
// before we add it to the holding cell, so getting into this state takes a bit of work.
9910+
//
9911+
// Here we accomplish this by using the dust exposure limit. This has the unique feature that
9912+
// node C can increase node B's dust exposure on the B <-> C channel without B doing anything.
9913+
// To exploit this, we get node B one HTLC away from being over-exposed to dust, give it one
9914+
// more HTLC in the holding cell, then have node C add an HTLC. By the time the holding-cell
9915+
// HTLC is released we are at max-dust-exposure and will fail it.
9916+
9917+
let chanmon_cfgs = create_chanmon_cfgs(3);
9918+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
9919+
9920+
// Configure nodes with specific dust limits
9921+
let mut config = test_default_channel_config();
9922+
// Use a fixed dust exposure limit to make the test simpler
9923+
const DUST_HTLC_VALUE_MSAT: u64 = 500_000;
9924+
config.channel_config.max_dust_htlc_exposure = MaxDustHTLCExposure::FixedLimitMsat(5_000_000);
9925+
config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100;
9926+
9927+
let configs = [Some(config.clone()), Some(config.clone()), Some(config.clone())];
9928+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &configs);
9929+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
9930+
9931+
let node_a_id = nodes[0].node.get_our_node_id();
9932+
let node_b_id = nodes[1].node.get_our_node_id();
9933+
let node_c_id = nodes[2].node.get_our_node_id();
9934+
9935+
// Create channels: A <-> B <-> C
9936+
create_announced_chan_between_nodes(&nodes, 0, 1);
9937+
let bc_chan_id = create_announced_chan_between_nodes(&nodes, 1, 2).2;
9938+
send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 10_000_000);
9939+
9940+
// Send multiple dust HTLCs from B to C to approach the dust limit (including transaction fees)
9941+
for _ in 0..4 {
9942+
route_payment(&nodes[1], &[&nodes[2]], DUST_HTLC_VALUE_MSAT);
9943+
}
9944+
9945+
// At this point we shouldn't be over the dust limit, and should still be able to send HTLCs.
9946+
let bs_chans = nodes[1].node.list_channels();
9947+
let bc_chan =
9948+
bs_chans.iter().filter(|chan| chan.counterparty.node_id == node_c_id).next().unwrap();
9949+
assert_eq!(
9950+
bc_chan.next_outbound_htlc_minimum_msat,
9951+
config.channel_handshake_config.our_htlc_minimum_msat
9952+
);
9953+
9954+
// Add a further HTLC from B to C, but don't deliver the send messages.
9955+
// After this we'll only have the ability to add one more HTLC, but by not delivering the send
9956+
// messages (leaving B waiting on C's RAA) the next HTLC will go into B's holding cell.
9957+
let (route_bc, payment_hash_bc, _payment_preimage_bc, payment_secret_bc) =
9958+
get_route_and_payment_hash!(nodes[1], nodes[2], DUST_HTLC_VALUE_MSAT);
9959+
let onion_bc = RecipientOnionFields::secret_only(payment_secret_bc);
9960+
let id = PaymentId(payment_hash_bc.0);
9961+
nodes[1].node.send_payment_with_route(route_bc, payment_hash_bc, onion_bc, id).unwrap();
9962+
check_added_monitors(&nodes[1], 1);
9963+
let send_bc = SendEvent::from_node(&nodes[1]);
9964+
9965+
let bs_chans = nodes[1].node.list_channels();
9966+
let bc_chan =
9967+
bs_chans.iter().filter(|chan| chan.counterparty.node_id == node_c_id).next().unwrap();
9968+
assert_eq!(
9969+
bc_chan.next_outbound_htlc_minimum_msat,
9970+
config.channel_handshake_config.our_htlc_minimum_msat
9971+
);
9972+
9973+
// Forward an additional HTLC from A through B to C. This will go in B's holding cell for node
9974+
// C as it is waiting on a response to the above messages.
9975+
let payment_params_ac = PaymentParameters::from_node_id(node_c_id, TEST_FINAL_CLTV)
9976+
.with_bolt11_features(nodes[2].node.bolt11_invoice_features())
9977+
.unwrap();
9978+
let (route_ac, payment_hash_cell, _, payment_secret_ac) =
9979+
get_route_and_payment_hash!(nodes[0], nodes[2], payment_params_ac, DUST_HTLC_VALUE_MSAT);
9980+
let onion_ac = RecipientOnionFields::secret_only(payment_secret_ac);
9981+
let id = PaymentId(payment_hash_cell.0);
9982+
nodes[0].node.send_payment_with_route(route_ac, payment_hash_cell, onion_ac, id).unwrap();
9983+
check_added_monitors(&nodes[0], 1);
9984+
9985+
let send_ab = SendEvent::from_node(&nodes[0]);
9986+
nodes[1].node.handle_update_add_htlc(node_a_id, &send_ab.msgs[0]);
9987+
do_commitment_signed_dance(&nodes[1], &nodes[0], &send_ab.commitment_msg, false, true);
9988+
9989+
// At this point when we process pending forwards the HTLC will go into the holding cell and no
9990+
// further messages will be generated. Node B will also be at its maximum dust exposure and
9991+
// will refuse to send any dust HTLCs (when it includes the holding cell HTLC).
9992+
expect_and_process_pending_htlcs(&nodes[1], false);
9993+
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
9994+
9995+
let bs_chans = nodes[1].node.list_channels();
9996+
let bc_chan =
9997+
bs_chans.iter().filter(|chan| chan.counterparty.node_id == node_c_id).next().unwrap();
9998+
assert!(bc_chan.next_outbound_htlc_minimum_msat > DUST_HTLC_VALUE_MSAT);
9999+
10000+
// Send an additional HTLC from C to B. This will make B unable to forward the HTLC already in
10001+
// its holding cell as it would be over-exposed to dust.
10002+
let (route_cb, payment_hash_cb, payment_preimage_cb, payment_secret_cb) =
10003+
get_route_and_payment_hash!(nodes[2], nodes[1], DUST_HTLC_VALUE_MSAT);
10004+
let onion_cb = RecipientOnionFields::secret_only(payment_secret_cb);
10005+
let id = PaymentId(payment_hash_cb.0);
10006+
nodes[2].node.send_payment_with_route(route_cb, payment_hash_cb, onion_cb, id).unwrap();
10007+
check_added_monitors(&nodes[2], 1);
10008+
10009+
// Now deliver all the messages and make sure that the HTLC is failed-back.
10010+
let send_event_cb = SendEvent::from_node(&nodes[2]);
10011+
nodes[1].node.handle_update_add_htlc(node_c_id, &send_event_cb.msgs[0]);
10012+
nodes[1].node.handle_commitment_signed_batch_test(node_c_id, &send_event_cb.commitment_msg);
10013+
check_added_monitors(&nodes[1], 1);
10014+
10015+
nodes[2].node.handle_update_add_htlc(node_b_id, &send_bc.msgs[0]);
10016+
nodes[2].node.handle_commitment_signed_batch_test(node_b_id, &send_bc.commitment_msg);
10017+
check_added_monitors(&nodes[2], 1);
10018+
10019+
let cs_raa = get_event_msg!(nodes[2], MessageSendEvent::SendRevokeAndACK, node_b_id);
10020+
nodes[1].node.handle_revoke_and_ack(node_c_id, &cs_raa);
10021+
check_added_monitors(&nodes[1], 1);
10022+
let (bs_raa, bs_cs) = get_revoke_commit_msgs(&nodes[1], &node_c_id);
10023+
10024+
// When we delivered the RAA above, we attempted (and failed) to add the HTLC to the channel,
10025+
// causing it to be ready to fail-back, which we do here:
10026+
let next_hop =
10027+
HTLCHandlingFailureType::Forward { node_id: Some(node_c_id), channel_id: bc_chan_id };
10028+
expect_htlc_forwarding_fails(&nodes[1], &[next_hop]);
10029+
check_added_monitors(&nodes[1], 1);
10030+
fail_payment_along_path(&[&nodes[0], &nodes[1]]);
10031+
let conditions = PaymentFailedConditions::new();
10032+
expect_payment_failed_conditions(&nodes[0], payment_hash_cell, false, conditions);
10033+
10034+
nodes[2].node.handle_revoke_and_ack(node_b_id, &bs_raa);
10035+
check_added_monitors(&nodes[2], 1);
10036+
let cs_cs = get_htlc_update_msgs(&nodes[2], &node_b_id);
10037+
10038+
nodes[2].node.handle_commitment_signed_batch_test(node_b_id, &bs_cs);
10039+
check_added_monitors(&nodes[2], 1);
10040+
let cs_raa = get_event_msg!(nodes[2], MessageSendEvent::SendRevokeAndACK, node_b_id);
10041+
10042+
nodes[1].node.handle_commitment_signed_batch_test(node_c_id, &cs_cs.commitment_signed);
10043+
check_added_monitors(&nodes[1], 1);
10044+
let bs_raa = get_event_msg!(nodes[1], MessageSendEvent::SendRevokeAndACK, node_c_id);
10045+
10046+
nodes[1].node.handle_revoke_and_ack(node_c_id, &cs_raa);
10047+
check_added_monitors(&nodes[1], 1);
10048+
expect_and_process_pending_htlcs(&nodes[1], false);
10049+
expect_payment_claimable!(nodes[1], payment_hash_cb, payment_secret_cb, DUST_HTLC_VALUE_MSAT);
10050+
10051+
nodes[2].node.handle_revoke_and_ack(node_b_id, &bs_raa);
10052+
check_added_monitors(&nodes[2], 1);
10053+
10054+
// Now that everything has settled, make sure the channels still work with a simple claim.
10055+
claim_payment(&nodes[2], &[&nodes[1]], payment_preimage_cb);
10056+
}

0 commit comments

Comments
 (0)