Skip to content

Commit ec4adec

Browse files
committed
f - pass FundingNegotiationContext to calculate_change_output_value
1 parent 755511f commit ec4adec

File tree

2 files changed

+89
-109
lines changed

2 files changed

+89
-109
lines changed

lightning/src/ln/channel.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2768,18 +2768,14 @@ where
27682768
#[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled
27692769
fn begin_interactive_funding_tx_construction<ES: Deref>(
27702770
&mut self, signer_provider: &SP, entropy_source: &ES, holder_node_id: PublicKey,
2771-
is_initiator: bool, change_destination_opt: Option<ScriptBuf>,
2772-
shared_funding_input: Option<SharedOwnedInput>,
2771+
change_destination_opt: Option<ScriptBuf>, shared_funding_input: Option<SharedOwnedInput>,
27732772
) -> Result<Option<InteractiveTxMessageSend>, AbortReason>
27742773
where
27752774
ES::Target: EntropySource,
27762775
{
27772776
debug_assert!(matches!(self.context.channel_state, ChannelState::NegotiatingFunding(_)));
27782777
debug_assert!(self.interactive_tx_constructor.is_none());
27792778

2780-
let mut funding_inputs = Vec::new();
2781-
mem::swap(&mut self.funding_negotiation_context.our_funding_inputs, &mut funding_inputs);
2782-
27832779
// Add output for funding tx
27842780
// Note: For the error case when the inputs are insufficient, it will be handled after
27852781
// the `calculate_change_output_value` call below
@@ -2799,13 +2795,10 @@ where
27992795
.map_err(|_err| AbortReason::InternalError("Error getting destination script"))?
28002796
};
28012797
let change_value_opt = calculate_change_output_value(
2802-
is_initiator,
2803-
self.funding_negotiation_context.our_funding_satoshis,
2804-
&funding_inputs,
2798+
&self.funding_negotiation_context,
28052799
None,
28062800
&shared_funding_output.script_pubkey,
28072801
&funding_outputs,
2808-
self.funding_negotiation_context.funding_feerate_sat_per_1000_weight,
28092802
change_script.minimal_non_dust().to_sat(),
28102803
)?;
28112804
if let Some(change_value) = change_value_opt {
@@ -2824,6 +2817,9 @@ where
28242817
}
28252818
}
28262819

