Skip to content

Commit d7d24e4

Browse files
Implement fee spike reserve for channel initiators sending payments.
From lightning-rfc PR #740.
1 parent f1a57ae commit d7d24e4

File tree

2 files changed

+17
-10
lines changed

2 files changed

+17
-10
lines changed

lightning/src/ln/channel.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -3585,9 +3585,12 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
35853585
return Err(ChannelError::Ignore("Cannot send value that would put us over the max HTLC value in flight our peer will accept"));
35863586
}
35873587

3588+
// Add additional reserve that avoids stuck channels in the case of fee spikes.
3589+
let fee_spike_reserve = if self.channel_outbound { 2 * self.feerate_per_kw } else { 0 };
3590+
35883591
// Check self.their_channel_reserve_satoshis (the amount we must keep as
35893592
// reserve for them to have something to claim if we misbehave)
3590-
if self.value_to_self_msat < self.their_channel_reserve_satoshis * 1000 + amount_msat + htlc_outbound_value_msat + self.commit_tx_fee_outbound_htlc() {
3593+
if self.value_to_self_msat < self.their_channel_reserve_satoshis * 1000 + amount_msat + htlc_outbound_value_msat + self.commit_tx_fee_outbound_htlc() + fee_spike_reserve {
35913594
return Err(ChannelError::Ignore("Cannot send value that would put us over their reserve value"));
35923595
}
35933596

lightning/src/ln/functional_tests.rs

+13-9
Original file line numberDiff line numberDiff line change
@@ -1522,7 +1522,6 @@ fn test_duplicate_htlc_different_direction_onchain() {
15221522
}
15231523

15241524
fn do_channel_reserve_test(test_recv: bool) {
1525-
15261525
let chanmon_cfgs = create_chanmon_cfgs(3);
15271526
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
15281527
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
@@ -1556,6 +1555,7 @@ fn do_channel_reserve_test(test_recv: bool) {
15561555

15571556
let feemsat = 239; // somehow we know?
15581557
let total_fee_msat = (nodes.len() - 2) as u64 * 239;
1558+
let fee_spike_reserve = 2 * get_feerate!(nodes[0], chan_1.2);
15591559

15601560
let recv_value_0 = stat01.their_max_htlc_value_in_flight_msat - total_fee_msat;
15611561

@@ -1577,7 +1577,7 @@ fn do_channel_reserve_test(test_recv: bool) {
15771577
// nodes[0]'s wealth
15781578
loop {
15791579
let amt_msat = recv_value_0 + total_fee_msat;
1580-
if stat01.value_to_self_msat - amt_msat < stat01.channel_reserve_msat + stat01.commit_tx_fee_outbound {
1580+
if stat01.value_to_self_msat - amt_msat < stat01.channel_reserve_msat + stat01.commit_tx_fee_outbound + fee_spike_reserve {
15811581
break;
15821582
}
15831583
send_payment(&nodes[0], &vec![&nodes[1], &nodes[2]][..], recv_value_0, recv_value_0);
@@ -1598,7 +1598,7 @@ fn do_channel_reserve_test(test_recv: bool) {
15981598
}
15991599

16001600
{
1601-
let recv_value = stat01.value_to_self_msat - stat01.channel_reserve_msat - total_fee_msat - stat01.commit_tx_fee_outbound;
1601+
let recv_value = stat01.value_to_self_msat - stat01.channel_reserve_msat - total_fee_msat - stat01.commit_tx_fee_outbound - fee_spike_reserve;
16021602
// attempt to get channel_reserve violation
16031603
let (route, our_payment_hash, _) = get_route_and_payment_hash!(recv_value + 1);
16041604
let err = nodes[0].node.send_payment(route.clone(), our_payment_hash).err().unwrap();
@@ -1612,7 +1612,7 @@ fn do_channel_reserve_test(test_recv: bool) {
16121612

16131613
// adding pending output
16141614
let commit_tx_fee_1_acked_htlc = get_feerate!(nodes[0], chan_1.2) * COMMITMENT_TX_WEIGHT_PER_HTLC;
1615-
let recv_value_1 = (stat01.value_to_self_msat - stat01.channel_reserve_msat - total_fee_msat - stat01.commit_tx_fee_outbound - commit_tx_fee_1_acked_htlc)/2;
1615+
let recv_value_1 = (stat01.value_to_self_msat - stat01.channel_reserve_msat - total_fee_msat - stat01.commit_tx_fee_outbound - commit_tx_fee_1_acked_htlc - fee_spike_reserve)/2;
16161616
let amt_msat_1 = recv_value_1 + total_fee_msat;
16171617

16181618
let (route_1, our_payment_hash_1, our_payment_preimage_1) = get_route_and_payment_hash!(recv_value_1);
@@ -1627,7 +1627,7 @@ fn do_channel_reserve_test(test_recv: bool) {
16271627
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event_1.msgs[0]);
16281628

16291629
// channel reserve test with htlc pending output > 0
1630-
let recv_value_2 = stat01.value_to_self_msat - amt_msat_1 - stat01.channel_reserve_msat - total_fee_msat - stat01.commit_tx_fee_outbound - commit_tx_fee_1_acked_htlc;
1630+
let recv_value_2 = stat01.value_to_self_msat - amt_msat_1 - stat01.channel_reserve_msat - total_fee_msat - stat01.commit_tx_fee_outbound - commit_tx_fee_1_acked_htlc - fee_spike_reserve;
16311631
{
16321632
let (route, our_payment_hash, _) = get_route_and_payment_hash!(recv_value_2 + 1);
16331633
match nodes[0].node.send_payment(route, our_payment_hash).err().unwrap() {
@@ -1684,7 +1684,7 @@ fn do_channel_reserve_test(test_recv: bool) {
16841684
let recv_value_22 = recv_value_2 - recv_value_21 - total_fee_msat - commit_tx_fee_1_holding_cell_htlc;
16851685
{
16861686
let stat = get_channel_value_stat!(nodes[0], chan_1.2);
1687-
assert_eq!(stat.value_to_self_msat - (stat.pending_outbound_htlcs_amount_msat + recv_value_21 + recv_value_22 + total_fee_msat + total_fee_msat + commit_tx_fee_1_holding_cell_htlc + commit_tx_fee_1_acked_htlc + stat01.commit_tx_fee_outbound), stat.channel_reserve_msat);
1687+
assert_eq!(stat.value_to_self_msat - (stat.pending_outbound_htlcs_amount_msat + recv_value_21 + recv_value_22 + total_fee_msat + total_fee_msat + commit_tx_fee_1_holding_cell_htlc + commit_tx_fee_1_acked_htlc + stat01.commit_tx_fee_outbound + fee_spike_reserve), stat.channel_reserve_msat);
16881688
}
16891689

16901690
// now see if they go through on both sides
@@ -1794,7 +1794,7 @@ fn do_channel_reserve_test(test_recv: bool) {
17941794
let expected_value_to_self = stat01.value_to_self_msat - (recv_value_1 + total_fee_msat) - (recv_value_21 + total_fee_msat) - (recv_value_22 + total_fee_msat) - (recv_value_3 + total_fee_msat);
17951795
let stat0 = get_channel_value_stat!(nodes[0], chan_1.2);
17961796
assert_eq!(stat0.value_to_self_msat, expected_value_to_self);
1797-
assert_eq!(stat0.value_to_self_msat, stat0.channel_reserve_msat + stat0.commit_tx_fee_outbound);
1797+
assert_eq!(stat0.value_to_self_msat, stat0.channel_reserve_msat + stat0.commit_tx_fee_outbound + fee_spike_reserve);
17981798

17991799
let stat2 = get_channel_value_stat!(nodes[2], chan_2.2);
18001800
assert_eq!(stat2.value_to_self_msat, stat22.value_to_self_msat + recv_value_1 + recv_value_21 + recv_value_22 + recv_value_3);
@@ -5973,15 +5973,19 @@ fn test_update_add_htlc_bolt2_receiver_sender_can_afford_amount_sent() {
59735973
let chan_stat = get_channel_value_stat!(nodes[0], chan.2);
59745974
let their_channel_reserve = chan_stat.channel_reserve_msat;
59755975
let commit_tx_fee = chan_stat.commit_tx_fee_outbound;
5976+
let fee_spike_reserve = 2 * get_feerate!(nodes[0], chan.2);
59765977

5977-
let max_can_send = 5000000 - their_channel_reserve - commit_tx_fee;
5978+
let max_can_send = 5000000 - their_channel_reserve - commit_tx_fee - fee_spike_reserve;
59785979
let route = nodes[0].router.get_route(&nodes[1].node.get_our_node_id(), None, &[], max_can_send, TEST_FINAL_CLTV).unwrap();
59795980
let (_, our_payment_hash) = get_payment_preimage_hash!(nodes[0]);
59805981
nodes[0].node.send_payment(route, our_payment_hash).unwrap();
59815982
check_added_monitors!(nodes[0], 1);
59825983
let mut updates = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
59835984

5984-
updates.update_add_htlcs[0].amount_msat = max_can_send + 1;
5985+
// Even though channel-initiator senders are required to respect the fee_spike_reserve,
5986+
// at this time channel-initiatee receivers are not required to enforce that senders
5987+
// respect the fee_spike_reserve.
5988+
updates.update_add_htlcs[0].amount_msat = max_can_send + fee_spike_reserve + 1;
59855989
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &updates.update_add_htlcs[0]);
59865990

59875991
assert!(nodes[1].node.list_channels().is_empty());

0 commit comments

Comments
 (0)