@@ -46,6 +46,7 @@ pub struct ChannelValueStat {
46
46
pub pending_inbound_htlcs_amount_msat : u64 ,
47
47
pub holding_cell_outbound_amount_msat : u64 ,
48
48
pub their_max_htlc_value_in_flight_msat : u64 , // outgoing
49
+ pub commit_tx_fee_outbound : u64 ,
49
50
}
50
51
51
52
enum InboundHTLCRemovalReason {
@@ -1656,6 +1657,50 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
1656
1657
cmp:: min ( self . value_to_self_msat as i64 - self . get_outbound_pending_htlc_stats ( ) . 1 as i64 , 0 ) as u64 )
1657
1658
}
1658
1659
1660
+ fn htlc_count_next_local_commit_tx ( & self ) -> u64 {
1661
+ assert ! ( self . channel_outbound) ;
1662
+
1663
+ let mut their_acked_htlcs = self . pending_inbound_htlcs . len ( ) as u64 ;
1664
+ for ref htlc in self . pending_outbound_htlcs . iter ( ) {
1665
+ match htlc. state {
1666
+ OutboundHTLCState :: Committed => their_acked_htlcs +=1 ,
1667
+ OutboundHTLCState :: RemoteRemoved { ..} => their_acked_htlcs +=1 ,
1668
+ OutboundHTLCState :: LocalAnnounced { ..} => their_acked_htlcs += 1 ,
1669
+ _ => { } ,
1670
+ }
1671
+ }
1672
+
1673
+ for ref htlc in self . holding_cell_htlc_updates . iter ( ) {
1674
+ match htlc {
1675
+ & & HTLCUpdateAwaitingACK :: AddHTLC { .. } => their_acked_htlcs += 1 ,
1676
+ _ => { } ,
1677
+ }
1678
+ }
1679
+
1680
+ their_acked_htlcs
1681
+ }
1682
+
1683
+ fn htlc_count_next_remote_commit_tx ( & self ) -> u64 {
1684
+ assert ! ( !self . channel_outbound) ;
1685
+
1686
+ let mut their_acked_htlcs = self . pending_inbound_htlcs . len ( ) as u64 ;
1687
+ // When calculating the set of HTLCs which will be included in their next
1688
+ // commitment_signed, all inbound HTLCs are included (as all states imply it will be
1689
+ // included) and only committed outbound HTLCs, see below.
1690
+ for ref htlc in self . pending_outbound_htlcs . iter ( ) {
1691
+ // We only include outbound HTLCs if it will not be included in their next
1692
+ // commitment_signed, ie if they've responded to us with an RAA after announcement
1693
+ // and if the removal process hasn't been finalized.
1694
+ match htlc. state {
1695
+ OutboundHTLCState :: Committed => their_acked_htlcs +=1 ,
1696
+ OutboundHTLCState :: RemoteRemoved { ..} => their_acked_htlcs +=1 ,
1697
+ _ => { } ,
1698
+ }
1699
+ }
1700
+
1701
+ their_acked_htlcs
1702
+ }
1703
+
1659
1704
pub fn update_add_htlc ( & mut self , msg : & msgs:: UpdateAddHTLC , pending_forward_state : PendingHTLCStatus ) -> Result < ( ) , ChannelError > {
1660
1705
if ( self . channel_state & ( ChannelState :: ChannelFunded as u32 | ChannelState :: RemoteShutdownSent as u32 ) ) != ( ChannelState :: ChannelFunded as u32 ) {
1661
1706
return Err ( ChannelError :: Close ( "Got add HTLC message when channel was not in an operational state" ) ) ;
@@ -1701,8 +1746,10 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
1701
1746
removed_outbound_total_msat += htlc. amount_msat ;
1702
1747
}
1703
1748
}
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" ) ) ;
1749
+ // The + 1 is for the HTLC that is currently being added to the commitment tx.
1750
+ let remote_fee_cost_msat = if self . channel_outbound { 0 } else { ( self . feerate_per_kw * ( COMMITMENT_TX_BASE_WEIGHT + ( self . htlc_count_next_remote_commit_tx ( ) + 1 ) * COMMITMENT_TX_WEIGHT_PER_HTLC ) ) } ;
1751
+ if htlc_inbound_value_msat + msg. amount_msat + self . value_to_self_msat + remote_fee_cost_msat > ( self . channel_value_satoshis - Channel :: < ChanSigner > :: get_our_channel_reserve_satoshis ( self . channel_value_satoshis ) ) * 1000 + removed_outbound_total_msat {
1752
+ return Err ( ChannelError :: Ignore ( "Remote HTLC add would put them over their reserve value" ) ) ;
1706
1753
}
1707
1754
if self . next_remote_htlc_id != msg. htlc_id {
1708
1755
return Err ( ChannelError :: Close ( "Remote skipped HTLC ID" ) ) ;
@@ -3031,6 +3078,9 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
3031
3078
res
3032
3079
} ,
3033
3080
their_max_htlc_value_in_flight_msat : self . their_max_htlc_value_in_flight_msat ,
3081
+ commit_tx_fee_outbound : if self . channel_outbound {
3082
+ ( self . feerate_per_kw * ( COMMITMENT_TX_BASE_WEIGHT + ( self . htlc_count_next_local_commit_tx ( ) + 1 ) * COMMITMENT_TX_WEIGHT_PER_HTLC ) )
3083
+ } else { 0 } ,
3034
3084
}
3035
3085
}
3036
3086
@@ -3534,9 +3584,15 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
3534
3584
return Err ( ChannelError :: Ignore ( "Cannot send value that would put us over the max HTLC value in flight our peer will accept" ) ) ;
3535
3585
}
3536
3586
3587
+ // Add additional reserve that avoids stuck channels in the case of fee spikes.
3588
+ let fee_spike_reserve = if self . channel_outbound { 2 * COMMITMENT_TX_WEIGHT_PER_HTLC * self . feerate_per_kw } else { 0 } ;
3589
+
3590
+ // The + 1 is for the HTLC currently being added to the commitment tx.
3591
+ let local_fee_cost_msat = if self . channel_outbound { ( self . feerate_per_kw * ( ( COMMITMENT_TX_BASE_WEIGHT + ( self . htlc_count_next_local_commit_tx ( ) + 1 ) * COMMITMENT_TX_WEIGHT_PER_HTLC ) ) ) } else { 0 } ;
3592
+
3537
3593
// Check self.their_channel_reserve_satoshis (the amount we must keep as
3538
3594
// 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 {
3595
+ if self . value_to_self_msat < self . their_channel_reserve_satoshis * 1000 + amount_msat + htlc_outbound_value_msat + local_fee_cost_msat + fee_spike_reserve {
3540
3596
return Err ( ChannelError :: Ignore ( "Cannot send value that would put us over their reserve value" ) ) ;
3541
3597
}
3542
3598
0 commit comments