Skip to content

Commit e12a945

Browse files
committed
minor Add error case when inputs are insufficient
1 parent 17f32f9 commit e12a945

File tree

2 files changed

+32
-16
lines changed

2 files changed

+32
-16
lines changed

lightning/src/ln/channel.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2282,12 +2282,17 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
22822282
};
22832283

22842284
// Optionally add change output
2285-
if let Some(change_value) = calculate_change_output_value(
2285+
let change_value_opt = calculate_change_output_value(
22862286
self.funding.is_outbound(), self.dual_funding_context.our_funding_satoshis,
22872287
&funding_inputs_prev_outputs, &funding_outputs,
22882288
self.dual_funding_context.funding_feerate_sat_per_1000_weight,
22892289
self.context.holder_dust_limit_satoshis,
2290-
) {
2290+
).map_err(|err| APIError::APIMisuseError {
2291+
err: format!("Insufficient inputs, cannot cover intended contribution of {} and fees; {}",
2292+
self.dual_funding_context.our_funding_satoshis, err
2293+
),
2294+
})?;
2295+
if let Some(change_value) = change_value_opt {
22912296
let change_script = signer_provider.get_destination_script(self.context.channel_keys_id).map_err(
22922297
|err| APIError::APIMisuseError {
22932298
err: format!("Failed to get change script as new destination script, {:?}", err),

lightning/src/ln/interactivetxs.rs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,14 +1666,19 @@ impl InteractiveTxConstructor {
16661666
/// Determine whether a change output should be added or not, and if so, of what size,
16671667
/// considering our given inputs, outputs, and intended contribution.
16681668
/// Computes and takes into account fees.
1669-
/// Return value is the value computed for the change output (in satoshis),
1670-
/// or None if a change is not needed/possible.
1669+
/// Three outcomes are possible:
1670+
/// - Inputs are sufficient for intended contribution, fees, and a larger-than-dust change:
1671+
/// Ok(Some(change_amount))
1672+
/// - Inputs are sufficient for intended contribution and fees, but not for a change:
1673+
/// Ok(None)
1674+
/// - Insputs are not sufficent to cover contribution and fees:
1675+
/// Err(AbortReason::InsufficientFees)
16711676
#[allow(dead_code)] // TODO(dual_funding): Remove once begin_interactive_funding_tx_construction() is used
16721677
pub(super) fn calculate_change_output_value(
16731678
is_initiator: bool, our_contribution: u64, funding_inputs_prev_outputs: &Vec<&TxOut>,
16741679
funding_outputs: &Vec<OutputOwned>, funding_feerate_sat_per_1000_weight: u32,
16751680
holder_dust_limit_satoshis: u64,
1676-
) -> Option<u64> {
1681+
) -> Result<Option<u64>, AbortReason> {
16771682
let our_funding_inputs_weight =
16781683
funding_inputs_prev_outputs.iter().fold(0u64, |weight, prev_output| {
16791684
weight.saturating_add(estimate_input_weight(prev_output).to_wu())
@@ -1696,13 +1701,19 @@ pub(super) fn calculate_change_output_value(
16961701
funding_inputs_prev_outputs.iter().map(|out| out.value.to_sat()).sum();
16971702

16981703
// Note: in case of additional outputs, they will have to be subtracted here
1699-
let remaining_value =
1700-
total_input_satoshis.saturating_sub(our_contribution).saturating_sub(fees_sats);
17011704

1702-
if remaining_value <= holder_dust_limit_satoshis {
1703-
None
1705+
let min_contribution_and_fees = our_contribution.saturating_add(fees_sats);
1706+
let min_contribution_and_fees_and_dust = min_contribution_and_fees.saturating_add(holder_dust_limit_satoshis);
1707+
if total_input_satoshis < min_contribution_and_fees {
1708+
// Not enough to cover contribution plus fees
1709+
Err(AbortReason::InsufficientFees)
1710+
} else if total_input_satoshis < min_contribution_and_fees_and_dust {
1711+
// Enough to cover contribution plus fees, but leftover is below dust limit
1712+
Ok(None)
17041713
} else {
1705-
Some(remaining_value)
1714+
// Enough to have over-dust change
1715+
let remaining_value = total_input_satoshis.saturating_sub(min_contribution_and_fees);
1716+
Ok(Some(remaining_value))
17061717
}
17071718
}
17081719

@@ -2666,7 +2677,7 @@ mod tests {
26662677
funding_feerate_sat_per_1000_weight,
26672678
300,
26682679
);
2669-
assert_eq!(res.unwrap(), gross_change - fees - common_fees);
2680+
assert_eq!(res.unwrap().unwrap(), gross_change - fees - common_fees);
26702681
}
26712682
{
26722683
// There is leftover for change, without common fees
@@ -2678,7 +2689,7 @@ mod tests {
26782689
funding_feerate_sat_per_1000_weight,
26792690
300,
26802691
);
2681-
assert_eq!(res.unwrap(), gross_change - fees);
2692+
assert_eq!(res.unwrap().unwrap(), gross_change - fees);
26822693
}
26832694
{
26842695
// Larger fee, smaller change
@@ -2690,7 +2701,7 @@ mod tests {
26902701
9000,
26912702
300,
26922703
);
2693-
assert_eq!(res.unwrap(), 14384);
2704+
assert_eq!(res.unwrap().unwrap(), 14384);
26942705
}
26952706
{
26962707
// Insufficient inputs, no leftover
@@ -2702,7 +2713,7 @@ mod tests {
27022713
funding_feerate_sat_per_1000_weight,
27032714
300,
27042715
);
2705-
assert!(res.is_none());
2716+
assert_eq!(res.err().unwrap(), AbortReason::InsufficientFees);
27062717
}
27072718
{
27082719
// Very small leftover
@@ -2714,7 +2725,7 @@ mod tests {
27142725
funding_feerate_sat_per_1000_weight,
27152726
300,
27162727
);
2717-
assert!(res.is_none());
2728+
assert!(res.unwrap().is_none());
27182729
}
27192730
{
27202731
// Small leftover, but not dust
@@ -2726,7 +2737,7 @@ mod tests {
27262737
funding_feerate_sat_per_1000_weight,
27272738
100,
27282739
);
2729-
assert_eq!(res.unwrap(), 154);
2740+
assert_eq!(res.unwrap().unwrap(), 154);
27302741
}
27312742
}
27322743
}

0 commit comments

Comments
 (0)