Skip to content

Commit ae3fdd9

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 subtractions on the original unsigned integers. In addition, prior to this commit, we remained silent if the subtraction of the total fee and the anchors from the funder's balance underflowed; we now panic in this case.
1 parent 1c4a496 commit ae3fdd9

File tree

1 file changed

+37
-37
lines changed

1 file changed

+37
-37
lines changed

lightning/src/ln/channel.rs

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

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

37723775
#[cfg(debug_assertions)]
37733776
{
@@ -3778,33 +3781,39 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
37783781
} else {
37793782
funding.counterparty_max_commitment_tx_output.lock().unwrap()
37803783
};
3781-
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);
3782-
broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat as u64);
3783-
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);
3784-
broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat as u64);
3784+
debug_assert!(broadcaster_max_commitment_tx_output.0 <= value_to_self_msat || value_to_self_msat / 1000 >= funding.counterparty_selected_channel_reserve_satoshis.unwrap());
3785+
broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat);
3786+
debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat || value_to_remote_msat / 1000 >= funding.holder_selected_channel_reserve_satoshis);
3787+
broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat);
37853788
}
37863789

3790+
// # Panics
3791+
//
3792+
// The sum of the total fees and the anchors MUST be smaller than or equal to the funder's
3793+
// current balance rounded to the lower satoshi.
3794+
37873795
let total_fee_sat = commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), &funding.channel_transaction_parameters.channel_type_features);
3788-
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 };
3797+
let funder_debit = total_fee_sat.checked_add(anchors_val).unwrap();
37893798
let (value_to_self, value_to_remote) = if funding.is_outbound() {
3790-
(value_to_self_msat / 1000 - anchors_val - total_fee_sat as i64, value_to_remote_msat / 1000)
3799+
((value_to_self_msat / 1000).checked_sub(funder_debit).unwrap(), value_to_remote_msat / 1000)
37913800
} else {
3792-
(value_to_self_msat / 1000, value_to_remote_msat / 1000 - anchors_val - total_fee_sat as i64)
3801+
(value_to_self_msat / 1000, (value_to_remote_msat / 1000).checked_sub(funder_debit).unwrap())
37933802
};
37943803

3795-
let mut value_to_a = if local { value_to_self } else { value_to_remote };
3796-
let mut value_to_b = if local { value_to_remote } else { value_to_self };
3804+
let mut to_broadcaster_value_sat = if local { value_to_self } else { value_to_remote };
3805+
let mut to_countersignatory_value_sat = if local { value_to_remote } else { value_to_self };
37973806

3798-
if value_to_a >= (broadcaster_dust_limit_satoshis as i64) {
3799-
log_trace!(logger, " ...including {} output with value {}", if local { "to_local" } else { "to_remote" }, value_to_a);
3807+
if to_broadcaster_value_sat >= broadcaster_dust_limit_satoshis {
3808+
log_trace!(logger, " ...including {} output with value {}", if local { "to_local" } else { "to_remote" }, to_broadcaster_value_sat);
38003809
} else {
3801-
value_to_a = 0;
3810+
to_broadcaster_value_sat = 0;
38023811
}
38033812

3804-
if value_to_b >= (broadcaster_dust_limit_satoshis as i64) {
3805-
log_trace!(logger, " ...including {} output with value {}", if local { "to_remote" } else { "to_local" }, value_to_b);
3813+
if to_countersignatory_value_sat >= broadcaster_dust_limit_satoshis {
3814+
log_trace!(logger, " ...including {} output with value {}", if local { "to_remote" } else { "to_local" }, to_countersignatory_value_sat);
38063815
} else {
3807-
value_to_b = 0;
3816+
to_countersignatory_value_sat = 0;
38083817
}
38093818

38103819
let num_nondust_htlcs = included_non_dust_htlcs.len();
@@ -3814,8 +3823,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
38143823
else { funding.channel_transaction_parameters.as_counterparty_broadcastable() };
38153824
let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number,
38163825
per_commitment_point,
3817-
value_to_a as u64,
3818-
value_to_b as u64,
3826+
to_broadcaster_value_sat,
3827+
to_countersignatory_value_sat,
38193828
feerate_per_kw,
38203829
&mut included_non_dust_htlcs,
38213830
&channel_parameters,
@@ -3832,8 +3841,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
38323841
total_fee_sat,
38333842
num_nondust_htlcs,
38343843
htlcs_included,
3835-
local_balance_msat: value_to_self_msat as u64,
3836-
remote_balance_msat: value_to_remote_msat as u64,
3844+
local_balance_msat: value_to_self_msat,
3845+
remote_balance_msat: value_to_remote_msat,
38373846
inbound_htlc_preimages,
38383847
outbound_htlc_preimages,
38393848
}
@@ -12416,19 +12425,10 @@ mod tests {
1241612425
"30450221009ad80792e3038fe6968d12ff23e6888a565c3ddd065037f357445f01675d63f3022018384915e5f1f4ae157e15debf4f49b61c8d9d2b073c7d6f97c4a68caa3ed4c1",
1241712426
"02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b80024a01000000000000220020e9e86e4823faa62e222ebc858a226636856158f07e69898da3b0d1af0ddb3994c0c62d0000000000220020f3394e1e619b0eca1f91be2fb5ab4dfc59ba5b84ebe014ad1d43a564d012994a04004830450221009ad80792e3038fe6968d12ff23e6888a565c3ddd065037f357445f01675d63f3022018384915e5f1f4ae157e15debf4f49b61c8d9d2b073c7d6f97c4a68caa3ed4c1014830450221008fd5dbff02e4b59020d4cd23a3c30d3e287065fda75a0a09b402980adf68ccda022001e0b8b620cd915ddff11f1de32addf23d81d51b90e6841b2cb8dcaf3faa5ecf01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {});
1241812427

12419-
// commitment tx with fee greater than funder amount
12420-
chan.funding.value_to_self_msat = 6993000000; // 7000000000 - 7000000
12421-
chan.context.feerate_per_kw = 9651936;
12422-
chan.context.holder_dust_limit_satoshis = 546;
12423-
chan.context.channel_type = cached_channel_type;
12424-
12425-
test_commitment!("304402202ade0142008309eb376736575ad58d03e5b115499709c6db0b46e36ff394b492022037b63d78d66404d6504d4c4ac13be346f3d1802928a6d3ad95a6a944227161a2",
12426-
"304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a379",
12427-
"02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8001c0c62d0000000000160014cc1b07838e387deacd0e5232e1e8b49f4c29e484040047304402207e8d51e0c570a5868a78414f4e0cbfaed1106b171b9581542c30718ee4eb95ba02203af84194c97adf98898c9afe2f2ed4a7f8dba05a2dfab28ac9d9c604aa49a3790147304402202ade0142008309eb376736575ad58d03e5b115499709c6db0b46e36ff394b492022037b63d78d66404d6504d4c4ac13be346f3d1802928a6d3ad95a6a944227161a201475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", {});
12428-
1242912428
// commitment tx with 3 htlc outputs, 2 offered having the same amount and preimage
1243012429
chan.funding.value_to_self_msat = 7_000_000_000 - 2_000_000;
1243112430
chan.context.feerate_per_kw = 253;
12431+
chan.context.holder_dust_limit_satoshis = 546;
1243212432
chan.context.pending_inbound_htlcs.clear();
1243312433
chan.context.pending_inbound_htlcs.push({
1243412434
let mut out = InboundHTLCOutput{

0 commit comments

Comments
 (0)