Skip to content

Commit 26ea1e0

Browse files
committed
Return AvailableBalances in get_onchain_stats
Note that `AvailableBalances` will always refer to the holder's balances, even when `local` is set to `false`, when calling `TxBuilder::get_onchain_stats`.
1 parent 0fb1c01 commit 26ea1e0

2 files changed

Lines changed: 149 additions & 52 deletions

File tree

lightning/src/ln/channel.rs

Lines changed: 97 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,7 @@ use crate::offers::static_invoice::StaticInvoice;
7474
use crate::routing::gossip::NodeId;
7575
use crate::sign::ecdsa::EcdsaChannelSigner;
7676
use crate::sign::tx_builder::{
77-
get_available_balances, ChannelConstraints, HTLCAmountDirection, NextCommitmentStats,
78-
SpecTxBuilder, TxBuilder,
77+
ChannelConstraints, HTLCAmountDirection, NextCommitmentStats, SpecTxBuilder, TxBuilder,
7978
};
8079
use crate::sign::{ChannelSigner, EntropySource, NodeSigner, Recipient, SignerProvider};
8180
use crate::types::features::{ChannelTypeFeatures, InitFeatures};
@@ -3556,6 +3555,20 @@ impl<SP: SignerProvider> ChannelContext<SP> {
35563555
// check if the funder's amount for the initial commitment tx is sufficient
35573556
// for full fee payment plus a few HTLCs to ensure the channel will be useful.
35583557
let funders_amount_msat = open_channel_fields.funding_satoshis * 1000 - msg_push_msat;
3558+
let holder_channel_constraints = ChannelConstraints {
3559+
dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
3560+
channel_reserve_satoshis: msg_channel_reserve_satoshis,
3561+
htlc_minimum_msat: if config.channel_handshake_config.our_htlc_minimum_msat == 0 { 1 } else { config.channel_handshake_config.our_htlc_minimum_msat },
3562+
max_accepted_htlcs: cmp::min(config.channel_handshake_config.our_max_accepted_htlcs, max_htlcs(&channel_type)).into(),
3563+
max_htlc_value_in_flight_msat: get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.channel_handshake_config),
3564+
};
3565+
let counterparty_channel_constraints = ChannelConstraints {
3566+
dust_limit_satoshis: open_channel_fields.dust_limit_satoshis,
3567+
channel_reserve_satoshis: holder_selected_channel_reserve_satoshis,
3568+
htlc_minimum_msat: open_channel_fields.htlc_minimum_msat,
3569+
max_accepted_htlcs: open_channel_fields.max_accepted_htlcs.into(),
3570+
max_htlc_value_in_flight_msat: cmp::min(open_channel_fields.max_htlc_value_in_flight_msat, channel_value_satoshis * 1000),
3571+
};
35593572
let remote_stats = SpecTxBuilder {}.get_onchain_stats(
35603573
false, /* local */
35613574
false, /* is_outbound_from_holder */
@@ -3566,11 +3579,13 @@ impl<SP: SignerProvider> ChannelContext<SP> {
35663579
if channel_type.supports_anchor_zero_fee_commitments() { 0 } else { MIN_AFFORDABLE_HTLC_COUNT },
35673580
open_channel_fields.commitment_feerate_sat_per_1000_weight, /* feerate_per_kw */
35683581
None, /* dust_exposure_limiting_feerate, set to `None` as we don't check dust exposure due to excess fees here */
3569-
open_channel_fields.dust_limit_satoshis, /* counterparty_dust_limit_satoshis, does not matter as there are no pending HTLCs */
3582+
u64::MAX, /* max_dust_htlc_exposure_msat, we don't care about our max dust htlc exposure yet */
3583+
holder_channel_constraints,
3584+
counterparty_channel_constraints,
35703585
&channel_type
35713586
).map_err(|()| ChannelError::close(format!("Funding amount ({} sats) can't even pay fee for initial commitment transaction.", funders_amount_msat / 1000)))?;
35723587

3573-
let to_remote_satoshis = remote_stats.counterparty_balance_msat / 1000;
3588+
let to_remote_satoshis = remote_stats.commitment_stats.counterparty_balance_msat / 1000;
35743589
// While it's reasonable for us to not meet the channel reserve initially (if they don't
35753590
// want to push much to us), our counterparty should always have more than our reserve.
35763591
if to_remote_satoshis < holder_selected_channel_reserve_satoshis {
@@ -3827,6 +3842,20 @@ impl<SP: SignerProvider> ChannelContext<SP> {
38273842
);
38283843

38293844
let value_to_self_msat = channel_value_satoshis * 1000 - push_msat;
3845+
let holder_channel_constraints = ChannelConstraints {
3846+
dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
3847+
channel_reserve_satoshis: 0,
3848+
htlc_minimum_msat: if config.channel_handshake_config.our_htlc_minimum_msat == 0 { 1 } else { config.channel_handshake_config.our_htlc_minimum_msat },
3849+
max_accepted_htlcs: cmp::min(config.channel_handshake_config.our_max_accepted_htlcs, max_htlcs(&channel_type)).into(),
3850+
max_htlc_value_in_flight_msat: get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.channel_handshake_config),
3851+
};
3852+
let counterparty_channel_constraints = ChannelConstraints {
3853+
dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
3854+
channel_reserve_satoshis: holder_selected_channel_reserve_satoshis,
3855+
htlc_minimum_msat: 1,
3856+
max_accepted_htlcs: max_htlcs(&channel_type).into(),
3857+
max_htlc_value_in_flight_msat: channel_value_satoshis,
3858+
};
38303859
let _local_stats = SpecTxBuilder {}.get_onchain_stats(
38313860
true, /* local */
38323861
true, /* is_outbound_from_holder */
@@ -3837,8 +3866,10 @@ impl<SP: SignerProvider> ChannelContext<SP> {
38373866
if channel_type.supports_anchor_zero_fee_commitments() { 0 } else { MIN_AFFORDABLE_HTLC_COUNT },
38383867
commitment_feerate,
38393868
None, /* dust_exposure_limiting_feerate, set to `None` as we don't check dust exposure due to excess fees here */
3840-
MIN_CHAN_DUST_LIMIT_SATOSHIS, /* holder_dust_limit_satoshis, does not matter as there are no pending HTLCs */
3841-
&channel_type,
3869+
u64::MAX, /* max_dust_htlc_exposure_msat, we don't care about our max dust htlc exposure yet */
3870+
holder_channel_constraints,
3871+
counterparty_channel_constraints,
3872+
&channel_type
38423873
).map_err(|()| APIError::APIMisuseError { err: format!("Funding amount ({}) can't even pay fee for initial commitment transaction.", value_to_self_msat / 1000)})?;
38433874

38443875
let mut secp_ctx = Secp256k1::new();
@@ -3966,7 +3997,8 @@ impl<SP: SignerProvider> ChannelContext<SP> {
39663997
feerate_per_kw: commitment_feerate,
39673998
counterparty_dust_limit_satoshis: 0,
39683999
holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
3969-
counterparty_max_htlc_value_in_flight_msat: 0,
4000+
// Set to 100% of the channel value for now, will be adjusted down as needed when receiving accept channel
4001+
counterparty_max_htlc_value_in_flight_msat: channel_value_satoshis,
39704002
// We'll adjust this to include our counterparty's `funding_satoshis` when we
39714003
// receive `accept_channel2`.
39724004
holder_max_htlc_value_in_flight_msat: get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.channel_handshake_config),
@@ -4701,18 +4733,28 @@ impl<SP: SignerProvider> ChannelContext<SP> {
47014733
);
47024734
let next_value_to_self_msat = self.get_next_commitment_value_to_self_msat(true, funding);
47034735

4704-
let ret = SpecTxBuilder {}.get_onchain_stats(
4705-
true,
4706-
funding.is_outbound(),
4707-
funding.get_value_satoshis(),
4708-
next_value_to_self_msat,
4709-
&next_commitment_htlcs,
4710-
addl_nondust_htlc_count,
4711-
feerate_per_kw,
4712-
dust_exposure_limiting_feerate,
4713-
self.holder_dust_limit_satoshis,
4714-
funding.get_channel_type(),
4715-
)?;
4736+
let max_dust_htlc_exposure_msat =
4737+
self.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
4738+
4739+
let holder_channel_constraints = self.get_holder_channel_constraints(funding);
4740+
let counterparty_channel_constraints = self.get_counterparty_channel_constraints(funding);
4741+
4742+
let ret = SpecTxBuilder {}
4743+
.get_onchain_stats(
4744+
true,
4745+
funding.is_outbound(),
4746+
funding.get_value_satoshis(),
4747+
next_value_to_self_msat,
4748+
&next_commitment_htlcs,
4749+
addl_nondust_htlc_count,
4750+
feerate_per_kw,
4751+
dust_exposure_limiting_feerate,
4752+
max_dust_htlc_exposure_msat,
4753+
holder_channel_constraints,
4754+
counterparty_channel_constraints,
4755+
funding.get_channel_type(),
4756+
)?
4757+
.commitment_stats;
47164758

47174759
#[cfg(any(test, fuzzing))]
47184760
{
@@ -4733,10 +4775,13 @@ impl<SP: SignerProvider> ChannelContext<SP> {
47334775
0,
47344776
feerate_per_kw,
47354777
dust_exposure_limiting_feerate,
4736-
self.holder_dust_limit_satoshis,
4778+
max_dust_htlc_exposure_msat,
4779+
holder_channel_constraints,
4780+
counterparty_channel_constraints,
47374781
funding.get_channel_type(),
47384782
)
4739-
.expect("Balance exhausted on local commitment");
4783+
.expect("Balance exhausted on local commitment")
4784+
.commitment_stats;
47404785
*funding.next_local_fee.lock().unwrap() = PredictedNextFee {
47414786
predicted_feerate: feerate_per_kw,
47424787
predicted_nondust_htlc_count: predicted_stats.nondust_htlc_count,
@@ -4760,18 +4805,28 @@ impl<SP: SignerProvider> ChannelContext<SP> {
47604805
);
47614806
let next_value_to_self_msat = self.get_next_commitment_value_to_self_msat(false, funding);
47624807

4763-
let ret = SpecTxBuilder {}.get_onchain_stats(
4764-
false,
4765-
funding.is_outbound(),
4766-
funding.get_value_satoshis(),
4767-
next_value_to_self_msat,
4768-
&next_commitment_htlcs,
4769-
addl_nondust_htlc_count,
4770-
feerate_per_kw,
4771-
dust_exposure_limiting_feerate,
4772-
self.counterparty_dust_limit_satoshis,
4773-
funding.get_channel_type(),
4774-
)?;
4808+
let max_dust_htlc_exposure_msat =
4809+
self.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
4810+
4811+
let holder_channel_constraints = self.get_holder_channel_constraints(funding);
4812+
let counterparty_channel_constraints = self.get_counterparty_channel_constraints(funding);
4813+
4814+
let ret = SpecTxBuilder {}
4815+
.get_onchain_stats(
4816+
false,
4817+
funding.is_outbound(),
4818+
funding.get_value_satoshis(),
4819+
next_value_to_self_msat,
4820+
&next_commitment_htlcs,
4821+
addl_nondust_htlc_count,
4822+
feerate_per_kw,
4823+
dust_exposure_limiting_feerate,
4824+
max_dust_htlc_exposure_msat,
4825+
holder_channel_constraints,
4826+
counterparty_channel_constraints,
4827+
funding.get_channel_type(),
4828+
)?
4829+
.commitment_stats;
47754830

47764831
#[cfg(any(test, fuzzing))]
47774832
{
@@ -4792,10 +4847,13 @@ impl<SP: SignerProvider> ChannelContext<SP> {
47924847
0,
47934848
feerate_per_kw,
47944849
dust_exposure_limiting_feerate,
4795-
self.counterparty_dust_limit_satoshis,
4850+
max_dust_htlc_exposure_msat,
4851+
holder_channel_constraints,
4852+
counterparty_channel_constraints,
47964853
funding.get_channel_type(),
47974854
)
4798-
.expect("Balance exhausted on remote commitment");
4855+
.expect("Balance exhausted on remote commitment")
4856+
.commitment_stats;
47994857
*funding.next_remote_fee.lock().unwrap() = PredictedNextFee {
48004858
predicted_feerate: feerate_per_kw,
48014859
predicted_nondust_htlc_count: predicted_stats.nondust_htlc_count,
@@ -5640,18 +5698,20 @@ impl<SP: SignerProvider> ChannelContext<SP> {
56405698
);
56415699
let max_dust_htlc_exposure_msat = self.get_max_dust_htlc_exposure_msat(dust_exposure_limiting_feerate);
56425700

5643-
get_available_balances(
5701+
SpecTxBuilder {}.get_onchain_stats(
5702+
true,
56445703
funding.is_outbound(),
56455704
funding.get_value_satoshis(),
56465705
funding.get_value_to_self_msat(),
56475706
&pending_htlcs,
5707+
0,
56485708
self.feerate_per_kw,
56495709
dust_exposure_limiting_feerate,
56505710
max_dust_htlc_exposure_msat,
56515711
self.get_holder_channel_constraints(funding),
56525712
self.get_counterparty_channel_constraints(funding),
56535713
funding.get_channel_type(),
5654-
)
5714+
).unwrap().available_balances
56555715
}
56565716

56575717
#[rustfmt::skip]

lightning/src/sign/tx_builder.rs

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ pub(crate) struct NextCommitmentStats {
4242
pub commit_tx_fee_sat: u64,
4343
}
4444

45+
pub(crate) struct OnchainStats {
46+
pub available_balances: crate::ln::channel::AvailableBalances,
47+
pub commitment_stats: NextCommitmentStats,
48+
}
49+
4550
fn commit_plus_htlc_tx_fees_msat(
4651
local: bool, next_commitment_htlcs: &[HTLCAmountDirection], dust_buffer_feerate: u32,
4752
feerate: u32, broadcaster_dust_limit_satoshis: u64, channel_type: &ChannelTypeFeatures,
@@ -293,7 +298,7 @@ fn get_next_commitment_stats(
293298
})
294299
}
295300

296-
pub(crate) fn get_available_balances(
301+
fn get_available_balances(
297302
is_outbound_from_holder: bool, channel_value_satoshis: u64, value_to_holder_msat: u64,
298303
pending_htlcs: &[HTLCAmountDirection], feerate_per_kw: u32,
299304
dust_exposure_limiting_feerate: Option<u32>, max_dust_htlc_exposure_msat: u64,
@@ -512,11 +517,12 @@ pub(crate) fn get_available_balances(
512517
pub(crate) trait TxBuilder {
513518
fn get_onchain_stats(
514519
&self, local: bool, is_outbound_from_holder: bool, channel_value_satoshis: u64,
515-
value_to_holder_msat: u64, next_commitment_htlcs: &[HTLCAmountDirection],
520+
value_to_holder_msat: u64, pending_htlcs: &[HTLCAmountDirection],
516521
addl_nondust_htlc_count: usize, feerate_per_kw: u32,
517-
dust_exposure_limiting_feerate: Option<u32>, broadcaster_dust_limit_satoshis: u64,
518-
channel_type: &ChannelTypeFeatures,
519-
) -> Result<NextCommitmentStats, ()>;
522+
dust_exposure_limiting_feerate: Option<u32>, max_dust_htlc_exposure_msat: u64,
523+
holder_channel_constraints: ChannelConstraints,
524+
counterparty_channel_constraints: ChannelConstraints, channel_type: &ChannelTypeFeatures,
525+
) -> Result<OnchainStats, ()>;
520526
fn build_commitment_transaction<L: Logger>(
521527
&self, local: bool, commitment_number: u64, per_commitment_point: &PublicKey,
522528
channel_parameters: &ChannelTransactionParameters, secp_ctx: &Secp256k1<secp256k1::All>,
@@ -530,23 +536,54 @@ pub(crate) struct SpecTxBuilder {}
530536
impl TxBuilder for SpecTxBuilder {
531537
fn get_onchain_stats(
532538
&self, local: bool, is_outbound_from_holder: bool, channel_value_satoshis: u64,
533-
value_to_holder_msat: u64, next_commitment_htlcs: &[HTLCAmountDirection],
539+
value_to_holder_msat: u64, pending_htlcs: &[HTLCAmountDirection],
534540
addl_nondust_htlc_count: usize, feerate_per_kw: u32,
535-
dust_exposure_limiting_feerate: Option<u32>, broadcaster_dust_limit_satoshis: u64,
536-
channel_type: &ChannelTypeFeatures,
537-
) -> Result<NextCommitmentStats, ()> {
538-
get_next_commitment_stats(
539-
local,
541+
dust_exposure_limiting_feerate: Option<u32>, max_dust_htlc_exposure_msat: u64,
542+
holder_channel_constraints: ChannelConstraints,
543+
counterparty_channel_constraints: ChannelConstraints, channel_type: &ChannelTypeFeatures,
544+
) -> Result<OnchainStats, ()> {
545+
let commitment_stats = if local {
546+
get_next_commitment_stats(
547+
true,
548+
is_outbound_from_holder,
549+
channel_value_satoshis,
550+
value_to_holder_msat,
551+
pending_htlcs,
552+
addl_nondust_htlc_count,
553+
feerate_per_kw,
554+
dust_exposure_limiting_feerate,
555+
holder_channel_constraints.dust_limit_satoshis,
556+
channel_type,
557+
)?
558+
} else {
559+
get_next_commitment_stats(
560+
false,
561+
is_outbound_from_holder,
562+
channel_value_satoshis,
563+
value_to_holder_msat,
564+
pending_htlcs,
565+
addl_nondust_htlc_count,
566+
feerate_per_kw,
567+
dust_exposure_limiting_feerate,
568+
counterparty_channel_constraints.dust_limit_satoshis,
569+
channel_type,
570+
)?
571+
};
572+
573+
let available_balances = get_available_balances(
540574
is_outbound_from_holder,
541575
channel_value_satoshis,
542576
value_to_holder_msat,
543-
next_commitment_htlcs,
544-
addl_nondust_htlc_count,
577+
pending_htlcs,
545578
feerate_per_kw,
546579
dust_exposure_limiting_feerate,
547-
broadcaster_dust_limit_satoshis,
580+
max_dust_htlc_exposure_msat,
581+
holder_channel_constraints,
582+
counterparty_channel_constraints,
548583
channel_type,
549-
)
584+
);
585+
586+
Ok(OnchainStats { available_balances, commitment_stats })
550587
}
551588
fn build_commitment_transaction<L: Logger>(
552589
&self, local: bool, commitment_number: u64, per_commitment_point: &PublicKey,

0 commit comments

Comments
 (0)