@@ -2254,21 +2254,10 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
22542254 funding_inputs.push(prev_funding_input);
22552255 }
22562256
2257- let mut funding_inputs_prev_outputs: Vec<&TxOut> = Vec::with_capacity(funding_inputs.len());
2258- // Check that vouts exist for each TxIn in provided transactions.
2259- for (idx, (txin, tx)) in funding_inputs.iter().enumerate() {
2260- if let Some(output) = tx.as_transaction().output.get(txin.previous_output.vout as usize) {
2261- funding_inputs_prev_outputs.push(output);
2262- } else {
2263- return Err(APIError::APIMisuseError {
2264- err: format!("Transaction with txid {} does not have an output with vout of {} corresponding to TxIn at funding_inputs[{}]",
2265- tx.as_transaction().compute_txid(), txin.previous_output.vout, idx) });
2266- }
2267- }
2257+ let funding_inputs_prev_outputs = DualFundingChannelContext::txouts_from_input_prev_txs(&funding_inputs)
2258+ .map_err(|err| APIError::APIMisuseError { err: err.to_string() })?;
22682259
2269- let total_input_satoshis: u64 = funding_inputs.iter().map(
2270- |(txin, tx)| tx.as_transaction().output.get(txin.previous_output.vout as usize).map(|out| out.value.to_sat()).unwrap_or(0)
2271- ).sum();
2260+ let total_input_satoshis: u64 = funding_inputs_prev_outputs.iter().map(|txout| txout.value.to_sat()).sum();
22722261 if total_input_satoshis < self.dual_funding_context.our_funding_satoshis {
22732262 return Err(APIError::APIMisuseError {
22742263 err: format!("Total value of funding inputs must be at least funding amount. It was {} sats",
@@ -4914,6 +4903,33 @@ pub(super) struct DualFundingChannelContext {
49144903 pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
49154904}
49164905
4906+ impl DualFundingChannelContext {
4907+ /// Obtain prev outputs for each supplied input and matching transaction.
4908+ /// Can error when there a prev tx does not have an output for the specified vout number.
4909+ /// Also checks for matching of transaction IDs.
4910+ fn txouts_from_input_prev_txs(inputs: &Vec<(TxIn, TransactionU16LenLimited)>) -> Result<Vec<&TxOut>, ChannelError> {
4911+ let mut prev_outputs: Vec<&TxOut> = Vec::with_capacity(inputs.len());
4912+ // Check that vouts exist for each TxIn in provided transactions.
4913+ for (idx, (txin, tx)) in inputs.iter().enumerate() {
4914+ let txid = tx.as_transaction().compute_txid();
4915+ if txin.previous_output.txid != txid {
4916+ return Err(ChannelError::Warn(
4917+ format!("Transaction input txid mismatch, {} vs. {}, at index {}", txin.previous_output.txid, txid, idx)
4918+ ));
4919+ }
4920+ if let Some(output) = tx.as_transaction().output.get(txin.previous_output.vout as usize) {
4921+ prev_outputs.push(output);
4922+ } else {
4923+ return Err(ChannelError::Warn(
4924+ format!("Transaction with txid {} does not have an output with vout of {} corresponding to TxIn, at index {}",
4925+ txid, txin.previous_output.vout, idx)
4926+ ));
4927+ }
4928+ }
4929+ Ok(prev_outputs)
4930+ }
4931+ }
4932+
49174933// Holder designates channel data owned for the benefit of the user client.
49184934// Counterparty designates channel data owned by the another channel participant entity.
49194935pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
@@ -9991,17 +10007,18 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
999110007 unfunded_channel_age_ticks: 0,
999210008 holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
999310009 };
10010+ let dual_funding_context = DualFundingChannelContext {
10011+ our_funding_satoshis: funding_satoshis,
10012+ their_funding_satoshis: None,
10013+ funding_tx_locktime,
10014+ funding_feerate_sat_per_1000_weight,
10015+ our_funding_inputs: funding_inputs,
10016+ };
999410017 let chan = Self {
999510018 funding,
999610019 context,
999710020 unfunded_context,
9998- dual_funding_context: DualFundingChannelContext {
9999- our_funding_satoshis: funding_satoshis,
10000- their_funding_satoshis: None,
10001- funding_tx_locktime,
10002- funding_feerate_sat_per_1000_weight,
10003- our_funding_inputs: funding_inputs,
10004- },
10021+ dual_funding_context,
1000510022 interactive_tx_constructor: None,
1000610023 interactive_tx_signing_session: None,
1000710024 };
0 commit comments