Skip to content

Commit 5369660

Browse files
committed
Use a FundingTxContributions enum for funding iputs and change
Specify what inputs and outputs to contribute to a funding transaction using an enum. This will make the splice-in and upcoming splice-out use cases explicit.
1 parent 8b832ba commit 5369660

File tree

2 files changed

+84
-44
lines changed

2 files changed

+84
-44
lines changed

lightning/src/ln/channel.rs

Lines changed: 77 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5977,13 +5977,8 @@ pub(super) struct FundingNegotiationContext {
59775977
/// The input spending the previous funding output, if this is a splice.
59785978
#[allow(dead_code)] // TODO(splicing): Remove once splicing is enabled.
59795979
pub shared_funding_input: Option<SharedOwnedInput>,
5980-
/// The funding inputs we will be contributing to the channel.
5981-
#[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
5982-
pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
5983-
/// The change output script. This will be used if needed or -- if not set -- generated using
5984-
/// `SignerProvider::get_destination_script`.
5985-
#[allow(dead_code)] // TODO(splicing): Remove once splicing is enabled.
5986-
pub change_script: Option<ScriptBuf>,
5980+
/// The components of the funding transaction that we will contribute.
5981+
pub funding_tx_contributions: FundingTxContributions,
59875982
}
59885983

59895984
impl FundingNegotiationContext {
@@ -6019,35 +6014,43 @@ impl FundingNegotiationContext {
60196014
script_pubkey: funding.get_funding_redeemscript().to_p2wsh(),
60206015
};
60216016

6022-
// Optionally add change output
6023-
if self.our_funding_contribution > SignedAmount::ZERO {
6024-
let change_value_opt = calculate_change_output_value(
6017+
let change_value_opt = if self.our_funding_contribution > SignedAmount::ZERO {
6018+
calculate_change_output_value(
60256019
&self,
60266020
self.shared_funding_input.is_some(),
60276021
&shared_funding_output.script_pubkey,
60286022
&funding_outputs,
60296023
context.holder_dust_limit_satoshis,
6030-
)?;
6031-
if let Some(change_value) = change_value_opt {
6032-
let change_script = if let Some(script) = self.change_script {
6033-
script
6034-
} else {
6035-
signer_provider
6036-
.get_destination_script(context.channel_keys_id)
6037-
.map_err(|_err| AbortReason::InternalError("Error getting change script"))?
6038-
};
6039-
let mut change_output =
6040-
TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
6041-
let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
6042-
let change_output_fee =
6043-
fee_for_weight(self.funding_feerate_sat_per_1000_weight, change_output_weight);
6044-
let change_value_decreased_with_fee =
6045-
change_value.saturating_sub(change_output_fee);
6046-
// Check dust limit again
6047-
if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
6048-
change_output.value = Amount::from_sat(change_value_decreased_with_fee);
6049-
funding_outputs.push(change_output);
6050-
}
6024+
)?
6025+
} else {
6026+
None
6027+
};
6028+
6029+
let (inputs_to_contribute, change_script) = match self.funding_tx_contributions {
6030+
FundingTxContributions::InputsOnly { inputs, change_script } => (inputs, change_script),
6031+
};
6032+
6033+
// Add change output if necessary
6034+
if let Some(change_value) = change_value_opt {
6035+
let change_script = if let Some(script) = change_script {
6036+
script
6037+
} else {
6038+
signer_provider
6039+
.get_destination_script(context.channel_keys_id)
6040+
.map_err(|_err| AbortReason::InternalError("Error getting change script"))?
6041+
};
6042+
6043+
let mut change_output =
6044+
TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
6045+
let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
6046+
let change_output_fee =
6047+
fee_for_weight(self.funding_feerate_sat_per_1000_weight, change_output_weight);
6048+
let change_value_decreased_with_fee = change_value.saturating_sub(change_output_fee);
6049+
6050+
// Check dust limit again
6051+
if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
6052+
change_output.value = Amount::from_sat(change_value_decreased_with_fee);
6053+
funding_outputs.push(change_output);
60516054
}
60526055
}
60536056

@@ -6059,7 +6062,7 @@ impl FundingNegotiationContext {
60596062
feerate_sat_per_kw: self.funding_feerate_sat_per_1000_weight,
60606063
is_initiator: self.is_initiator,
60616064
funding_tx_locktime: self.funding_tx_locktime,
6062-
inputs_to_contribute: self.our_funding_inputs,
6065+
inputs_to_contribute,
60636066
shared_funding_input: self.shared_funding_input,
60646067
shared_funding_output: SharedOwnedOutput::new(
60656068
shared_funding_output,
@@ -6071,6 +6074,30 @@ impl FundingNegotiationContext {
60716074
}
60726075
}
60736076

6077+
/// The components of a funding transaction that are contributed by one party.
6078+
pub enum FundingTxContributions {
6079+
/// When only inputs -- except for a possible change output -- are contributed to the funding
6080+
/// transaction. This must correspond to a positive contribution amount.
6081+
InputsOnly {
6082+
/// The inputs used to meet the contributed amount. Any excess amount will be sent to a
6083+
/// change output.
6084+
inputs: Vec<(TxIn, TransactionU16LenLimited)>,
6085+
6086+
/// An optional change output script. This will be used if needed or, if not set, generated
6087+
/// using `SignerProvider::get_destination_script`.
6088+
change_script: Option<ScriptBuf>,
6089+
},
6090+
}
6091+
6092+
impl FundingTxContributions {
6093+
/// Returns an inputs to be contributed to the funding transaction.
6094+
pub fn inputs(&self) -> &[(TxIn, TransactionU16LenLimited)] {
6095+
match self {
6096+
FundingTxContributions::InputsOnly { inputs, .. } => &inputs[..],
6097+
}
6098+
}
6099+
}
6100+
60746101
// Holder designates channel data owned for the benefit of the user client.
60756102
// Counterparty designates channel data owned by the another channel participant entity.
60766103
pub(super) struct FundedChannel<SP: Deref>
@@ -10684,15 +10711,17 @@ where
1068410711
funding_inputs.push((tx_in, tx16));
1068510712
}
1068610713

10714+
let funding_tx_contributions =
10715+
FundingTxContributions::InputsOnly { inputs: funding_inputs, change_script };
10716+
1068710717
let prev_funding_input = self.funding.to_splice_funding_input();
1068810718
let funding_negotiation_context = FundingNegotiationContext {
1068910719
is_initiator: true,
1069010720
our_funding_contribution,
1069110721
funding_tx_locktime: LockTime::from_consensus(locktime),
1069210722
funding_feerate_sat_per_1000_weight: funding_feerate_per_kw,
1069310723
shared_funding_input: Some(prev_funding_input),
10694-
our_funding_inputs: funding_inputs,
10695-
change_script,
10724+
funding_tx_contributions,
1069610725
};
1069710726

1069810727
self.pending_splice = Some(PendingSplice {
@@ -10806,15 +10835,17 @@ where
1080610835
self.funding.get_value_satoshis(),
1080710836
);
1080810837

10838+
let funding_tx_contributions =
10839+
FundingTxContributions::InputsOnly { inputs: vec![], change_script: None };
10840+
1080910841
let prev_funding_input = self.funding.to_splice_funding_input();
1081010842
let funding_negotiation_context = FundingNegotiationContext {
1081110843
is_initiator: false,
1081210844
our_funding_contribution,
1081310845
funding_tx_locktime: LockTime::from_consensus(msg.locktime),
1081410846
funding_feerate_sat_per_1000_weight: msg.funding_feerate_per_kw,
1081510847
shared_funding_input: Some(prev_funding_input),
10816-
our_funding_inputs: Vec::new(),
10817-
change_script: None,
10848+
funding_tx_contributions,
1081810849
};
1081910850

1082010851
let mut interactive_tx_constructor = funding_negotiation_context
@@ -12505,14 +12536,17 @@ where
1250512536
unfunded_channel_age_ticks: 0,
1250612537
holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
1250712538
};
12539+
let funding_tx_contributions = FundingTxContributions::InputsOnly {
12540+
inputs: funding_inputs,
12541+
change_script: None,
12542+
};
1250812543
let funding_negotiation_context = FundingNegotiationContext {
1250912544
is_initiator: true,
1251012545
our_funding_contribution: SignedAmount::from_sat(funding_satoshis as i64),
1251112546
funding_tx_locktime,
1251212547
funding_feerate_sat_per_1000_weight,
1251312548
shared_funding_input: None,
12514-
our_funding_inputs: funding_inputs,
12515-
change_script: None,
12549+
funding_tx_contributions,
1251612550
};
1251712551
let chan = Self {
1251812552
funding,
@@ -12659,14 +12693,17 @@ where
1265912693
&funding.get_counterparty_pubkeys().revocation_basepoint);
1266012694
context.channel_id = channel_id;
1266112695

12696+
let funding_tx_contributions = FundingTxContributions::InputsOnly {
12697+
inputs: our_funding_inputs.clone(),
12698+
change_script: None,
12699+
};
1266212700
let funding_negotiation_context = FundingNegotiationContext {
1266312701
is_initiator: false,
1266412702
our_funding_contribution,
1266512703
funding_tx_locktime: LockTime::from_consensus(msg.locktime),
1266612704
funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
1266712705
shared_funding_input: None,
12668-
our_funding_inputs: our_funding_inputs.clone(),
12669-
change_script: None,
12706+
funding_tx_contributions,
1267012707
};
1267112708
let shared_funding_output = TxOut {
1267212709
value: Amount::from_sat(funding.get_value_satoshis()),

lightning/src/ln/interactivetxs.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,7 +1891,7 @@ pub(super) fn calculate_change_output_value(
18911891

18921892
let mut total_input_satoshis = 0u64;
18931893
let mut our_funding_inputs_weight = 0u64;
1894-
for (txin, tx) in context.our_funding_inputs.iter() {
1894+
for (txin, tx) in context.funding_tx_contributions.inputs().iter() {
18951895
let txid = tx.as_transaction().compute_txid();
18961896
if txin.previous_output.txid != txid {
18971897
return Err(AbortReason::PrevTxOutInvalid);
@@ -1944,7 +1944,9 @@ pub(super) fn calculate_change_output_value(
19441944
#[cfg(test)]
19451945
mod tests {
19461946
use crate::chain::chaininterface::{fee_for_weight, FEERATE_FLOOR_SATS_PER_KW};
1947-
use crate::ln::channel::{FundingNegotiationContext, TOTAL_BITCOIN_SUPPLY_SATOSHIS};
1947+
use crate::ln::channel::{
1948+
FundingNegotiationContext, FundingTxContributions, TOTAL_BITCOIN_SUPPLY_SATOSHIS,
1949+
};
19481950
use crate::ln::interactivetxs::{
19491951
calculate_change_output_value, generate_holder_serial_id, AbortReason,
19501952
HandleTxCompleteValue, InteractiveTxConstructor, InteractiveTxConstructorArgs,
@@ -2980,6 +2982,8 @@ mod tests {
29802982
(txin, TransactionU16LenLimited::new(tx).unwrap())
29812983
})
29822984
.collect::<Vec<(TxIn, TransactionU16LenLimited)>>();
2985+
let funding_tx_contributions =
2986+
FundingTxContributions::InputsOnly { inputs, change_script: None };
29832987
let our_contributed = 110_000;
29842988
let txout = TxOut { value: Amount::from_sat(10_000), script_pubkey: ScriptBuf::new() };
29852989
let outputs = vec![txout];
@@ -2998,8 +3002,7 @@ mod tests {
29983002
funding_tx_locktime: AbsoluteLockTime::ZERO,
29993003
funding_feerate_sat_per_1000_weight,
30003004
shared_funding_input: None,
3001-
our_funding_inputs: inputs,
3002-
change_script: None,
3005+
funding_tx_contributions,
30033006
};
30043007
assert_eq!(
30053008
calculate_change_output_value(&context, false, &ScriptBuf::new(), &outputs, 300),

0 commit comments

Comments
 (0)