Skip to content

Commit ebd94c2

Browse files
committed
Add test to demonstrate we currently do not account for newly trimmed HTLCs when updating a feerate
1 parent a9892a9 commit ebd94c2

File tree

1 file changed

+182
-0
lines changed

1 file changed

+182
-0
lines changed

lightning/src/ln/update_fee_tests.rs

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,3 +1193,185 @@ pub fn do_cannot_afford_on_holding_cell_release(
11931193
nodes[0].logger.assert_log("lightning::ln::channel", err, 1);
11941194
}
11951195
}
1196+
1197+
#[xtest(feature = "_externalize_tests")]
1198+
pub fn can_afford_given_trimmed_htlcs() {
1199+
do_can_afford_given_trimmed_htlcs(core::cmp::Ordering::Equal);
1200+
do_can_afford_given_trimmed_htlcs(core::cmp::Ordering::Greater);
1201+
do_can_afford_given_trimmed_htlcs(core::cmp::Ordering::Less);
1202+
}
1203+
1204+
pub fn do_can_afford_given_trimmed_htlcs(inequality_regions: core::cmp::Ordering) {
1205+
// Test that when we check whether we can afford a feerate update, we account for the
1206+
// decrease in the weight of the commitment transaction due to newly trimmed HTLCs at the higher feerate.
1207+
//
1208+
// Place a non-dust HTLC on the transaction, increase the feerate such that the HTLC
1209+
// gets trimmed, and finally check whether we were able to afford the new feerate.
1210+
1211+
let channel_type = ChannelTypeFeatures::only_static_remote_key();
1212+
let can_afford = match inequality_regions {
1213+
core::cmp::Ordering::Less => false,
1214+
core::cmp::Ordering::Equal => true,
1215+
core::cmp::Ordering::Greater => true,
1216+
};
1217+
let inequality_boundary_offset = match inequality_regions {
1218+
core::cmp::Ordering::Less => 0,
1219+
core::cmp::Ordering::Equal => 1,
1220+
core::cmp::Ordering::Greater => 2,
1221+
};
1222+
1223+
let chanmon_cfgs = create_chanmon_cfgs(2);
1224+
1225+
let mut default_config = test_default_channel_config();
1226+
default_config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel =
1227+
100;
1228+
1229+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
1230+
let node_chanmgrs =
1231+
create_node_chanmgrs(2, &node_cfgs, &[Some(default_config.clone()), Some(default_config)]);
1232+
1233+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
1234+
1235+
let node_a_id = nodes[0].node.get_our_node_id();
1236+
let node_b_id = nodes[1].node.get_our_node_id();
1237+
1238+
// We will update the feerate from 253sat/kw to 1000sat/kw
1239+
let target_feerate = 1000;
1240+
// Set a HTLC amount that is non-dust at 253sat/kw and dust at 1000sat/kw
1241+
let node_0_inbound_htlc_amount_sat = 750;
1242+
1243+
// This is the number of HTLCs that `can_send_update_fee` will account for when checking
1244+
// whether node 0 can afford the target feerate. We do not include the inbound HTLC we will send,
1245+
// as that HTLC will be trimmed at the new feerate.
1246+
let buffer_tx_fee_sat = chan_utils::commit_tx_fee_sat(
1247+
target_feerate,
1248+
crate::ln::channel::CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize,
1249+
&channel_type,
1250+
);
1251+
let channel_reserve_satoshis = 1000;
1252+
1253+
let channel_value_sat = 100_000;
1254+
let node_0_balance_sat =
1255+
(buffer_tx_fee_sat + channel_reserve_satoshis) - 1 + inequality_boundary_offset;
1256+
let node_1_balance_sat = channel_value_sat - node_0_balance_sat;
1257+
1258+
let chan_id =
1259+
create_chan_between_nodes_with_value(&nodes[0], &nodes[1], channel_value_sat, 0).3;
1260+
{
1261+
// Double check the reserve here
1262+
let per_peer_state_lock;
1263+
let mut peer_state_lock;
1264+
let chan =
1265+
get_channel_ref!(nodes[1], nodes[0], per_peer_state_lock, peer_state_lock, chan_id);
1266+
assert_eq!(
1267+
chan.funding().holder_selected_channel_reserve_satoshis,
1268+
channel_reserve_satoshis
1269+
);
1270+
}
1271+
1272+
// Set node 0's balance at some offset from the inequality boundary
1273+
send_payment(&nodes[0], &[&nodes[1]], node_1_balance_sat * 1000);
1274+
1275+
// Route the HTLC from node 1 to node 0
1276+
route_payment(&nodes[1], &[&nodes[0]], node_0_inbound_htlc_amount_sat * 1000);
1277+
1278+
// Confirm the feerate on node 0's commitment transaction
1279+
{
1280+
let expected_tx_fee_sat = chan_utils::commit_tx_fee_sat(253, 1, &channel_type);
1281+
let commitment_tx = get_local_commitment_txn!(nodes[0], chan_id)[0].clone();
1282+
1283+
let mut actual_fee = commitment_tx
1284+
.output
1285+
.iter()
1286+
.map(|output| output.value.to_sat())
1287+
.reduce(|acc, value| acc + value)
1288+
.unwrap();
1289+
actual_fee = channel_value_sat - actual_fee;
1290+
assert_eq!(expected_tx_fee_sat, actual_fee);
1291+
1292+
// The HTLC is non-dust...
1293+
assert_eq!(commitment_tx.output.len(), 3);
1294+
}
1295+
1296+
{
1297+
// Bump the feerate
1298+
let mut feerate_lock = chanmon_cfgs[0].fee_estimator.sat_per_kw.lock().unwrap();
1299+
*feerate_lock = target_feerate;
1300+
}
1301+
nodes[0].node.timer_tick_occurred();
1302+
check_added_monitors(&nodes[0], if can_afford { 1 } else { 0 });
1303+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
1304+
1305+
if can_afford {
1306+
// We could afford the target feerate, sanity check everything
1307+
assert_eq!(events.len(), 1);
1308+
if let MessageSendEvent::UpdateHTLCs { node_id, channel_id, updates } =
1309+
events.pop().unwrap()
1310+
{
1311+
assert_eq!(node_id, node_b_id);
1312+
assert_eq!(channel_id, chan_id);
1313+
assert_eq!(updates.commitment_signed.len(), 1);
1314+
// The HTLC is now trimmed!
1315+
assert_eq!(updates.commitment_signed[0].htlc_signatures.len(), 0);
1316+
assert_eq!(updates.update_add_htlcs.len(), 0);
1317+
assert_eq!(updates.update_fulfill_htlcs.len(), 0);
1318+
assert_eq!(updates.update_fail_htlcs.len(), 0);
1319+
assert_eq!(updates.update_fail_malformed_htlcs.len(), 0);
1320+
let update_fee = updates.update_fee.unwrap();
1321+
assert_eq!(update_fee.channel_id, chan_id);
1322+
assert_eq!(update_fee.feerate_per_kw, target_feerate);
1323+
1324+
nodes[1].node.handle_update_fee(node_a_id, &update_fee);
1325+
commitment_signed_dance!(nodes[1], nodes[0], updates.commitment_signed, false);
1326+
1327+
// Confirm the feerate on node 0's commitment transaction
1328+
{
1329+
// Also add the trimmed HTLC to the fees
1330+
let expected_tx_fee_sat =
1331+
chan_utils::commit_tx_fee_sat(target_feerate, 0, &channel_type)
1332+
+ node_0_inbound_htlc_amount_sat;
1333+
let commitment_tx = get_local_commitment_txn!(nodes[0], channel_id)[0].clone();
1334+
1335+
let mut actual_fee = commitment_tx
1336+
.output
1337+
.iter()
1338+
.map(|output| output.value.to_sat())
1339+
.reduce(|acc, value| acc + value)
1340+
.unwrap();
1341+
actual_fee = channel_value_sat - actual_fee;
1342+
assert_eq!(expected_tx_fee_sat, actual_fee);
1343+
1344+
// The HTLC is now trimmed!
1345+
assert_eq!(commitment_tx.output.len(), 2);
1346+
}
1347+
1348+
// Confirm the feerate on node 1's commitment transaction
1349+
{
1350+
// Also add the trimmed HTLC to the fees
1351+
let expected_tx_fee_sat =
1352+
chan_utils::commit_tx_fee_sat(target_feerate, 0, &channel_type)
1353+
+ node_0_inbound_htlc_amount_sat;
1354+
let commitment_tx = get_local_commitment_txn!(nodes[1], channel_id)[0].clone();
1355+
1356+
let mut actual_fee = commitment_tx
1357+
.output
1358+
.iter()
1359+
.map(|output| output.value.to_sat())
1360+
.reduce(|acc, value| acc + value)
1361+
.unwrap();
1362+
actual_fee = channel_value_sat - actual_fee;
1363+
assert_eq!(expected_tx_fee_sat, actual_fee);
1364+
1365+
// The HTLC is now trimmed!
1366+
assert_eq!(commitment_tx.output.len(), 2);
1367+
}
1368+
} else {
1369+
panic!();
1370+
}
1371+
} else {
1372+
// We could not afford the target feerate, no events should be generated
1373+
assert_eq!(events.len(), 0);
1374+
let err = format!("Cannot afford to send new feerate at {}", target_feerate);
1375+
nodes[0].logger.assert_log("lightning::ln::channel", err, 1);
1376+
}
1377+
}

0 commit comments

Comments
 (0)