Skip to content

Commit 9a4eabe

Browse files
committed
minor Add error case when inputs are insufficient
1 parent 3625987 commit 9a4eabe

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

22852285
// Optionally add change output
2286-
if let Some(change_value) = calculate_change_output_value(
2286+
let change_value_opt = calculate_change_output_value(
22872287
self.funding.is_outbound(), self.dual_funding_context.our_funding_satoshis,
22882288
&funding_inputs_prev_outputs, &funding_outputs,
22892289
self.dual_funding_context.funding_feerate_sat_per_1000_weight,
22902290
self.context.holder_dust_limit_satoshis,
2291-
) {
2291+
).map_err(|err| APIError::APIMisuseError {
2292+
err: format!("Insufficient inputs, cannot cover intended contribution of {} and fees; {}",
2293+
self.dual_funding_context.our_funding_satoshis, err
2294+
),
2295+
})?;
2296+
if let Some(change_value) = change_value_opt {
22922297
let change_script = signer_provider.get_destination_script(self.context.channel_keys_id).map_err(
22932298
|err| APIError::APIMisuseError {
22942299
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
@@ -1667,14 +1667,19 @@ impl InteractiveTxConstructor {
16671667
/// Determine whether a change output should be added or not, and if so, of what size,
16681668
/// considering our given inputs, outputs, and intended contribution.
16691669
/// Computes and takes into account fees.
1670-
/// Return value is the value computed for the change output (in satoshis),
1671-
/// or None if a change is not needed/possible.
1670+
/// Three outcomes are possible:
1671+
/// - Inputs are sufficient for intended contribution, fees, and a larger-than-dust change:
1672+
/// Ok(Some(change_amount))
1673+
/// - Inputs are sufficient for intended contribution and fees, but not for a change:
1674+
/// Ok(None)
1675+
/// - Insputs are not sufficent to cover contribution and fees:
1676+
/// Err(AbortReason::InsufficientFees)
16721677
#[allow(dead_code)] // TODO(dual_funding): Remove once begin_interactive_funding_tx_construction() is used
16731678
pub(super) fn calculate_change_output_value(
16741679
is_initiator: bool, our_contribution: u64, funding_inputs_prev_outputs: &Vec<&TxOut>,
16751680
funding_outputs: &Vec<OutputOwned>, funding_feerate_sat_per_1000_weight: u32,
16761681
holder_dust_limit_satoshis: u64,
1677-
) -> Option<u64> {
1682+
) -> Result<Option<u64>, AbortReason> {
16781683
let our_funding_inputs_weight =
16791684
funding_inputs_prev_outputs.iter().fold(0u64, |weight, prev_output| {
16801685
weight.saturating_add(estimate_input_weight(prev_output).to_wu())
@@ -1697,13 +1702,19 @@ pub(super) fn calculate_change_output_value(
16971702
funding_inputs_prev_outputs.iter().map(|out| out.value.to_sat()).sum();
16981703

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

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

@@ -2667,7 +2678,7 @@ mod tests {
26672678
funding_feerate_sat_per_1000_weight,
26682679
300,
26692680
);
2670-
assert_eq!(res.unwrap(), gross_change - fees - common_fees);
2681+
assert_eq!(res.unwrap().unwrap(), gross_change - fees - common_fees);
26712682
}
26722683
{
26732684
// There is leftover for change, without common fees
@@ -2679,7 +2690,7 @@ mod tests {
26792690
funding_feerate_sat_per_1000_weight,
26802691
300,
26812692
);
2682-
assert_eq!(res.unwrap(), gross_change - fees);
2693+
assert_eq!(res.unwrap().unwrap(), gross_change - fees);
26832694
}
26842695
{
26852696
// Larger fee, smaller change
@@ -2691,7 +2702,7 @@ mod tests {
26912702
9000,
26922703
300,
26932704
);
2694-
assert_eq!(res.unwrap(), 14384);
2705+
assert_eq!(res.unwrap().unwrap(), 14384);
26952706
}
26962707
{
26972708
// Insufficient inputs, no leftover
@@ -2703,7 +2714,7 @@ mod tests {
27032714
funding_feerate_sat_per_1000_weight,
27042715
300,
27052716
);
2706-
assert!(res.is_none());
2717+
assert_eq!(res.err().unwrap(), AbortReason::InsufficientFees);
27072718
}
27082719
{
27092720
// Very small leftover
@@ -2715,7 +2726,7 @@ mod tests {
27152726
funding_feerate_sat_per_1000_weight,
27162727
300,
27172728
);
2718-
assert!(res.is_none());
2729+
assert!(res.unwrap().is_none());
27192730
}
27202731
{
27212732
// Small leftover, but not dust
@@ -2727,7 +2738,7 @@ mod tests {
27272738
funding_feerate_sat_per_1000_weight,
27282739
100,
27292740
);
2730-
assert_eq!(res.unwrap(), 154);
2741+
assert_eq!(res.unwrap().unwrap(), 154);
27312742
}
27322743
}
27332744
}

0 commit comments

Comments
 (0)