Skip to content

Commit 6ca654a

Browse files
Incl tx fee when calcing inbound+outbound HTLC limits on channels
When we receive an inbound HTLC from a peer on an inbound channel, the peer needs to be able to pay for the additional commitment tx fees as well. When we're sending an outbound HTLC on an outbound channel, we need to be able to pay for the additional commitment tx fees as well. Co-authored-by: Matt Corallo <[email protected]> Co-authored-by: Valentine Wallace <[email protected]>
1 parent e8a8fd0 commit 6ca654a

File tree

2 files changed

+92
-19
lines changed

2 files changed

+92
-19
lines changed

lightning/src/ln/channel.rs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ pub struct ChannelValueStat {
4646
pub pending_inbound_htlcs_amount_msat: u64,
4747
pub holding_cell_outbound_amount_msat: u64,
4848
pub their_max_htlc_value_in_flight_msat: u64, // outgoing
49+
pub commit_tx_fee_outbound: u64,
4950
}
5051

5152
enum InboundHTLCRemovalReason {
@@ -1656,6 +1657,54 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
16561657
cmp::min(self.value_to_self_msat as i64 - self.get_outbound_pending_htlc_stats().1 as i64, 0) as u64)
16571658
}
16581659

1660+
fn commit_tx_fee_outbound_htlc(&self) -> u64 {
1661+
if !self.channel_outbound {
1662+
return 0;
1663+
} else {
1664+
let mut their_acked_htlcs = self.pending_inbound_htlcs.len() as u64;
1665+
1666+
for ref htlc in self.pending_outbound_htlcs.iter() {
1667+
match htlc.state {
1668+
OutboundHTLCState::Committed => their_acked_htlcs +=1,
1669+
OutboundHTLCState::RemoteRemoved {..} => their_acked_htlcs +=1,
1670+
OutboundHTLCState::LocalAnnounced {..} => their_acked_htlcs += 1,
1671+
_ => {},
1672+
}
1673+
}
1674+
1675+
for ref htlc in self.holding_cell_htlc_updates.iter() {
1676+
match htlc {
1677+
&&HTLCUpdateAwaitingACK::AddHTLC { .. } => their_acked_htlcs += 1,
1678+
_ => {},
1679+
}
1680+
}
1681+
1682+
return self.feerate_per_kw * (COMMITMENT_TX_BASE_WEIGHT + their_acked_htlcs * COMMITMENT_TX_WEIGHT_PER_HTLC);
1683+
}
1684+
}
1685+
1686+
fn commit_tx_fee_inbound_htlc(&self) -> u64 {
1687+
if self.channel_outbound {
1688+
return 0;
1689+
} else {
1690+
let mut their_acked_htlcs = self.pending_inbound_htlcs.len() as u64;
1691+
1692+
// When calculating the set of HTLCs which will be included in their next
1693+
// commitment_signed, all inbound HTLCs are included (as all states imply it will be
1694+
// included) and only committed outbound HTLCs, see below.
1695+
for ref htlc in self.pending_outbound_htlcs.iter() {
1696+
if let OutboundHTLCState::Committed = htlc.state {
1697+
// We only include outbound HTLCs if it will not be included in their next
1698+
// commitment_signed, ie if they've responded to us with an RAA after announcement
1699+
// and if they haven't yet started removal.
1700+
their_acked_htlcs += 1;
1701+
}
1702+
}
1703+
1704+
return self.feerate_per_kw * (COMMITMENT_TX_BASE_WEIGHT + their_acked_htlcs * COMMITMENT_TX_WEIGHT_PER_HTLC);
1705+
}
1706+
}
1707+
16591708
pub fn update_add_htlc(&mut self, msg: &msgs::UpdateAddHTLC, pending_forward_state: PendingHTLCStatus) -> Result<(), ChannelError> {
16601709
if (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::RemoteShutdownSent as u32)) != (ChannelState::ChannelFunded as u32) {
16611710
return Err(ChannelError::Close("Got add HTLC message when channel was not in an operational state"));
@@ -1701,7 +1750,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
17011750
removed_outbound_total_msat += htlc.amount_msat;
17021751
}
17031752
}
1704-
if htlc_inbound_value_msat + msg.amount_msat + self.value_to_self_msat > (self.channel_value_satoshis - Channel::<ChanSigner>::get_our_channel_reserve_satoshis(self.channel_value_satoshis)) * 1000 + removed_outbound_total_msat {
1753+
let remote_fee_cost = self.commit_tx_fee_inbound_htlc();
1754+
if htlc_inbound_value_msat + msg.amount_msat + self.value_to_self_msat > (self.channel_value_satoshis - Channel::<ChanSigner>::get_our_channel_reserve_satoshis(self.channel_value_satoshis)) * 1000 + removed_outbound_total_msat - remote_fee_cost {
17051755
return Err(ChannelError::Close("Remote HTLC add would put them over their reserve value"));
17061756
}
17071757
if self.next_remote_htlc_id != msg.htlc_id {
@@ -3031,6 +3081,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
30313081
res
30323082
},
30333083
their_max_htlc_value_in_flight_msat: self.their_max_htlc_value_in_flight_msat,
3084+
commit_tx_fee_outbound: self.commit_tx_fee_outbound_htlc(),
30343085
}
30353086
}
30363087

