@@ -70,7 +70,7 @@ use crate::ln::script::{self, ShutdownScript};
70
70
use crate::ln::types::ChannelId;
71
71
use crate::routing::gossip::NodeId;
72
72
use crate::sign::ecdsa::EcdsaChannelSigner;
73
- use crate::sign::tx_builder::{SpecTxBuilder, TxBuilder};
73
+ use crate::sign::tx_builder::{SpecTxBuilder, TxBuilder, HTLCAmountDirection };
74
74
use crate::sign::{ChannelSigner, EntropySource, NodeSigner, Recipient, SignerProvider};
75
75
use crate::types::features::{ChannelTypeFeatures, InitFeatures};
76
76
use crate::types::payment::{PaymentHash, PaymentPreimage};
@@ -1097,12 +1097,12 @@ pub enum AnnouncementSigsState {
1097
1097
/// An enum indicating whether the local or remote side offered a given HTLC.
1098
1098
enum HTLCInitiator {
1099
1099
LocalOffered,
1100
+ #[allow(dead_code)]
1100
1101
RemoteOffered,
1101
1102
}
1102
1103
1103
1104
/// Current counts of various HTLCs, useful for calculating current balances available exactly.
1104
1105
struct HTLCStats {
1105
- pending_inbound_htlcs: usize,
1106
1106
pending_outbound_htlcs: usize,
1107
1107
pending_inbound_htlcs_value_msat: u64,
1108
1108
pending_outbound_htlcs_value_msat: u64,
@@ -4104,6 +4104,39 @@ where
4104
4104
);
4105
4105
}
4106
4106
4107
+ fn pending_inbound_htlcs_value_msat(&self) -> u64 {
4108
+ self.pending_inbound_htlcs.iter().map(|htlc| htlc.amount_msat).sum()
4109
+ }
4110
+
4111
+ fn next_commitment_htlcs(&self, htlc_candidate: Option<HTLCAmountDirection>) -> Vec<HTLCAmountDirection> {
4112
+ let mut commitment_htlcs = Vec::with_capacity(1 + self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + self.holding_cell_htlc_updates.len());
4113
+ let pending_inbound_htlcs = self.pending_inbound_htlcs.iter().map(|InboundHTLCOutput { amount_msat, .. }| HTLCAmountDirection { outbound: false, amount_msat: *amount_msat });
4114
+ use OutboundHTLCState::*;
4115
+ let pending_outbound_htlcs = self.pending_outbound_htlcs.iter().filter_map(|OutboundHTLCOutput { ref state, amount_msat, .. }|
4116
+ matches!(state, LocalAnnounced { .. } | Committed | RemoteRemoved { .. }).then_some(HTLCAmountDirection { outbound: true, amount_msat: *amount_msat }));
4117
+
4118
+ // We do not include holding cell HTLCs, we will validate them upon freeing the holding cell...
4119
+ //let holding_cell_htlcs = self.holding_cell_htlc_updates.iter().filter_map(|htlc| if let HTLCUpdateAwaitingACK::AddHTLC { amount_msat, ..} = htlc { Some(HTLCAmountDirection { outbound: true, amount_msat: *amount_msat }) } else { None });
4120
+
4121
+ commitment_htlcs.extend(htlc_candidate.into_iter().chain(pending_inbound_htlcs).chain(pending_outbound_htlcs));
4122
+ commitment_htlcs
4123
+ }
4124
+
4125
+ fn get_next_commitment_value_to_self_msat(&self, funding: &FundingScope) -> u64 {
4126
+ let outbound_removed_htlc_msat: u64 = self.pending_outbound_htlcs
4127
+ .iter()
4128
+ .filter_map(|htlc| {
4129
+ matches!(
4130
+ htlc.state,
4131
+ OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_, _))
4132
+ | OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_, _))
4133
+ )
4134
+ .then_some(htlc.amount_msat)
4135
+ })
4136
+ .sum();
4137
+ funding.value_to_self_msat.saturating_sub(outbound_removed_htlc_msat)
4138
+ }
4139
+
4107
4140
#[rustfmt::skip]
4108
4141
fn validate_update_add_htlc<F: Deref>(
4109
4142
&self, funding: &FundingScope, msg: &msgs::UpdateAddHTLC,
@@ -4119,70 +4152,37 @@ where
4119
4152
let dust_exposure_limiting_feerate = self.get_dust_exposure_limiting_feerate(
4120
4153
&fee_estimator, funding.get_channel_type(),
4121
4154
);
4122
- let htlc_stats = self.get_pending_htlc_stats(funding, None, dust_exposure_limiting_feerate);
4123
- if htlc_stats .pending_inbound_htlcs + 1 > self.holder_max_accepted_htlcs as usize {
4155
+
4156
+ if self .pending_inbound_htlcs.len() + 1 > self.holder_max_accepted_htlcs as usize {
4124
4157
return Err(ChannelError::close(format!("Remote tried to push more than our max accepted HTLCs ({})", self.holder_max_accepted_htlcs)));
4125
4158
}
4126
- if htlc_stats .pending_inbound_htlcs_value_msat + msg.amount_msat > self.holder_max_htlc_value_in_flight_msat {
4159
+ if self .pending_inbound_htlcs_value_msat() + msg.amount_msat > self.holder_max_htlc_value_in_flight_msat {
4127
4160
return Err(ChannelError::close(format!("Remote HTLC add would put them over our max HTLC value ({})", self.holder_max_htlc_value_in_flight_msat)));
4128
4161
}
4129
4162
4130
- // Check holder_selected_channel_reserve_satoshis (we're getting paid, so they have to at least meet
4131
- // the reserve_satoshis we told them to always have as direct payment so that they lose
4132
- // something if we punish them for broadcasting an old state).
4133
- // Note that we don't really care about having a small/no to_remote output in our local
4134
- // commitment transactions, as the purpose of the channel reserve is to ensure we can
4135
- // punish *them* if they misbehave, so we discount any outbound HTLCs which will not be
4136
- // present in the next commitment transaction we send them (at least for fulfilled ones,
4137
- // failed ones won't modify value_to_self).
4138
- // Note that we will send HTLCs which another instance of rust-lightning would think
4139
- // violate the reserve value if we do not do this (as we forget inbound HTLCs from the
4140
- // Channel state once they will not be present in the next received commitment
4141
- // transaction).
4142
- let (local_balance_before_fee_msat, remote_balance_before_fee_msat) = {
4143
- let removed_outbound_total_msat: u64 = self.pending_outbound_htlcs
4144
- .iter()
4145
- .filter_map(|htlc| {
4146
- matches!(
4147
- htlc.state,
4148
- OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_, _))
4149
- | OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_, _))
4150
- )
4151
- .then_some(htlc.amount_msat)
4152
- })
4153
- .sum();
4154
- let pending_value_to_self_msat =
4155
- funding.value_to_self_msat + htlc_stats.pending_inbound_htlcs_value_msat - removed_outbound_total_msat;
4156
- let pending_remote_value_msat =
4157
- funding.get_value_satoshis() * 1000 - pending_value_to_self_msat;
4163
+ let next_commitment_htlcs = self.next_commitment_htlcs(Some(HTLCAmountDirection { outbound: false, amount_msat: msg.amount_msat }));
4164
+ let value_to_self_msat = self.get_next_commitment_value_to_self_msat(funding);
4165
+ let next_commitment_stats = SpecTxBuilder {}.get_builder_stats(funding.is_outbound(), funding.get_value_satoshis(), value_to_self_msat, &next_commitment_htlcs, 0, self.feerate_per_kw, dust_exposure_limiting_feerate, funding.get_channel_type(), self.holder_dust_limit_satoshis, self.counterparty_dust_limit_satoshis);
4158
4166
4159
- // Subtract any non-HTLC outputs from the local and remote balances
4160
- SpecTxBuilder {}.subtract_non_htlc_outputs(funding.is_outbound(), funding.value_to_self_msat, pending_remote_value_msat, funding.get_channel_type())
4161
- };
4162
- if remote_balance_before_fee_msat < msg.amount_msat {
4163
- return Err(ChannelError::close("Remote HTLC add would overdraw remaining funds".to_owned()));
4164
- }
4167
+ let remote_balance_before_fee_msat = next_commitment_stats.counterparty_balance_msat.ok_or(ChannelError::close("Remote HTLC add would overdraw remaining funds".to_owned()))?;
4165
4168
4166
4169
// Check that the remote can afford to pay for this HTLC on-chain at the current
4167
4170
// feerate_per_kw, while maintaining their channel reserve (as required by the spec).
4168
4171
{
4169
4172
let remote_commit_tx_fee_msat = if funding.is_outbound() { 0 } else {
4170
- let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
4171
- self.next_remote_commit_tx_fee_msat(funding, Some(htlc_candidate), None) // Don't include the extra fee spike buffer HTLC in calculations
4173
+ next_commitment_stats.counterparty_commit_tx_fee_sat * 1000
4172
4174
};
4173
- if remote_balance_before_fee_msat.saturating_sub(msg.amount_msat) < remote_commit_tx_fee_msat {
4175
+ if remote_balance_before_fee_msat < remote_commit_tx_fee_msat {
4174
4176
return Err(ChannelError::close("Remote HTLC add would not leave enough to pay for fees".to_owned()));
4175
4177
};
4176
- if remote_balance_before_fee_msat.saturating_sub(msg.amount_msat).saturating_sub( remote_commit_tx_fee_msat) < funding.holder_selected_channel_reserve_satoshis * 1000 {
4178
+ if remote_balance_before_fee_msat.saturating_sub(remote_commit_tx_fee_msat) < funding.holder_selected_channel_reserve_satoshis * 1000 {
4177
4179
return Err(ChannelError::close("Remote HTLC add would put them under remote reserve value".to_owned()));
4178
4180
}
4179
4181
}
4180
4182
4181
4183
if funding.is_outbound() {
4182
4184
// Check that they won't violate our local required channel reserve by adding this HTLC.
4183
- let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
4184
- let local_commit_tx_fee_msat = self.next_local_commit_tx_fee_msat(funding, htlc_candidate, None);
4185
- if local_balance_before_fee_msat < funding.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 + local_commit_tx_fee_msat {
4185
+ if next_commitment_stats.holder_balance_msat.unwrap() < funding.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 + next_commitment_stats.holder_commit_tx_fee_sat * 1000 {
4186
4186
return Err(ChannelError::close("Cannot accept HTLC that would put our balance under counterparty-announced channel reserve value".to_owned()));
4187
4187
}
4188
4188
}
@@ -4795,7 +4795,6 @@ where
4795
4795
});
4796
4796
4797
4797
HTLCStats {
4798
- pending_inbound_htlcs: self.pending_inbound_htlcs.len(),
4799
4798
pending_outbound_htlcs,
4800
4799
pending_inbound_htlcs_value_msat,
4801
4800
pending_outbound_htlcs_value_msat,
0 commit comments