Skip to content

Commit f8b74a7

Browse files
committed
Don't generate a commitment if we cannot afford a holding cell feerate
Upon releasing an `update_fee` from its holding cell, it can be dropped and not sent to the peer in case we no longer can afford the new feerate. When this happens, we previously still sent a commitment to the peer, which could break the spec if no other HTLC updates were sent to the peer. Now, when a fee update gets dropped from its holding cell, we also do not produce a commitment if no other HTLC updates are to be sent to the peer.
1 parent 6133a6c commit f8b74a7

File tree

3 files changed

+188
-7
lines changed

3 files changed

+188
-7
lines changed

lightning/src/ln/channel.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6275,14 +6275,11 @@ impl<SP: Deref> FundedChannel<SP> where
62756275
}
62766276
}
62776277
}
6278-
if update_add_count == 0 && update_fulfill_count == 0 && update_fail_count == 0 && self.context.holding_cell_update_fee.is_none() {
6278+
let update_fee = self.context.holding_cell_update_fee.take().and_then(|feerate| self.send_update_fee(feerate, false, fee_estimator, logger));
6279+
6280+
if update_add_count == 0 && update_fulfill_count == 0 && update_fail_count == 0 && update_fee.is_none() {
62796281
return (None, htlcs_to_fail);
62806282
}
6281-
let update_fee = if let Some(feerate) = self.context.holding_cell_update_fee.take() {
6282-
self.send_update_fee(feerate, false, fee_estimator, logger)
6283-
} else {
6284-
None
6285-
};
62866283

62876284
let mut additional_update = self.build_commitment_no_status_check(logger);
62886285
// build_commitment_no_status_check and get_update_fulfill_htlc may bump latest_monitor_id

lightning/src/ln/channelmanager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6586,7 +6586,7 @@ where
65866586
NotifyOption::DoPersist
65876587
}
65886588

6589-
#[cfg(fuzzing)]
6589+
#[cfg(any(test, fuzzing, feature = "_externalize_tests"))]
65906590
/// In chanmon_consistency we want to sometimes do the channel fee updates done in
65916591
/// timer_tick_occurred, but we can't generate the disabled channel updates as it considers
65926592
/// these a fuzz failure (as they usually indicate a channel force-close, which is exactly what

