Skip to content

Commit 728e7c2

Browse files
committed
Remove i64 casts in ChannelContext::build_commitment_transaction
Instead of converting operands to `i64` and checking if the subtractions overflowed by checking if the `i64` is smaller than zero, we instead choose to do checked and saturating subtractions on the original unsigned integers.
1 parent 592f17d commit 728e7c2

File tree

1 file changed

+37
-27
lines changed

1 file changed

+37
-27
lines changed

lightning/src/ln/channel.rs

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3758,14 +3758,17 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
37583758
}
37593759
}
37603760

3761-
let value_to_self_msat: i64 = (funding.value_to_self_msat - local_htlc_total_msat) as i64 + value_to_self_msat_offset;
3762-
assert!(value_to_self_msat >= 0);
3763-
// Note that in case they have several just-awaiting-last-RAA fulfills in-progress (ie
3764-
// AwaitingRemoteRevokeToRemove or AwaitingRemovedRemoteRevoke) we may have allowed them to
3765-
// "violate" their reserve value by couting those against it. Thus, we have to convert
3766-
// everything to i64 before subtracting as otherwise we can overflow.
3767-
let value_to_remote_msat: i64 = (funding.get_value_satoshis() * 1000) as i64 - (funding.value_to_self_msat as i64) - (remote_htlc_total_msat as i64) - value_to_self_msat_offset;
3768-
assert!(value_to_remote_msat >= 0);
3761+
// # Panics
3762+
//
3763+
// While we expect `value_to_self_msat_offset` to be negative in some cases, the value going
3764+
// to each party MUST be 0 or positive, even if all HTLCs pending in the commitment clear by
3765+
// failure.
3766+
3767+
// TODO: When MSRV >= 1.66.0, use u64::checked_add_signed
3768+
let mut value_to_self_msat = (funding.value_to_self_msat as i64 + value_to_self_msat_offset).try_into().unwrap();
3769+
let mut value_to_remote_msat = (funding.get_value_satoshis() * 1000).checked_sub(value_to_self_msat).unwrap();
3770+
value_to_self_msat = value_to_self_msat.checked_sub(local_htlc_total_msat).unwrap();
3771+
value_to_remote_msat = value_to_remote_msat.checked_sub(remote_htlc_total_msat).unwrap();
37693772

37703773
#[cfg(debug_assertions)]
37713774
{
@@ -3776,33 +3779,40 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
37763779
} else {
37773780
funding.counterparty_max_commitment_tx_output.lock().unwrap()
37783781
};
3779-
debug_assert!(broadcaster_max_commitment_tx_output.0 <= value_to_self_msat as u64 || value_to_self_msat / 1000 >= funding.counterparty_selected_channel_reserve_satoshis.unwrap() as i64);
3780-
broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat as u64);
3781-
debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat as u64 || value_to_remote_msat / 1000 >= funding.holder_selected_channel_reserve_satoshis as i64);
3782-
broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat as u64);
3782+
debug_assert!(broadcaster_max_commitment_tx_output.0 <= value_to_self_msat || value_to_self_msat / 1000 >= funding.counterparty_selected_channel_reserve_satoshis.unwrap());
3783+
broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat);
3784+
debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat || value_to_remote_msat / 1000 >= funding.holder_selected_channel_reserve_satoshis);
3785+
broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat);
37833786
}
37843787

3788+
// We MUST use saturating subs here, as the funder's balance is not guaranteed to be greater
3789+
// than or equal to the sum of `total_fee_sat` and `anchors_val`.
3790+
//
3791+
// This is because when the remote party sends an `update_fee` message, we build the new
3792+
// commitment transaction *before* checking whether the remote party's balance is enough to
3793+
// cover the total fee and the anchors.
3794+
37853795
let total_fee_sat = commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), &funding.channel_transaction_parameters.channel_type_features);
3786-
let anchors_val = if funding.channel_transaction_parameters.channel_type_features.supports_anchors_zero_fee_htlc_tx() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 } as i64;
3796+
let anchors_val = if funding.channel_transaction_parameters.channel_type_features.supports_anchors_zero_fee_htlc_tx() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 };
37873797
let (value_to_self, value_to_remote) = if funding.is_outbound() {
3788-
(value_to_self_msat / 1000 - anchors_val - total_fee_sat as i64, value_to_remote_msat / 1000)
3798+
((value_to_self_msat / 1000).saturating_sub(anchors_val).saturating_sub(total_fee_sat), value_to_remote_msat / 1000)
37893799
} else {
3790-
(value_to_self_msat / 1000, value_to_remote_msat / 1000 - anchors_val - total_fee_sat as i64)
3800+
(value_to_self_msat / 1000, (value_to_remote_msat / 1000).saturating_sub(anchors_val).saturating_sub(total_fee_sat))
37913801
};
37923802

3793-
let mut value_to_a = if local { value_to_self } else { value_to_remote };
3794-
let mut value_to_b = if local { value_to_remote } else { value_to_self };
3803+
let mut to_broadcaster_value_sat = if local { value_to_self } else { value_to_remote };
3804+
let mut to_countersignatory_value_sat = if local { value_to_remote } else { value_to_self };
37953805

3796-
if value_to_a >= (broadcaster_dust_limit_satoshis as i64) {
3797-
log_trace!(logger, " ...including {} output with value {}", if local { "to_local" } else { "to_remote" }, value_to_a);
3806+
if to_broadcaster_value_sat >= broadcaster_dust_limit_satoshis {
3807+
log_trace!(logger, " ...including {} output with value {}", if local { "to_local" } else { "to_remote" }, to_broadcaster_value_sat);
37983808
} else {
3799-
value_to_a = 0;
3809+
to_broadcaster_value_sat = 0;
38003810
}
38013811

3802-
if value_to_b >= (broadcaster_dust_limit_satoshis as i64) {
3803-
log_trace!(logger, " ...including {} output with value {}", if local { "to_remote" } else { "to_local" }, value_to_b);
3812+
if to_countersignatory_value_sat >= broadcaster_dust_limit_satoshis {
3813+
log_trace!(logger, " ...including {} output with value {}", if local { "to_remote" } else { "to_local" }, to_countersignatory_value_sat);
38043814
} else {
3805-
value_to_b = 0;
3815+
to_countersignatory_value_sat = 0;
38063816
}
38073817

38083818
let num_nondust_htlcs = included_non_dust_htlcs.len();
@@ -3812,8 +3822,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
38123822
else { funding.channel_transaction_parameters.as_counterparty_broadcastable() };
38133823
let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number,
38143824
per_commitment_point,
3815-
value_to_a as u64,
3816-
value_to_b as u64,
3825+
to_broadcaster_value_sat,
3826+
to_countersignatory_value_sat,
38173827
feerate_per_kw,
38183828
&mut included_non_dust_htlcs,
38193829
&channel_parameters,
@@ -3830,8 +3840,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
38303840
total_fee_sat,
38313841
num_nondust_htlcs,
38323842
htlcs_included,
3833-
local_balance_msat: value_to_self_msat as u64,
3834-
remote_balance_msat: value_to_remote_msat as u64,
3843+
local_balance_msat: value_to_self_msat,
3844+
remote_balance_msat: value_to_remote_msat,
38353845
inbound_htlc_preimages,
38363846
outbound_htlc_preimages,
38373847
}

0 commit comments

Comments
 (0)