Skip to content

Commit 7323582

Browse files
Impl fee spike reserve + incl commit tx fee in channel reserve calculation
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. + implement fee spike reserve for channel initiators sending payments. From lightning-rfc PR #740. Co-authored-by: Matt Corallo <[email protected]> Co-authored-by: Valentine Wallace <[email protected]>
1 parent 7ec16e5 commit 7323582

File tree

2 files changed

+223
-80
lines changed

2 files changed

+223
-80
lines changed

lightning/src/ln/channel.rs

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,6 +1656,54 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
16561656
cmp::min(self.value_to_self_msat as i64 - self.get_outbound_pending_htlc_stats().1 as i64, 0) as u64)
16571657
}
16581658

1659+
fn commit_tx_fee_msat(&self, num_htlcs: u64) -> u64 {
1660+
(COMMITMENT_TX_BASE_WEIGHT + num_htlcs * COMMITMENT_TX_WEIGHT_PER_HTLC) * self.feerate_per_kw / 1000 * 1000
1661+
}
1662+
1663+
fn htlc_count_next_local_commit_tx(&self) -> u64 {
1664+
assert!(self.channel_outbound);
1665+
1666+
let mut their_acked_htlcs = self.pending_inbound_htlcs.len() as u64;
1667+
for ref htlc in self.pending_outbound_htlcs.iter() {
1668+
match htlc.state {
1669+
OutboundHTLCState::Committed => their_acked_htlcs +=1,
1670+
OutboundHTLCState::RemoteRemoved {..} => their_acked_htlcs +=1,
1671+
OutboundHTLCState::LocalAnnounced {..} => their_acked_htlcs += 1,
1672+
_ => {},
1673+
}
1674+
}
1675+
1676+
for ref htlc in self.holding_cell_htlc_updates.iter() {
1677+
match htlc {
1678+
&&HTLCUpdateAwaitingACK::AddHTLC { .. } => their_acked_htlcs += 1,
1679+
_ => {},
1680+
}
1681+
}
1682+
1683+
their_acked_htlcs
1684+
}
1685+
1686+
fn htlc_count_next_remote_commit_tx(&self) -> u64 {
1687+
assert!(!self.channel_outbound);
1688+
1689+
let mut their_acked_htlcs = self.pending_inbound_htlcs.len() as u64;
1690+
// When calculating the set of HTLCs which will be included in their next
1691+
// commitment_signed, all inbound HTLCs are included (as all states imply it will be
1692+
// included) and only committed outbound HTLCs, see below.
1693+
for ref htlc in self.pending_outbound_htlcs.iter() {
1694+
// We only include outbound HTLCs if it will not be included in their next
1695+
// commitment_signed, ie if they've responded to us with an RAA after announcement
1696+
// and if the removal process hasn't been finalized.
1697+
match htlc.state {
1698+
OutboundHTLCState::Committed => their_acked_htlcs +=1,
1699+
OutboundHTLCState::RemoteRemoved {..} => their_acked_htlcs +=1,
1700+
_ => {},
1701+
}
1702+
}
1703+
1704+
their_acked_htlcs
1705+
}
1706+
16591707
pub fn update_add_htlc(&mut self, msg: &msgs::UpdateAddHTLC, pending_forward_state: PendingHTLCStatus) -> Result<(), ChannelError> {
16601708
if (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::RemoteShutdownSent as u32)) != (ChannelState::ChannelFunded as u32) {
16611709
return Err(ChannelError::Close("Got add HTLC message when channel was not in an operational state"));
@@ -1701,8 +1749,14 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
17011749
removed_outbound_total_msat += htlc.amount_msat;
17021750
}
17031751
}
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 {
1705-
return Err(ChannelError::Close("Remote HTLC add would put them over their reserve value"));
1752+
1753+
// The + 1 is for the HTLC that is currently being added to the commitment tx.
1754+
let remote_fee_cost_msat = if self.channel_outbound { 0 } else {
1755+
self.commit_tx_fee_msat(self.htlc_count_next_remote_commit_tx() + 1)
1756+
};
1757+
if htlc_inbound_value_msat + msg.amount_msat + self.value_to_self_msat + remote_fee_cost_msat
1758+
> (self.channel_value_satoshis - Channel::<ChanSigner>::get_our_channel_reserve_satoshis(self.channel_value_satoshis)) * 1000 + removed_outbound_total_msat {
1759+
return Err(ChannelError::Ignore("Remote HTLC add would put them over their reserve value"));
17061760
}
17071761
if self.next_remote_htlc_id != msg.htlc_id {
17081762
return Err(ChannelError::Close("Remote skipped HTLC ID"));
@@ -3534,9 +3588,17 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
35343588
return Err(ChannelError::Ignore("Cannot send value that would put us over the max HTLC value in flight our peer will accept"));
35353589
}
35363590

3591+
// Add additional reserve that avoids stuck channels in the case of fee spikes.
3592+
3593+
// The +1 is for the HTLC currently being added to the commitment tx and
3594+
// the +2 is for the fee spike reserve.
3595+
let local_fee_cost_msat = if self.channel_outbound {
3596+
self.commit_tx_fee_msat(self.htlc_count_next_local_commit_tx() + 1 + 2)
3597+
} else { 0 };
3598+
35373599
// Check self.their_channel_reserve_satoshis (the amount we must keep as
35383600
// 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 {
3601+
if self.value_to_self_msat < self.their_channel_reserve_satoshis * 1000 + amount_msat + htlc_outbound_value_msat + local_fee_cost_msat {
35403602
return Err(ChannelError::Ignore("Cannot send value that would put us over their reserve value"));
35413603
}
35423604

0 commit comments

Comments
 (0)