@@ -3536,7 +3587,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
35363587

35373588
// Check self.their_channel_reserve_satoshis (the amount we must keep as
35383589
// reserve for them to have something to claim if we misbehave)
3539-
if self.value_to_self_msat < self.their_channel_reserve_satoshis * 1000 + amount_msat + htlc_outbound_value_msat {
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() {
35403591
return Err(ChannelError::Ignore("Cannot send value that would put us over their reserve value"));
35413592
}
35423593

lightning/src/ln/functional_tests.rs

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {
1580+
if stat01.value_to_self_msat - amt_msat < stat01.channel_reserve_msat + stat01.commit_tx_fee_outbound {
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;
1601+
let recv_value = stat01.value_to_self_msat - stat01.channel_reserve_msat - total_fee_msat - stat01.commit_tx_fee_outbound;
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();
@@ -1611,7 +1611,8 @@ fn do_channel_reserve_test(test_recv: bool) {
16111611
}
16121612

16131613
// adding pending output
1614-
let recv_value_1 = (stat01.value_to_self_msat - stat01.channel_reserve_msat - total_fee_msat)/2;
1614+
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;
16151616
let amt_msat_1 = recv_value_1 + total_fee_msat;
16161617

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

16281629
// channel reserve test with htlc pending output > 0
1629-
let recv_value_2 = stat01.value_to_self_msat - amt_msat_1 - stat01.channel_reserve_msat - total_fee_msat;
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;
16301631
{
16311632
let (route, our_payment_hash, _) = get_route_and_payment_hash!(recv_value_2 + 1);
16321633
match nodes[0].node.send_payment(route, our_payment_hash).err().unwrap() {
@@ -1638,8 +1639,10 @@ fn do_channel_reserve_test(test_recv: bool) {
16381639
}
16391640

16401641
{
1641-
// test channel_reserve test on nodes[1] side
1642-
let (route, our_payment_hash, _) = get_route_and_payment_hash!(recv_value_2 + 1);
1642+
// test channel_reserve test on nodes[1] side. The recv_value_1 HTLC hasn't been promoted to Committed yet,
1643+
// so it won't be included in the channel reserve check. Therefore, to trigger a channel close we'll have
1644+
// to add the extra HTLC commit tx fee back in.
1645+
let (route, our_payment_hash, _) = get_route_and_payment_hash!(recv_value_2 + commit_tx_fee_1_acked_htlc + 1);
16431646

16441647
// Need to manually create update_add_htlc message to go around the channel reserve check in send_htlc()
16451648
let secp_ctx = Secp256k1::new();
@@ -1656,7 +1659,7 @@ fn do_channel_reserve_test(test_recv: bool) {
16561659
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash);
16571660
let msg = msgs::UpdateAddHTLC {
16581661
channel_id: chan_1.2,
1659-
htlc_id,
1662+
htlc_id: htlc_id + 1,
16601663
amount_msat: htlc_msat,
16611664
payment_hash: our_payment_hash,
16621665
cltv_expiry: htlc_cltv,
@@ -1676,11 +1679,12 @@ fn do_channel_reserve_test(test_recv: bool) {
16761679
}
16771680

16781681
// split the rest to test holding cell
1679-
let recv_value_21 = recv_value_2/2;
1680-
let recv_value_22 = recv_value_2 - recv_value_21 - total_fee_msat;
1682+
let commit_tx_fee_1_holding_cell_htlc = get_feerate!(nodes[0], chan_1.2) * COMMITMENT_TX_WEIGHT_PER_HTLC;
1683+
let recv_value_21 = recv_value_2/2 - commit_tx_fee_1_holding_cell_htlc/2;
1684+
let recv_value_22 = recv_value_2 - recv_value_21 - total_fee_msat - commit_tx_fee_1_holding_cell_htlc;
16811685
{
16821686
let stat = get_channel_value_stat!(nodes[0], chan_1.2);
1683-
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), 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), stat.channel_reserve_msat);
16841688
}
16851689

16861690
// now see if they go through on both sides
@@ -1714,6 +1718,7 @@ fn do_channel_reserve_test(test_recv: bool) {
17141718
let (as_revoke_and_ack, as_commitment_signed) = get_revoke_commit_msgs!(nodes[1], nodes[0].node.get_our_node_id());
17151719
check_added_monitors!(nodes[1], 1);
17161720

1721+
// the pending htlc should be promoted to committed
17171722
nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &as_revoke_and_ack);
17181723
check_added_monitors!(nodes[0], 1);
17191724
let commitment_update_2 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
@@ -1772,13 +1777,27 @@ fn do_channel_reserve_test(test_recv: bool) {
17721777
claim_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), our_payment_preimage_21, recv_value_21);
17731778
claim_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), our_payment_preimage_22, recv_value_22);
17741779

1775-
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);
1780+
let recv_value_3 = commit_tx_fee_1_acked_htlc + commit_tx_fee_1_holding_cell_htlc - total_fee_msat;
1781+
{
1782+
let (route, our_payment_hash, _) = get_route_and_payment_hash!(recv_value_3 + 1);
1783+
let err = nodes[0].node.send_payment(route.clone(), our_payment_hash).err().unwrap();
1784+
match err {
1785+
APIError::ChannelUnavailable{err} => assert_eq!(err, "Cannot send value that would put us over their reserve value"),
1786+
_ => panic!("Unknown error variants"),
1787+
}
1788+
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
1789+
nodes[0].logger.assert_log("lightning::ln::channelmanager".to_string(), "Cannot send value that would put us over their reserve value".to_string(), 4);
1790+
}
1791+
1792+
send_payment(&nodes[0], &vec![&nodes[1], &nodes[2]][..], recv_value_3, recv_value_3);
1793+
1794+
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);
17761795
let stat0 = get_channel_value_stat!(nodes[0], chan_1.2);
17771796
assert_eq!(stat0.value_to_self_msat, expected_value_to_self);
1778-
assert_eq!(stat0.value_to_self_msat, stat0.channel_reserve_msat);
1797+
assert_eq!(stat0.value_to_self_msat, stat0.channel_reserve_msat + stat0.commit_tx_fee_outbound);
17791798