2820+
let mut funding_inputs = Vec::new();
2821+
mem::swap(&mut self.funding_negotiation_context.our_funding_inputs, &mut funding_inputs);
2822+
28272823
let constructor_args = InteractiveTxConstructorArgs {
28282824
entropy_source,
28292825
holder_node_id,
@@ -2832,7 +2828,7 @@ where
28322828
feerate_sat_per_kw: self
28332829
.funding_negotiation_context
28342830
.funding_feerate_sat_per_1000_weight,
2835-
is_initiator,
2831+
is_initiator: self.funding_negotiation_context.is_initiator,
28362832
funding_tx_locktime: self.funding_negotiation_context.funding_tx_locktime,
28372833
inputs_to_contribute: funding_inputs,
28382834
shared_funding_input,
@@ -5852,6 +5848,8 @@ fn check_v2_funding_inputs_sufficient(
58525848

58535849
/// Context for negotiating channels (dual-funded V2 open, splicing)
58545850
pub(super) struct FundingNegotiationContext {
5851+
/// Whether we initiated the funding negotiation.
5852+
pub is_initiator: bool,
58555853
/// The amount in satoshis we will be contributing to the channel.
58565854
pub our_funding_satoshis: u64,
58575855
/// The amount in satoshis our counterparty will be contributing to the channel.
@@ -11869,6 +11867,7 @@ where
1186911867
holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
1187011868
};
1187111869
let funding_negotiation_context = FundingNegotiationContext {
11870+
is_initiator: true,
1187211871
our_funding_satoshis: funding_satoshis,
1187311872
// TODO(dual_funding) TODO(splicing) Include counterparty contribution, once that's enabled
1187411873
their_funding_satoshis: None,
@@ -12029,6 +12028,7 @@ where
1202912028
context.channel_id = channel_id;
1203012029

1203112030
let funding_negotiation_context = FundingNegotiationContext {
12031+
is_initiator: false,
1203212032
our_funding_satoshis: our_funding_satoshis,
1203312033
their_funding_satoshis: Some(msg.common_fields.funding_satoshis),
1203412034
funding_tx_locktime: LockTime::from_consensus(msg.locktime),

lightning/src/ln/interactivetxs.rs

Lines changed: 79 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use bitcoin::{OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Wei
2222
use crate::chain::chaininterface::fee_for_weight;
2323
use crate::events::bump_transaction::{BASE_INPUT_WEIGHT, EMPTY_SCRIPT_SIG_WEIGHT};
2424
use crate::ln::chan_utils::FUNDING_TRANSACTION_WITNESS_WEIGHT;
25-
use crate::ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS;
25+
use crate::ln::channel::{FundingNegotiationContext, TOTAL_BITCOIN_SUPPLY_SATOSHIS};
2626
use crate::ln::msgs;
2727
use crate::ln::msgs::{MessageSendEvent, SerialId, TxSignatures};
2828
use crate::ln::types::ChannelId;
@@ -1874,26 +1874,21 @@ impl InteractiveTxConstructor {
18741874
/// `Err(AbortReason::InsufficientFees)`
18751875
///
18761876
/// Parameters:
1877-
/// - `is_initiator` - Whether we are the negotiation initiator or not (acceptor).
1878-
/// - `our_contribution` - The sats amount we intend to contribute to the funding
1879-
/// transaction being negotiated.
1880-
/// - `funding_inputs` - List of our inputs. It does not include the shared input, if there is one.
1877+
/// - `context` - Context of the funding negotiation, including non-shared inputs and feerate.
18811878
/// - `shared_input` - The locally owned amount of the shared input (in sats), if there is one.
18821879
/// - `shared_output_funding_script` - The script of the shared output.
18831880
/// - `funding_outputs` - Our funding outputs.
1884-
/// - `funding_feerate_sat_per_1000_weight` - Fee rate to be used.
18851881
/// - `change_output_dust_limit` - The dust limit (in sats) to consider.
18861882
pub(super) fn calculate_change_output_value(
1887-
is_initiator: bool, our_contribution: u64,
1888-
funding_inputs: &Vec<(TxIn, TransactionU16LenLimited)>, shared_input: Option<u64>,
1883+
context: &FundingNegotiationContext, shared_input: Option<u64>,
18891884
shared_output_funding_script: &ScriptBuf, funding_outputs: &Vec<TxOut>,
1890-
funding_feerate_sat_per_1000_weight: u32, change_output_dust_limit: u64,
1885+
change_output_dust_limit: u64,
18911886
) -> Result<Option<u64>, AbortReason> {
18921887
// Process inputs and their prev txs:
18931888
// calculate value sum and weight sum of inputs, also perform checks
18941889
let mut total_input_satoshis = 0u64;
18951890
let mut our_funding_inputs_weight = 0u64;
1896-
for (txin, tx) in funding_inputs.iter() {
1891+
for (txin, tx) in context.our_funding_inputs.iter() {
18971892
let txid = tx.as_transaction().compute_txid();
18981893
if txin.previous_output.txid != txid {
18991894
return Err(AbortReason::PrevTxOutInvalid);
@@ -1922,7 +1917,7 @@ pub(super) fn calculate_change_output_value(
19221917

19231918
// If we are the initiator, we must pay for the weight of the funding output and
19241919
// all common fields in the funding transaction.
1925-
if is_initiator {
1920+
if context.is_initiator {
19261921
weight = weight.saturating_add(get_output_weight(shared_output_funding_script).to_wu());
19271922
weight = weight.saturating_add(TX_COMMON_FIELDS_WEIGHT);
19281923

@@ -1931,15 +1926,15 @@ pub(super) fn calculate_change_output_value(
19311926
}
19321927
}
19331928

1934-
let fees_sats = fee_for_weight(funding_feerate_sat_per_1000_weight, weight);
1929+
let fees_sats = fee_for_weight(context.funding_feerate_sat_per_1000_weight, weight);
19351930

19361931
let net_total_less_fees =
19371932
total_input_satoshis.saturating_sub(total_output_satoshis).saturating_sub(fees_sats);
1938-
if net_total_less_fees < our_contribution {
1933+
if net_total_less_fees < context.our_funding_satoshis {
19391934
// Not enough to cover contribution plus fees
19401935
return Err(AbortReason::InsufficientFees);
19411936
}
1942-
let remaining_value = net_total_less_fees.saturating_sub(our_contribution);
1937+
let remaining_value = net_total_less_fees.saturating_sub(context.our_funding_satoshis);
19431938
if remaining_value < change_output_dust_limit {
19441939
// Enough to cover contribution plus fees, but leftover is below dust limit; no change
19451940
Ok(None)
@@ -1952,7 +1947,7 @@ pub(super) fn calculate_change_output_value(
19521947
#[cfg(test)]
19531948
mod tests {
19541949
use crate::chain::chaininterface::{fee_for_weight, FEERATE_FLOOR_SATS_PER_KW};
1955-
use crate::ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS;
1950+
use crate::ln::channel::{FundingNegotiationContext, TOTAL_BITCOIN_SUPPLY_SATOSHIS};
19561951
use crate::ln::interactivetxs::{
19571952
calculate_change_output_value, generate_holder_serial_id, AbortReason,
19581953
HandleTxCompleteValue, InteractiveTxConstructor, InteractiveTxConstructorArgs,
@@ -2980,89 +2975,74 @@ mod tests {
29802975
let gross_change = total_inputs - total_outputs - our_contributed;
29812976
let fees = 1746;
29822977
let common_fees = 234;
2983-
{
2984-
// There is leftover for change
2985-
let res = calculate_change_output_value(
2986-
true,
2987-
our_contributed,
2988-
&inputs,
2989-
None,
2990-
&ScriptBuf::new(),
2991-
&outputs,
2992-
funding_feerate_sat_per_1000_weight,
2993-
300,
2994-
);
2995-
assert_eq!(res, Ok(Some(gross_change - fees - common_fees)));
2996-
}
2997-
{
2998-
// There is leftover for change, without common fees
2999-
let res = calculate_change_output_value(
3000-
false,
3001-
our_contributed,
3002-
&inputs,
3003-
None,
3004-
&ScriptBuf::new(),
3005-
&outputs,
3006-
funding_feerate_sat_per_1000_weight,
3007-
300,
3008-
);
3009-
assert_eq!(res, Ok(Some(gross_change - fees)));
3010-
}
3011-
{
3012-
// Larger fee, smaller change
3013-
let res = calculate_change_output_value(
3014-
true,
3015-
our_contributed,
3016-
&inputs,
3017-
None,
3018-
&ScriptBuf::new(),
3019-
&outputs,
3020-
funding_feerate_sat_per_1000_weight * 3,
3021-
300,
3022-
);
3023-
assert_eq!(res, Ok(Some(4060)));
3024-
}
3025-
{
3026-
// Insufficient inputs, no leftover
3027-
let res = calculate_change_output_value(
3028-
false,
3029-
130_000,
3030-
&inputs,
3031-
None,
3032-
&ScriptBuf::new(),
3033-
&outputs,
3034-
funding_feerate_sat_per_1000_weight,
3035-
300,
3036-
);
3037-
assert_eq!(res, Err(AbortReason::InsufficientFees));
3038-
}
3039-
{
3040-
// Very small leftover
3041-
let res = calculate_change_output_value(
3042-
false,
3043-
118_000,
3044-
&inputs,
3045-
None,
3046-
&ScriptBuf::new(),
3047-
&outputs,
3048-
funding_feerate_sat_per_1000_weight,
3049-
300,
3050-
);
3051-
assert_eq!(res, Ok(None));
3052-
}
3053-
{
3054-
// Small leftover, but not dust
3055-
let res = calculate_change_output_value(
3056-
false,
3057-
117_992,
3058-
&inputs,
3059-
None,
3060-
&ScriptBuf::new(),
3061-
&outputs,
3062-
funding_feerate_sat_per_1000_weight,
3063-
100,
3064-
);
3065-
assert_eq!(res, Ok(Some(262)));
3066-
}
2978+
2979+
// There is leftover for change
2980+
let context = FundingNegotiationContext {
2981+
is_initiator: true,
2982+
our_funding_satoshis: our_contributed,
2983+
their_funding_satoshis: None,
2984+
funding_tx_locktime: AbsoluteLockTime::ZERO,
2985+
funding_feerate_sat_per_1000_weight,
2986+
our_funding_inputs: inputs,
2987+
};
2988+
assert_eq!(
2989+
calculate_change_output_value(&context, None, &ScriptBuf::new(), &outputs, 300),
2990+
Ok(Some(gross_change - fees - common_fees)),
2991+
);
2992+
2993+
// There is leftover for change, without common fees
2994+
let context = FundingNegotiationContext {
2995+
is_initiator: false,
2996+
..context
2997+
};
2998+
assert_eq!(
2999+
calculate_change_output_value(&context, None, &ScriptBuf::new(), &outputs, 300),
3000+
Ok(Some(gross_change - fees)),
3001+
);
3002+
3003+
// Larger fee, smaller change
3004+
let context = FundingNegotiationContext {
3005+
is_initiator: true,
3006+
funding_feerate_sat_per_1000_weight: funding_feerate_sat_per_1000_weight * 3,
3007+
..context
3008+
};
3009+
assert_eq!(
3010+
calculate_change_output_value(&context, None, &ScriptBuf::new(), &outputs, 300),
3011+
Ok(Some(4060)),
3012+
);
3013+
3014+
// Insufficient inputs, no leftover
3015+
let context = FundingNegotiationContext {
3016+
is_initiator: false,
3017+
our_funding_satoshis: 130_000,
3018+
funding_feerate_sat_per_1000_weight: funding_feerate_sat_per_1000_weight,
3019+
..context
3020+
};
3021+
assert_eq!(
3022+
calculate_change_output_value(&context, None, &ScriptBuf::new(), &outputs, 300),
3023+
Err(AbortReason::InsufficientFees),
3024+
);
3025+
3026+
// Very small leftover
3027+
let context = FundingNegotiationContext {
3028+
is_initiator: false,
3029+
our_funding_satoshis: 118_000,
3030+
..context
3031+
};
3032+
assert_eq!(
3033+
calculate_change_output_value(&context, None, &ScriptBuf::new(), &outputs, 300),
3034+
Ok(None),
3035+
);
3036+
3037+
// Small leftover, but not dust
3038+
let context = FundingNegotiationContext {
3039+
is_initiator: false,
3040+
our_funding_satoshis: 117_992,
3041+
..context
3042+
};
3043+
assert_eq!(
3044+
calculate_change_output_value(&context, None, &ScriptBuf::new(), &outputs, 100),
3045+
Ok(Some(262)),
3046+
);
30673047
}
30683048
}

0 commit comments

Comments
 (0)