@@ -2251,21 +2251,10 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
22512251 funding_inputs.push(prev_funding_input);
22522252 }
22532253
2254- let mut funding_inputs_prev_outputs: Vec<&TxOut> = Vec::with_capacity(funding_inputs.len());
2255- // Check that vouts exist for each TxIn in provided transactions.
2256- for (idx, (txin, tx)) in funding_inputs.iter().enumerate() {
2257- if let Some(output) = tx.as_transaction().output.get(txin.previous_output.vout as usize) {
2258- funding_inputs_prev_outputs.push(output);
2259- } else {
2260- return Err(APIError::APIMisuseError {
2261- err: format!("Transaction with txid {} does not have an output with vout of {} corresponding to TxIn at funding_inputs[{}]",
2262- tx.as_transaction().compute_txid(), txin.previous_output.vout, idx) });
2263- }
2264- }
2254+ let funding_inputs_prev_outputs = DualFundingChannelContext::txouts_from_input_prev_txs(&funding_inputs)
2255+ .map_err(|err| APIError::APIMisuseError { err: err.to_string() })?;
22652256
2266- let total_input_satoshis: u64 = funding_inputs.iter().map(
2267- |(txin, tx)| tx.as_transaction().output.get(txin.previous_output.vout as usize).map(|out| out.value.to_sat()).unwrap_or(0)
2268- ).sum();
2257+ let total_input_satoshis: u64 = funding_inputs_prev_outputs.iter().map(|txout| txout.value.to_sat()).sum();
22692258 if total_input_satoshis < self.dual_funding_context.our_funding_satoshis {
22702259 return Err(APIError::APIMisuseError {
22712260 err: format!("Total value of funding inputs must be at least funding amount. It was {} sats",
@@ -5013,6 +5002,33 @@ pub(super) struct DualFundingChannelContext {
50135002 pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
50145003}
50155004
5005+ impl DualFundingChannelContext {
5006+ /// Obtain prev outputs for each supplied input and matching transaction.
5007+ /// Can error when there a prev tx does not have an output for the specified vout number.
5008+ /// Also checks for matching of transaction IDs.
5009+ fn txouts_from_input_prev_txs(inputs: &Vec<(TxIn, TransactionU16LenLimited)>) -> Result<Vec<&TxOut>, ChannelError> {
5010+ let mut prev_outputs: Vec<&TxOut> = Vec::with_capacity(inputs.len());
5011+ // Check that vouts exist for each TxIn in provided transactions.
5012+ for (idx, (txin, tx)) in inputs.iter().enumerate() {
5013+ let txid = tx.as_transaction().compute_txid();
5014+ if txin.previous_output.txid != txid {
5015+ return Err(ChannelError::Warn(
5016+ format!("Transaction input txid mismatch, {} vs. {}, at index {}", txin.previous_output.txid, txid, idx)
5017+ ));
5018+ }
5019+ if let Some(output) = tx.as_transaction().output.get(txin.previous_output.vout as usize) {
5020+ prev_outputs.push(output);
5021+ } else {
5022+ return Err(ChannelError::Warn(
5023+ format!("Transaction with txid {} does not have an output with vout of {} corresponding to TxIn, at index {}",
5024+ txid, txin.previous_output.vout, idx)
5025+ ));
5026+ }
5027+ }
5028+ Ok(prev_outputs)
5029+ }
5030+ }
5031+
50165032// Holder designates channel data owned for the benefit of the user client.
50175033// Counterparty designates channel data owned by the another channel participant entity.
50185034pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
@@ -9997,17 +10013,18 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
999710013 unfunded_channel_age_ticks: 0,
999810014 holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
999910015 };
10016+ let dual_funding_context = DualFundingChannelContext {
10017+ our_funding_satoshis: funding_satoshis,
10018+ their_funding_satoshis: None,
10019+ funding_tx_locktime,
10020+ funding_feerate_sat_per_1000_weight,
10021+ our_funding_inputs: funding_inputs,
10022+ };
1000010023 let chan = Self {
1000110024 funding,
1000210025 context,
1000310026 unfunded_context,
10004- dual_funding_context: DualFundingChannelContext {
10005- our_funding_satoshis: funding_satoshis,
10006- their_funding_satoshis: None,
10007- funding_tx_locktime,
10008- funding_feerate_sat_per_1000_weight,
10009- our_funding_inputs: funding_inputs,
10010- },
10027+ dual_funding_context,
1001110028 interactive_tx_constructor: None,
1001210029 interactive_tx_signing_session: None,
1001310030 };
0 commit comments