17801799
let stat2 = get_channel_value_stat!(nodes[2], chan_2.2);
1781-
assert_eq!(stat2.value_to_self_msat, stat22.value_to_self_msat + recv_value_1 + recv_value_21 + recv_value_22);
1800+
assert_eq!(stat2.value_to_self_msat, stat22.value_to_self_msat + recv_value_1 + recv_value_21 + recv_value_22 + recv_value_3);
17821801
}
17831802

17841803
#[test]
@@ -5951,15 +5970,18 @@ fn test_update_add_htlc_bolt2_receiver_sender_can_afford_amount_sent() {
59515970
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
59525971
let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::supported(), InitFeatures::supported());
59535972

5954-
let their_channel_reserve = get_channel_value_stat!(nodes[0], chan.2).channel_reserve_msat;
5973+
let chan_stat = get_channel_value_stat!(nodes[0], chan.2);
5974+
let their_channel_reserve = chan_stat.channel_reserve_msat;
5975+
let commit_tx_fee = chan_stat.commit_tx_fee_outbound;
59555976

5956-
let route = nodes[0].router.get_route(&nodes[1].node.get_our_node_id(), None, &[], 5000000-their_channel_reserve, TEST_FINAL_CLTV).unwrap();
5977+
let max_can_send = 5000000 - their_channel_reserve - commit_tx_fee;
5978+
let route = nodes[0].router.get_route(&nodes[1].node.get_our_node_id(), None, &[], max_can_send, TEST_FINAL_CLTV).unwrap();
59575979
let (_, our_payment_hash) = get_payment_preimage_hash!(nodes[0]);
59585980
nodes[0].node.send_payment(route, our_payment_hash).unwrap();
59595981
check_added_monitors!(nodes[0], 1);
59605982
let mut updates = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
59615983

5962-
updates.update_add_htlcs[0].amount_msat = 5000000-their_channel_reserve+1;
5984+
updates.update_add_htlcs[0].amount_msat = max_can_send + 1;
59635985
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &updates.update_add_htlcs[0]);
59645986

59655987
assert!(nodes[1].node.list_channels().is_empty());
@@ -6043,7 +6065,7 @@ fn test_update_add_htlc_bolt2_receiver_check_cltv_expiry() {
60436065
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
60446066
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
60456067
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
6046-
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 95000000, InitFeatures::supported(), InitFeatures::supported());
6068+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 94000000, InitFeatures::supported(), InitFeatures::supported());
60476069
let route = nodes[0].router.get_route(&nodes[1].node.get_our_node_id(), None, &[], 3999999, TEST_FINAL_CLTV).unwrap();
60486070
let (_, our_payment_hash) = get_payment_preimage_hash!(nodes[0]);
60496071
nodes[0].node.send_payment(route, our_payment_hash).unwrap();

0 commit comments

Comments
 (0)