Skip to content

Commit 3f49662

Browse files
committed
validate_update_add_htlc
1 parent c5e84da commit 3f49662

File tree

1 file changed

+46
-47
lines changed

1 file changed

+46
-47
lines changed

lightning/src/ln/channel.rs

Lines changed: 46 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ use crate::ln::script::{self, ShutdownScript};
7070
use crate::ln::types::ChannelId;
7171
use crate::routing::gossip::NodeId;
7272
use crate::sign::ecdsa::EcdsaChannelSigner;
73-
use crate::sign::tx_builder::{SpecTxBuilder, TxBuilder};
73+
use crate::sign::tx_builder::{SpecTxBuilder, TxBuilder, HTLCAmountDirection};
7474
use crate::sign::{ChannelSigner, EntropySource, NodeSigner, Recipient, SignerProvider};
7575
use crate::types::features::{ChannelTypeFeatures, InitFeatures};
7676
use crate::types::payment::{PaymentHash, PaymentPreimage};
@@ -1097,12 +1097,12 @@ pub enum AnnouncementSigsState {
10971097
/// An enum indicating whether the local or remote side offered a given HTLC.
10981098
enum HTLCInitiator {
10991099
LocalOffered,
1100+
#[allow(dead_code)]
11001101
RemoteOffered,
11011102
}
11021103

11031104
/// Current counts of various HTLCs, useful for calculating current balances available exactly.
11041105
struct HTLCStats {
1105-
pending_inbound_htlcs: usize,
11061106
pending_outbound_htlcs: usize,
11071107
pending_inbound_htlcs_value_msat: u64,
11081108
pending_outbound_htlcs_value_msat: u64,
@@ -4104,6 +4104,39 @@ where
41044104
);
41054105
}
41064106

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+
41074140
#[rustfmt::skip]
41084141
fn validate_update_add_htlc<F: Deref>(
41094142
&self, funding: &FundingScope, msg: &msgs::UpdateAddHTLC,
@@ -4119,70 +4152,37 @@ where
41194152
let dust_exposure_limiting_feerate = self.get_dust_exposure_limiting_feerate(
41204153
&fee_estimator, funding.get_channel_type(),
41214154
);
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 {
41244157
return Err(ChannelError::close(format!("Remote tried to push more than our max accepted HTLCs ({})", self.holder_max_accepted_htlcs)));
41254158
}
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 {
41274160
return Err(ChannelError::close(format!("Remote HTLC add would put them over our max HTLC value ({})", self.holder_max_htlc_value_in_flight_msat)));
41284161
}
41294162

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);
41584166

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()))?;
41654168

41664169
// Check that the remote can afford to pay for this HTLC on-chain at the current
41674170
// feerate_per_kw, while maintaining their channel reserve (as required by the spec).
41684171
{
41694172
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
41724174
};
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 {
41744176
return Err(ChannelError::close("Remote HTLC add would not leave enough to pay for fees".to_owned()));
41754177
};
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 {
41774179
return Err(ChannelError::close("Remote HTLC add would put them under remote reserve value".to_owned()));
41784180
}
41794181
}
41804182

41814183
if funding.is_outbound() {
41824184
// 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 {
41864186
return Err(ChannelError::close("Cannot accept HTLC that would put our balance under counterparty-announced channel reserve value".to_owned()));
41874187
}
41884188
}
@@ -4795,7 +4795,6 @@ where
47954795
});
47964796

47974797
HTLCStats {
4798-
pending_inbound_htlcs: self.pending_inbound_htlcs.len(),
47994798
pending_outbound_htlcs,
48004799
pending_inbound_htlcs_value_msat,
48014800
pending_outbound_htlcs_value_msat,

0 commit comments

Comments
 (0)