Skip to content

Commit 22c866a

Browse files
committed
minor Add error case when inputs are insufficient
1 parent 9644612 commit 22c866a

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
@@ -2172,12 +2172,17 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
21722172
};
21732173

21742174
// Optionally add change output
2175-
if let Some(change_value) = calculate_change_output_value(
2175+
let change_value_opt = calculate_change_output_value(
21762176
self.context.is_outbound(), self.dual_funding_context.our_funding_satoshis,
21772177
&funding_inputs_prev_outputs, &funding_outputs,
21782178
self.dual_funding_context.funding_feerate_sat_per_1000_weight,
21792179
self.context.holder_dust_limit_satoshis,
2180-
) {
2180+
).map_err(|err| APIError::APIMisuseError {
2181+
err: format!("Insufficient inputs, cannot cover intended contribution of {} and fees; {}",
2182+
self.dual_funding_context.our_funding_satoshis, err
2183+
),
2184+
})?;
2185+
if let Some(change_value) = change_value_opt {
21812186
let change_script = signer_provider.get_destination_script(self.context.channel_keys_id).map_err(
21822187
|err| APIError::APIMisuseError {
21832188
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
@@ -1665,14 +1665,19 @@ impl InteractiveTxConstructor {
16651665
/// Determine whether a change output should be added or not, and if so, of what size,
16661666
/// considering our given inputs, outputs, and intended contribution.
16671667
/// Computes and takes into account fees.
1668-
/// Return value is the value computed for the change output (in satoshis),
1669-
/// or None if a change is not needed/possible.
1668+
/// Three outcomes are possible:
1669+
/// - Inputs are sufficient for intended contribution, fees, and a larger-than-dust change:
1670+
/// Ok(Some(change_amount))
1671+
/// - Inputs are sufficient for intended contribution and fees, but not for a change:
1672+
/// Ok(None)
1673+
/// - Insputs are not sufficent to cover contribution and fees:
1674+
/// Err(AbortReason::InsufficientFees)
16701675
#[allow(dead_code)] // TODO(dual_funding): Remove once begin_interactive_funding_tx_construction() is used
16711676
pub(super) fn calculate_change_output_value(
16721677
is_initiator: bool, our_contribution: u64, funding_inputs_prev_outputs: &Vec<&TxOut>,
16731678
funding_outputs: &Vec<OutputOwned>, funding_feerate_sat_per_1000_weight: u32,
16741679
holder_dust_limit_satoshis: u64,
1675-
) -> Option<u64> {
1680+
) -> Result<Option<u64>, AbortReason> {
16761681
let our_funding_inputs_weight =
16771682
funding_inputs_prev_outputs.iter().fold(0u64, |weight, prev_output| {
16781683
weight.saturating_add(estimate_input_weight(prev_output).to_wu())
@@ -1695,13 +1700,19 @@ pub(super) fn calculate_change_output_value(
16951700
funding_inputs_prev_outputs.iter().map(|out| out.value.to_sat()).sum();
16961701

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

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

@@ -2665,7 +2676,7 @@ mod tests {
26652676
funding_feerate_sat_per_1000_weight,
26662677
300,
26672678
);
2668-
assert_eq!(res.unwrap(), gross_change - fees - common_fees);
2679+
assert_eq!(res.unwrap().unwrap(), gross_change - fees - common_fees);
26692680
}
26702681
{
26712682
// There is leftover for change, without common fees
@@ -2677,7 +2688,7 @@ mod tests {
26772688
funding_feerate_sat_per_1000_weight,
26782689
300,
26792690
);
2680-
assert_eq!(res.unwrap(), gross_change - fees);
2691+
assert_eq!(res.unwrap().unwrap(), gross_change - fees);
26812692
}
26822693
{
26832694
// Larger fee, smaller change
@@ -2689,7 +2700,7 @@ mod tests {
26892700
9000,
26902701
300,
26912702
);
2692-
assert_eq!(res.unwrap(), 14384);
2703+
assert_eq!(res.unwrap().unwrap(), 14384);
26932704
}
26942705
{
26952706
// Insufficient inputs, no leftover
@@ -2701,7 +2712,7 @@ mod tests {
27012712
funding_feerate_sat_per_1000_weight,
27022713
300,
27032714
);
2704-
assert!(res.is_none());
2715+
assert_eq!(res.err().unwrap(), AbortReason::InsufficientFees);
27052716
}
27062717
{
27072718
// Very small leftover
@@ -2713,7 +2724,7 @@ mod tests {
27132724
funding_feerate_sat_per_1000_weight,
27142725
300,
27152726
);
2716-
assert!(res.is_none());
2727+
assert!(res.unwrap().is_none());
27172728
}
27182729
{
27192730
// Small leftover, but not dust
@@ -2725,7 +2736,7 @@ mod tests {
27252736
funding_feerate_sat_per_1000_weight,
27262737
100,
27272738
);
2728-
assert_eq!(res.unwrap(), 154);
2739+
assert_eq!(res.unwrap().unwrap(), 154);
27292740
}
27302741
}
27312742
}

0 commit comments

Comments
 (0)