Skip to content

Commit 06ed9cb

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 3a3e7eb commit 06ed9cb

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
@@ -74,7 +74,7 @@ use crate::ln::script::{self, ShutdownScript};
7474
use crate::ln::types::ChannelId;
7575
use crate::routing::gossip::NodeId;
7676
use crate::sign::ecdsa::EcdsaChannelSigner;
77-
use crate::sign::tx_builder::{SpecTxBuilder, TxBuilder};
77+
use crate::sign::tx_builder::{HTLCAmountDirection, NextCommitmentStats, SpecTxBuilder, TxBuilder};
7878
use crate::sign::{ChannelSigner, EntropySource, NodeSigner, Recipient, SignerProvider};
7979
use crate::types::features::{ChannelTypeFeatures, InitFeatures};
8080
use crate::types::payment::{PaymentHash, PaymentPreimage};
@@ -4100,6 +4100,167 @@ where
41004100
);
41014101
}
41024102

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

0 commit comments

Comments
 (0)