@@ -13,7 +13,7 @@ use bitcoin::consensus::encode;
1313use bitcoin::constants::ChainHash;
1414use bitcoin::script::{Builder, Script, ScriptBuf, WScriptHash};
1515use bitcoin::sighash::EcdsaSighashType;
16- use bitcoin::transaction::{Transaction, TxIn, TxOut};
16+ use bitcoin::transaction::{Transaction, TxOut};
1717use bitcoin::{Weight, Witness};
1818
1919use bitcoin::hash_types::{BlockHash, Txid};
@@ -26,7 +26,7 @@ use bitcoin::secp256k1::{ecdsa::Signature, Secp256k1};
2626use bitcoin::secp256k1::{PublicKey, SecretKey};
2727#[cfg(splicing)]
2828use bitcoin::Sequence;
29- use bitcoin::{secp256k1, sighash};
29+ use bitcoin::{secp256k1, sighash, TxIn };
3030
3131use crate::chain::chaininterface::{
3232 fee_for_weight, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator,
@@ -53,7 +53,7 @@ use crate::ln::channel_state::{
5353 OutboundHTLCDetails, OutboundHTLCStateDetails,
5454};
5555use crate::ln::channelmanager::{
56- self, FundingConfirmedMessage, HTLCFailureMsg, HTLCSource, OpenChannelMessage,
56+ self, FundingConfirmedMessage, FundingTxInput, HTLCFailureMsg, HTLCSource, OpenChannelMessage,
5757 PaymentClaimDetails, PendingHTLCInfo, PendingHTLCStatus, RAACommitmentOrder, SentHTLCId,
5858 BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA,
5959};
@@ -5915,10 +5915,12 @@ fn estimate_v2_funding_transaction_fee(
59155915#[cfg(splicing)]
59165916#[rustfmt::skip]
59175917fn check_v2_funding_inputs_sufficient(
5918- contribution_amount: i64, funding_inputs: &[(TxIn, Transaction, Weight) ], is_initiator: bool,
5918+ contribution_amount: i64, funding_inputs: &[FundingTxInput ], is_initiator: bool,
59195919 is_splice: bool, funding_feerate_sat_per_1000_weight: u32,
59205920) -> Result<u64, ChannelError> {
5921- let mut total_input_witness_weight = Weight::from_wu(funding_inputs.iter().map(|(_, _, w)| w.to_wu()).sum());
5921+ let mut total_input_witness_weight = Weight::from_wu(
5922+ funding_inputs.iter().map(|input| input.utxo.satisfaction_weight).sum(),
5923+ );
59225924 let mut funding_inputs_len = funding_inputs.len();
59235925 if is_initiator && is_splice {
59245926 // consider the weight of the input and witness needed for spending the old funding transaction
@@ -5928,15 +5930,8 @@ fn check_v2_funding_inputs_sufficient(
59285930 let estimated_fee = estimate_v2_funding_transaction_fee(is_initiator, funding_inputs_len, total_input_witness_weight, funding_feerate_sat_per_1000_weight);
59295931
59305932 let mut total_input_sats = 0u64;
5931- for (idx, input) in funding_inputs.iter().enumerate() {
5932- if let Some(output) = input.1.output.get(input.0.previous_output.vout as usize) {
5933- total_input_sats = total_input_sats.saturating_add(output.value.to_sat());
5934- } else {
5935- return Err(ChannelError::Warn(format!(
5936- "Transaction with txid {} does not have an output with vout of {} corresponding to TxIn at funding_inputs[{}]",
5937- input.1.compute_txid(), input.0.previous_output.vout, idx
5938- )));
5939- }
5933+ for FundingTxInput { utxo, .. } in funding_inputs.iter() {
5934+ total_input_sats = total_input_sats.saturating_add(utxo.output.value.to_sat());
59405935 }
59415936
59425937 // If the inputs are enough to cover intended contribution amount, with fees even when
@@ -5978,7 +5973,7 @@ pub(super) struct FundingNegotiationContext {
59785973 pub shared_funding_input: Option<SharedOwnedInput>,
59795974 /// The funding inputs we will be contributing to the channel.
59805975 #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
5981- pub our_funding_inputs: Vec<(TxIn, Transaction, Weight) >,
5976+ pub our_funding_inputs: Vec<FundingTxInput >,
59825977 /// The change output script. This will be used if needed or -- if not set -- generated using
59835978 /// `SignerProvider::get_destination_script`.
59845979 #[allow(dead_code)] // TODO(splicing): Remove once splicing is enabled.
@@ -6050,8 +6045,13 @@ impl FundingNegotiationContext {
60506045 }
60516046 }
60526047
6053- let funding_inputs =
6054- self.our_funding_inputs.into_iter().map(|(txin, tx, _)| (txin, tx)).collect();
6048+ let funding_inputs = self
6049+ .our_funding_inputs
6050+ .into_iter()
6051+ .map(|FundingTxInput { utxo, sequence, prevtx }| {
6052+ (TxIn { previous_output: utxo.outpoint, sequence, ..Default::default() }, prevtx)
6053+ })
6054+ .collect();
60556055
60566056 let constructor_args = InteractiveTxConstructorArgs {
60576057 entropy_source,
@@ -10604,9 +10604,8 @@ where
1060410604 /// generated by `SignerProvider::get_destination_script`.
1060510605 #[cfg(splicing)]
1060610606 pub fn splice_channel(
10607- &mut self, our_funding_contribution_satoshis: i64,
10608- our_funding_inputs: Vec<(TxIn, Transaction, Weight)>, change_script: Option<ScriptBuf>,
10609- funding_feerate_per_kw: u32, locktime: u32,
10607+ &mut self, our_funding_contribution_satoshis: i64, our_funding_inputs: Vec<FundingTxInput>,
10608+ change_script: Option<ScriptBuf>, funding_feerate_per_kw: u32, locktime: u32,
1061010609 ) -> Result<msgs::SpliceInit, APIError> {
1061110610 // Check if a splice has been initiated already.
1061210611 // Note: only a single outstanding splice is supported (per spec)
@@ -10672,7 +10671,7 @@ where
1067210671 ),
1067310672 })?;
1067410673
10675- for (txin, tx, _) in our_funding_inputs.iter() {
10674+ for FundingTxInput { utxo, prevtx, .. } in our_funding_inputs.iter() {
1067610675 const MESSAGE_TEMPLATE: msgs::TxAddInput = msgs::TxAddInput {
1067710676 channel_id: ChannelId([0; 32]),
1067810677 serial_id: 0,
@@ -10681,12 +10680,12 @@ where
1068110680 sequence: 0,
1068210681 shared_input_txid: None,
1068310682 };
10684- let message_len = MESSAGE_TEMPLATE.serialized_length() + tx .serialized_length();
10683+ let message_len = MESSAGE_TEMPLATE.serialized_length() + prevtx .serialized_length();
1068510684 if message_len > LN_MAX_MSG_LEN {
1068610685 return Err(APIError::APIMisuseError {
1068710686 err: format!(
1068810687 "Funding input references a prevtx that is too large for tx_add_input: {}",
10689- txin.previous_output ,
10688+ utxo.outpoint ,
1069010689 ),
1069110690 });
1069210691 }
@@ -12468,7 +12467,7 @@ where
1246812467 pub fn new_outbound<ES: Deref, F: Deref, L: Deref>(
1246912468 fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
1247012469 counterparty_node_id: PublicKey, their_features: &InitFeatures, funding_satoshis: u64,
12471- funding_inputs: Vec<(TxIn, Transaction, Weight) >, user_id: u128, config: &UserConfig,
12470+ funding_inputs: Vec<FundingTxInput >, user_id: u128, config: &UserConfig,
1247212471 current_chain_height: u32, outbound_scid_alias: u64, funding_confirmation_target: ConfirmationTarget,
1247312472 logger: L,
1247412473 ) -> Result<Self, APIError>
@@ -12682,8 +12681,12 @@ where
1268212681 value: Amount::from_sat(funding.get_value_satoshis()),
1268312682 script_pubkey: funding.get_funding_redeemscript().to_p2wsh(),
1268412683 };
12685- let inputs_to_contribute =
12686- our_funding_inputs.into_iter().map(|(txin, tx, _)| (txin, tx)).collect();
12684+ let inputs_to_contribute = our_funding_inputs
12685+ .into_iter()
12686+ .map(|FundingTxInput { utxo, sequence, prevtx }| {
12687+ (TxIn { previous_output: utxo.outpoint, sequence, ..Default::default() }, prevtx)
12688+ })
12689+ .collect();
1268712690
1268812691 let interactive_tx_constructor = Some(InteractiveTxConstructor::new(
1268912692 InteractiveTxConstructorArgs {
@@ -14119,6 +14122,8 @@ mod tests {
1411914122 TOTAL_BITCOIN_SUPPLY_SATOSHIS,
1412014123 };
1412114124 use crate::ln::channel_keys::{RevocationBasepoint, RevocationKey};
14125+ #[cfg(splicing)]
14126+ use crate::ln::channelmanager::FundingTxInput;
1412214127 use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
1412314128 use crate::ln::msgs;
1412414129 use crate::ln::msgs::{ChannelUpdate, UnsignedChannelUpdate, MAX_VALUE_MSAT};
@@ -14151,11 +14156,9 @@ mod tests {
1415114156 use bitcoin::secp256k1::ffi::Signature as FFISignature;
1415214157 use bitcoin::secp256k1::{ecdsa::Signature, Secp256k1};
1415314158 use bitcoin::secp256k1::{PublicKey, SecretKey};
14154- #[cfg(splicing)]
14155- use bitcoin::transaction::TxIn;
1415614159 use bitcoin::transaction::{Transaction, TxOut, Version};
1415714160 #[cfg(splicing)]
14158- use bitcoin::Weight ;
14161+ use bitcoin::{ScriptBuf, Sequence, WPubkeyHash} ;
1415914162 use bitcoin::{WitnessProgram, WitnessVersion};
1416014163 use std::cmp;
1416114164
@@ -15897,19 +15900,17 @@ mod tests {
1589715900
1589815901 #[cfg(splicing)]
1589915902 #[rustfmt::skip]
15900- fn funding_input_sats(input_value_sats: u64) -> (TxIn, Transaction, Weight) {
15901- use crate::sign::P2WPKH_WITNESS_WEIGHT;
15902-
15903- let input_1_prev_out = TxOut { value: Amount::from_sat(input_value_sats), script_pubkey: bitcoin::ScriptBuf::default() };
15904- let input_1_prev_tx = Transaction {
15905- input: vec![], output: vec![input_1_prev_out],
15906- version: Version::TWO, lock_time: bitcoin::absolute::LockTime::ZERO,
15903+ fn funding_input_sats(input_value_sats: u64) -> FundingTxInput {
15904+ let prevout = TxOut {
15905+ value: Amount::from_sat(input_value_sats),
15906+ script_pubkey: ScriptBuf::new_p2wpkh(&WPubkeyHash::all_zeros()),
1590715907 };
15908- let input_1_txin = TxIn {
15909- previous_output: bitcoin::OutPoint { txid: input_1_prev_tx.compute_txid(), vout: 0 } ,
15910- ..Default::default()
15908+ let prevtx = Transaction {
15909+ input: vec![], output: vec![prevout] ,
15910+ version: Version::TWO, lock_time: bitcoin::absolute::LockTime::ZERO,
1591115911 };
15912- (input_1_txin, input_1_prev_tx, Weight::from_wu(P2WPKH_WITNESS_WEIGHT))
15912+
15913+ FundingTxInput::new_p2wpkh(prevtx, 0, Sequence::ZERO).unwrap()
1591315914 }
1591415915
1591515916 #[cfg(splicing)]
@@ -15930,7 +15931,7 @@ mod tests {
1593015931 true,
1593115932 2000,
1593215933 ).unwrap(),
15933- 2268 ,
15934+ 2284 ,
1593415935 );
1593515936
1593615937 // negative case, inputs clearly insufficient
@@ -15946,13 +15947,13 @@ mod tests {
1594615947 );
1594715948 assert_eq!(
1594815949 format!("{:?}", res.err().unwrap()),
15949- "Warn: Total input amount 100000 is lower than needed for contribution 220000, considering fees of 1730 . Need more inputs.",
15950+ "Warn: Total input amount 100000 is lower than needed for contribution 220000, considering fees of 1738 . Need more inputs.",
1595015951 );
1595115952 }
1595215953
1595315954 // barely covers
1595415955 {
15955- let expected_fee: u64 = 2268 ;
15956+ let expected_fee: u64 = 2284 ;
1595615957 assert_eq!(
1595715958 check_v2_funding_inputs_sufficient(
1595815959 (300_000 - expected_fee - 20) as i64,
@@ -15982,13 +15983,13 @@ mod tests {
1598215983 );
1598315984 assert_eq!(
1598415985 format!("{:?}", res.err().unwrap()),
15985- "Warn: Total input amount 300000 is lower than needed for contribution 298032, considering fees of 2495 . Need more inputs.",
15986+ "Warn: Total input amount 300000 is lower than needed for contribution 298032, considering fees of 2513 . Need more inputs.",
1598615987 );
1598715988 }
1598815989
1598915990 // barely covers, less fees (no extra weight, no init)
1599015991 {
15991- let expected_fee: u64 = 1076 ;
15992+ let expected_fee: u64 = 1092 ;
1599215993 assert_eq!(
1599315994 check_v2_funding_inputs_sufficient(
1599415995 (300_000 - expected_fee - 20) as i64,
0 commit comments