Skip to content

Commit 214b88c

Browse files
committed
Add ChannelContext::get_next_{local, remote}_commitment_stats
In upcoming commits, these methods will serve as proxies to `SpecTxBuilder::get_next_commitment_stats` in all validation of channel updates in `ChannelContext`. Eventually, these methods will completely replace `get_pending_htlc_stats`, and `get_next_{local, remote}_commit_tx_fee_msat`. When predicting the HTLCs on next commitment, we take the conservative approach and only assume that a HTLC will not be in the next commitment when it is guaranteed that it won't be.
1 parent a98a2af commit 214b88c

File tree

1 file changed

+162
-1
lines changed

1 file changed

+162
-1
lines changed

lightning/src/ln/channel.rs

Lines changed: 162 additions & 1 deletion
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::{HTLCAmountDirection, NextCommitmentStats, SpecTxBuilder, TxBuilder};
7474
use crate::sign::{ChannelSigner, EntropySource, NodeSigner, Recipient, SignerProvider};
7575
use crate::types::features::{ChannelTypeFeatures, InitFeatures};
7676
use crate::types::payment::{PaymentHash, PaymentPreimage};
@@ -4104,6 +4104,167 @@ where
41044104
);
41054105
}
41064106

4107+
/// Returns a best-effort guess of the set of HTLCs that will be present
4108+
/// on the next local or remote commitment. We cannot be certain as the
4109+
/// actual set of HTLCs present on the next commitment depends on the
4110+
/// ordering of commitment_signed and revoke_and_ack messages.
4111+
///
4112+
/// We take the conservative approach and only assume that a HTLC will
4113+
/// not be in the next commitment when it is guaranteed that it won't be.
4114+
#[allow(dead_code)]
4115+
#[rustfmt::skip]
4116+
fn get_next_commitment_htlcs(
4117+
&self, local: bool, htlc_candidate: Option<HTLCAmountDirection>, include_counterparty_unknown_htlcs: bool,
4118+
) -> Vec<HTLCAmountDirection> {
4119+
let mut commitment_htlcs = Vec::with_capacity(
4120+
1 + self.pending_inbound_htlcs.len()
4121+
+ self.pending_outbound_htlcs.len()
4122+
+ self.holding_cell_htlc_updates.len(),
4123+
);
4124+
// `LocalRemoved` HTLCs will certainly not be present on any future remote
4125+
// commitments, but they could be in a future local commitment as the remote has
4126+
// not yet acknowledged the removal.
4127+
let pending_inbound_htlcs = self
4128+
.pending_inbound_htlcs
4129+
.iter()
4130+
.filter(|InboundHTLCOutput { state, .. }| match (state, local) {
4131+
(InboundHTLCState::RemoteAnnounced(..), _) => true,
4132+
(InboundHTLCState::AwaitingRemoteRevokeToAnnounce(..), _) => true,
4133+
(InboundHTLCState::AwaitingAnnouncedRemoteRevoke(..), _) => true,
4134+
(InboundHTLCState::Committed, _) => true,
4135+
(InboundHTLCState::LocalRemoved(..), true) => true,
4136+
(InboundHTLCState::LocalRemoved(..), false) => false,
4137+
})
4138+
.map(|&InboundHTLCOutput { amount_msat, .. }| HTLCAmountDirection { outbound: false, amount_msat });
4139+
// `RemoteRemoved` HTLCs can still be present on the next remote commitment if
4140+
// local produces a commitment before acknowledging the update. These HTLCs
4141+
// will for sure not be present on the next local commitment.
4142+
let pending_outbound_htlcs = self
4143+
.pending_outbound_htlcs
4144+
.iter()
4145+
.filter(|OutboundHTLCOutput { state, .. }| match (state, local) {
4146+
(OutboundHTLCState::LocalAnnounced(..), _) => if include_counterparty_unknown_htlcs { true } else { false },
4147+
(OutboundHTLCState::Committed, _) => true,
4148+
(OutboundHTLCState::RemoteRemoved(..), true) => false,
4149+
(OutboundHTLCState::RemoteRemoved(..), false) => true,
4150+
(OutboundHTLCState::AwaitingRemoteRevokeToRemove(..), _) => false,
4151+
(OutboundHTLCState::AwaitingRemovedRemoteRevoke(..), _) => false,
4152+
})
4153+
.map(|&OutboundHTLCOutput { amount_msat, .. }| HTLCAmountDirection { outbound: true, amount_msat });
4154+
4155+
let holding_cell_htlcs = self.holding_cell_htlc_updates.iter().filter_map(|htlc| {
4156+
if let &HTLCUpdateAwaitingACK::AddHTLC { amount_msat, .. } = htlc {
4157+
Some(HTLCAmountDirection { outbound: true, amount_msat })
4158+
} else {
4159+
None
4160+
}
4161+
});
4162+
4163+
if include_counterparty_unknown_htlcs {
4164+
commitment_htlcs.extend(
4165+
htlc_candidate.into_iter().chain(pending_inbound_htlcs).chain(pending_outbound_htlcs).chain(holding_cell_htlcs)
4166+
);
4167+
} else {
4168+
commitment_htlcs.extend(
4169+
htlc_candidate.into_iter().chain(pending_inbound_htlcs).chain(pending_outbound_htlcs)
4170+
);
4171+
}
4172+
4173+
commitment_htlcs
4174+
}
4175+
4176+
/// This returns the value of `value_to_self_msat` after accounting for all the
4177+
/// successful inbound and outbound HTLCs that won't be present on the next
4178+
/// commitment.
4179+
///
4180+
/// To determine which HTLC claims to account for, we take the cases where a HTLC
4181+
/// will *not* be present on the next commitment from `next_commitment_htlcs`, and
4182+
/// check if their outcome is successful. If it is, we add the value of this claimed
4183+
/// HTLC to the balance of the claimer.
4184+
#[allow(dead_code)]
4185+
#[rustfmt::skip]
4186+
fn get_next_commitment_value_to_self_msat(&self, local: bool, funding: &FundingScope) -> u64 {
4187+
let inbound_claimed_htlc_msat: u64 =
4188+
self.pending_inbound_htlcs
4189+
.iter()
4190+
.filter(|InboundHTLCOutput { state, .. }| match (state, local) {
4191+
(InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_, _)), true) => false,
4192+
(InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_, _)), false) => true,
4193+
_ => false,
4194+
})
4195+
.map(|InboundHTLCOutput { amount_msat, .. }| amount_msat)
4196+
.sum();
4197+
let outbound_claimed_htlc_msat: u64 =
4198+
self.pending_outbound_htlcs
4199+
.iter()
4200+
.filter(|OutboundHTLCOutput { state, .. }| match (state, local) {
4201+
(OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(_, _)), true) => true,
4202+
(OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(_, _)), false) => false,
4203+
(OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_, _)), _) => true,
4204+
(OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_, _)), _) => true,
4205+
_ => false,
4206+
})
4207+
.map(|OutboundHTLCOutput { amount_msat, .. }| amount_msat)
4208+
.sum();
4209+
4210+
funding
4211+
.value_to_self_msat
4212+
.saturating_sub(outbound_claimed_htlc_msat)
4213+
.saturating_add(inbound_claimed_htlc_msat)
4214+
}
4215+
4216+
#[allow(dead_code)]
4217+
fn get_next_local_commitment_stats(
4218+
&self, funding: &FundingScope, htlc_candidate: Option<HTLCAmountDirection>,
4219+
include_counterparty_unknown_htlcs: bool, addl_nondust_htlc_count: usize,
4220+
feerate_per_kw: u32, dust_exposure_limiting_feerate: Option<u32>,
4221+
) -> NextCommitmentStats {
4222+
let next_commitment_htlcs = self.get_next_commitment_htlcs(
4223+
true,
4224+
htlc_candidate,
4225+
include_counterparty_unknown_htlcs,
4226+
);
4227+
let next_value_to_self_msat = self.get_next_commitment_value_to_self_msat(true, funding);
4228+
SpecTxBuilder {}.get_next_commitment_stats(
4229+
true,
4230+
funding.is_outbound(),
4231+
funding.get_value_satoshis(),
4232+
next_value_to_self_msat,
4233+
next_commitment_htlcs,
4234+
addl_nondust_htlc_count,
4235+
feerate_per_kw,
4236+
dust_exposure_limiting_feerate,
4237+
self.holder_dust_limit_satoshis,
4238+
funding.get_channel_type(),
4239+
)
4240+
}
4241+
4242+
#[allow(dead_code)]
4243+
fn get_next_remote_commitment_stats(
4244+
&self, funding: &FundingScope, htlc_candidate: Option<HTLCAmountDirection>,
4245+
include_counterparty_unknown_htlcs: bool, addl_nondust_htlc_count: usize,
4246+
feerate_per_kw: u32, dust_exposure_limiting_feerate: Option<u32>,
4247+
) -> NextCommitmentStats {
4248+
let next_commitment_htlcs = self.get_next_commitment_htlcs(
4249+
false,
4250+
htlc_candidate,
4251+
include_counterparty_unknown_htlcs,
4252+
);
4253+
let next_value_to_self_msat = self.get_next_commitment_value_to_self_msat(false, funding);
4254+
SpecTxBuilder {}.get_next_commitment_stats(
4255+
false,
4256+
funding.is_outbound(),
4257+
funding.get_value_satoshis(),
4258+
next_value_to_self_msat,
4259+
next_commitment_htlcs,
4260+
addl_nondust_htlc_count,
4261+
feerate_per_kw,
4262+
dust_exposure_limiting_feerate,
4263+
self.counterparty_dust_limit_satoshis,
4264+
funding.get_channel_type(),
4265+
)
4266+
}
4267+
41074268
#[rustfmt::skip]
41084269
fn validate_update_add_htlc<F: Deref>(
41094270
&self, funding: &FundingScope, msg: &msgs::UpdateAddHTLC,

0 commit comments

Comments
 (0)