lightning/src/ln/update_fee_tests.rs

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,3 +1009,187 @@ pub fn accept_busted_but_better_fee() {
10091009
_ => panic!("Unexpected event"),
10101010
};
10111011
}
1012+
1013+
#[xtest(feature = "_externalize_tests")]
1014+
pub fn cannot_afford_on_holding_cell_release() {
1015+
do_cannot_afford_on_holding_cell_release(ChannelTypeFeatures::only_static_remote_key(), true);
1016+
do_cannot_afford_on_holding_cell_release(ChannelTypeFeatures::only_static_remote_key(), false);
1017+
do_cannot_afford_on_holding_cell_release(
1018+
ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(),
1019+
true,
1020+
);
1021+
do_cannot_afford_on_holding_cell_release(
1022+
ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(),
1023+
false,
1024+
);
1025+
}
1026+
1027+
pub fn do_cannot_afford_on_holding_cell_release(
1028+
channel_type_features: ChannelTypeFeatures, can_afford: bool,
1029+
) {
1030+
// Test that if we can't afford a feerate update when releasing an
1031+
// update_fee from its holding cell, we do not generate any msg events
1032+
let chanmon_cfgs = create_chanmon_cfgs(2);
1033+
1034+
let mut default_config = test_default_channel_config();
1035+
default_config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel =
1036+
100;
1037+
if channel_type_features.supports_anchors_zero_fee_htlc_tx() {
1038+
default_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
1039+
default_config.manually_accept_inbound_channels = true;
1040+
}
1041+
1042+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
1043+
let node_chanmgrs =
1044+
create_node_chanmgrs(2, &node_cfgs, &[Some(default_config.clone()), Some(default_config)]);
1045+
1046+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
1047+
1048+
let node_a_id = nodes[0].node.get_our_node_id();
1049+
let node_b_id = nodes[1].node.get_our_node_id();
1050+
1051+
let target_feerate = 1000;
1052+
let expected_tx_fee_sat =
1053+
chan_utils::commit_tx_fee_sat(target_feerate, 1, &channel_type_features);
1054+
// This is the number of htlcs that `send_update_fee` will account for when checking whether
1055+
// it can afford the new feerate upon releasing an update_fee from its holding cell,
1056+
// ie the buffer + the inbound HTLC we will add while the update_fee is in the holding cell
1057+
let buffer_htlcs = crate::ln::channel::CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize + 1;
1058+
let buffer_tx_fee_sat =
1059+
chan_utils::commit_tx_fee_sat(target_feerate, buffer_htlcs, &channel_type_features);
1060+
let anchor_value_satoshis = if channel_type_features.supports_anchors_zero_fee_htlc_tx() {
1061+
2 * crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI
1062+
} else {
1063+
0
1064+
};
1065+
let channel_reserve_satoshis = 1000;
1066+
1067+
let channel_value_sat = 100_000;
1068+
let node_0_balance_sat = buffer_tx_fee_sat + anchor_value_satoshis + channel_reserve_satoshis
1069+
- if can_afford { 0 } else { 1 };
1070+
let node_1_balance_sat = channel_value_sat - node_0_balance_sat;
1071+
1072+
let chan_id =
1073+
create_chan_between_nodes_with_value(&nodes[0], &nodes[1], channel_value_sat, 0).3;
1074+
1075+
// Set node 0's balance to the can/can't afford threshold
1076+
send_payment(&nodes[0], &[&nodes[1]], node_1_balance_sat * 1000);
1077+
1078+
{
1079+
// Sanity check the reserve
1080+
let per_peer_state_lock;
1081+
let mut peer_state_lock;
1082+
let chan =
1083+
get_channel_ref!(nodes[1], nodes[0], per_peer_state_lock, peer_state_lock, chan_id);
1084+
assert_eq!(
1085+
chan.funding().holder_selected_channel_reserve_satoshis,
1086+
channel_reserve_satoshis
1087+
);
1088+
}
1089+
1090+
{
1091+
// Bump the feerate
1092+
let mut feerate_lock = chanmon_cfgs[0].fee_estimator.sat_per_kw.lock().unwrap();
1093+
*feerate_lock = target_feerate;
1094+
}
1095+
1096+
// Put the update fee into the holding cell of node 0
1097+
1098+
nodes[0].node.maybe_update_chan_fees();
1099+
1100+
// While the update_fee is in the holding cell, add an inbound HTLC
1101+
1102+
let (route, payment_hash, _, payment_secret) =
1103+
get_route_and_payment_hash!(nodes[1], nodes[0], 5000 * 1000);
1104+
let onion = RecipientOnionFields::secret_only(payment_secret);
1105+
let id = PaymentId(payment_hash.0);
1106+
nodes[1].node.send_payment_with_route(route, payment_hash, onion, id).unwrap();
1107+
check_added_monitors(&nodes[1], 1);
1108+
1109+
let payment_event = {
1110+
let mut events_1 = nodes[1].node.get_and_clear_pending_msg_events();
1111+
assert_eq!(events_1.len(), 1);
1112+
SendEvent::from_event(events_1.pop().unwrap())
1113+
};
1114+
assert_eq!(payment_event.node_id, node_a_id);
1115+
assert_eq!(payment_event.msgs.len(), 1);
1116+
1117+
nodes[0].node.handle_update_add_htlc(node_b_id, &payment_event.msgs[0]);
1118+
nodes[0].node.handle_commitment_signed(node_b_id, &payment_event.commitment_msg[0]);
1119+
check_added_monitors(&nodes[0], 1);
1120+
1121+
let (revoke_ack, commitment_signed) = get_revoke_commit_msgs!(nodes[0], node_b_id);
1122+
1123+
nodes[1].node.handle_revoke_and_ack(node_a_id, &revoke_ack);
1124+
check_added_monitors(&nodes[1], 1);
1125+
nodes[1].node.handle_commitment_signed(node_a_id, &commitment_signed[0]);
1126+
check_added_monitors(&nodes[1], 1);
1127+
1128+
let mut events = nodes[1].node.get_and_clear_pending_msg_events();
1129+
assert_eq!(events.len(), 1);
1130+
1131+
if let MessageSendEvent::SendRevokeAndACK { node_id, msg } = events.pop().unwrap() {
1132+
assert_eq!(node_id, node_a_id);
1133+
nodes[0].node.handle_revoke_and_ack(node_b_id, &msg);
1134+
check_added_monitors!(nodes[0], 1);
1135+
} else {
1136+
panic!();
1137+
}
1138+
1139+
let events = nodes[0].node.get_and_clear_pending_events();
1140+
assert_eq!(events.len(), 1);
1141+
assert!(matches!(events[0], Event::PendingHTLCsForwardable { .. }));
1142+
1143+
// Release the update_fee from its holding cell
1144+
1145+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
1146+
if can_afford {
1147+
// We could afford the update_fee, sanity check everything
1148+
assert_eq!(events.len(), 1);
1149+
if let MessageSendEvent::UpdateHTLCs { node_id, channel_id, updates } =
1150+
events.pop().unwrap()
1151+
{
1152+
assert_eq!(node_id, node_b_id);
1153+
assert_eq!(channel_id, chan_id);
1154+
assert_eq!(updates.commitment_signed.len(), 1);
1155+
assert_eq!(updates.commitment_signed[0].htlc_signatures.len(), 1);
1156+
assert_eq!(updates.update_add_htlcs.len(), 0);
1157+
assert_eq!(updates.update_fulfill_htlcs.len(), 0);
1158+
assert_eq!(updates.update_fail_htlcs.len(), 0);
1159+
assert_eq!(updates.update_fail_malformed_htlcs.len(), 0);
1160+
let update_fee = updates.update_fee.unwrap();
1161+
assert_eq!(update_fee.channel_id, chan_id);
1162+
assert_eq!(update_fee.feerate_per_kw, target_feerate);
1163+
1164+
nodes[1].node.handle_update_fee(node_a_id, &update_fee);
1165+
commitment_signed_dance!(nodes[1], nodes[0], updates.commitment_signed, false);
1166+
1167+
// Confirm the feerate on node 0's commitment transaction
1168+
{
1169+
let commitment_tx = get_local_commitment_txn!(nodes[0], channel_id)[0].clone();
1170+
1171+
let mut actual_fee =
1172+
commitment_tx.output.iter().fold(0, |acc, output| acc + output.value.to_sat());
1173+
actual_fee = channel_value_sat - actual_fee;
1174+
assert_eq!(expected_tx_fee_sat, actual_fee);
1175+
}
1176+
1177+
// Confirm the feerate on node 1's commitment transaction
1178+
{
1179+
let commitment_tx = get_local_commitment_txn!(nodes[1], channel_id)[0].clone();
1180+
1181+
let mut actual_fee =
1182+
commitment_tx.output.iter().fold(0, |acc, output| acc + output.value.to_sat());
1183+
actual_fee = channel_value_sat - actual_fee;
1184+
assert_eq!(expected_tx_fee_sat, actual_fee);
1185+
}
1186+
} else {
1187+
panic!();
1188+
}
1189+
} else {
1190+
// We could not afford the update_fee, no events should be generated
1191+
assert_eq!(events.len(), 0);
1192+
let err = format!("Cannot afford to send new feerate at {}", target_feerate);
1193+
nodes[0].logger.assert_log("lightning::ln::channel", err, 1);
1194+
}
1195+
}

0 commit comments

Comments
 (0)