@@ -13,7 +13,7 @@ use bitcoin::consensus::encode;
13
13
use bitcoin::constants::ChainHash;
14
14
use bitcoin::script::{Builder, Script, ScriptBuf, WScriptHash};
15
15
use bitcoin::sighash::EcdsaSighashType;
16
- use bitcoin::transaction::{Transaction, TxIn, TxOut};
16
+ use bitcoin::transaction::{Transaction, TxOut};
17
17
use bitcoin::{Weight, Witness};
18
18
19
19
use bitcoin::hash_types::{BlockHash, Txid};
@@ -26,7 +26,7 @@ use bitcoin::secp256k1::{ecdsa::Signature, Secp256k1};
26
26
use bitcoin::secp256k1::{PublicKey, SecretKey};
27
27
#[cfg(splicing)]
28
28
use bitcoin::Sequence;
29
- use bitcoin::{secp256k1, sighash};
29
+ use bitcoin::{secp256k1, sighash, TxIn };
30
30
31
31
use crate::chain::chaininterface::{
32
32
fee_for_weight, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator,
@@ -53,7 +53,7 @@ use crate::ln::channel_state::{
53
53
OutboundHTLCDetails, OutboundHTLCStateDetails,
54
54
};
55
55
use crate::ln::channelmanager::{
56
- self, FundingConfirmedMessage, HTLCFailureMsg, HTLCSource, OpenChannelMessage,
56
+ self, FundingConfirmedMessage, FundingTxInput, HTLCFailureMsg, HTLCSource, OpenChannelMessage,
57
57
PaymentClaimDetails, PendingHTLCInfo, PendingHTLCStatus, RAACommitmentOrder, SentHTLCId,
58
58
BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA,
59
59
};
@@ -5915,10 +5915,12 @@ fn estimate_v2_funding_transaction_fee(
5915
5915
#[cfg(splicing)]
5916
5916
#[rustfmt::skip]
5917
5917
fn 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,
5919
5919
is_splice: bool, funding_feerate_sat_per_1000_weight: u32,
5920
5920
) -> 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
+ );
5922
5924
let mut funding_inputs_len = funding_inputs.len();
5923
5925
if is_initiator && is_splice {
5924
5926
// 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(
5928
5930
let estimated_fee = estimate_v2_funding_transaction_fee(is_initiator, funding_inputs_len, total_input_witness_weight, funding_feerate_sat_per_1000_weight);
5929
5931
5930
5932
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());
5940
5935
}
5941
5936
5942
5937
// If the inputs are enough to cover intended contribution amount, with fees even when
@@ -5978,7 +5973,7 @@ pub(super) struct FundingNegotiationContext {
5978
5973
pub shared_funding_input: Option<SharedOwnedInput>,
5979
5974
/// The funding inputs we will be contributing to the channel.
5980
5975
#[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 >,
5982
5977
/// The change output script. This will be used if needed or -- if not set -- generated using
5983
5978
/// `SignerProvider::get_destination_script`.
5984
5979
#[allow(dead_code)] // TODO(splicing): Remove once splicing is enabled.
@@ -6050,8 +6045,13 @@ impl FundingNegotiationContext {
6050
6045
}
6051
6046
}
6052
6047
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();
6055
6055
6056
6056
let constructor_args = InteractiveTxConstructorArgs {
6057
6057
entropy_source,
@@ -10604,9 +10604,8 @@ where
10604
10604
/// generated by `SignerProvider::get_destination_script`.
10605
10605
#[cfg(splicing)]
10606
10606
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,
10610
10609
) -> Result<msgs::SpliceInit, APIError> {
10611
10610
// Check if a splice has been initiated already.
10612
10611
// Note: only a single outstanding splice is supported (per spec)
@@ -10672,7 +10671,7 @@ where
10672
10671
),
10673
10672
})?;
10674
10673
10675
- for (txin, tx, _) in our_funding_inputs.iter() {
10674
+ for FundingTxInput { utxo, prevtx, .. } in our_funding_inputs.iter() {
10676
10675
const MESSAGE_TEMPLATE: msgs::TxAddInput = msgs::TxAddInput {
10677
10676
channel_id: ChannelId([0; 32]),
10678
10677
serial_id: 0,
@@ -10681,12 +10680,12 @@ where
10681
10680
sequence: 0,
10682
10681
shared_input_txid: None,
10683
10682
};
10684
- let message_len = MESSAGE_TEMPLATE.serialized_length() + tx .serialized_length();
10683
+ let message_len = MESSAGE_TEMPLATE.serialized_length() + prevtx .serialized_length();
10685
10684
if message_len > LN_MAX_MSG_LEN {
10686
10685
return Err(APIError::APIMisuseError {
10687
10686
err: format!(
10688
10687
"Funding input references a prevtx that is too large for tx_add_input: {}",
10689
- txin.previous_output ,
10688
+ utxo.outpoint ,
10690
10689
),
10691
10690
});
10692
10691
}
@@ -12468,7 +12467,7 @@ where
12468
12467
pub fn new_outbound<ES: Deref, F: Deref, L: Deref>(
12469
12468
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
12470
12469
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,
12472
12471
current_chain_height: u32, outbound_scid_alias: u64, funding_confirmation_target: ConfirmationTarget,
12473
12472
logger: L,
12474
12473
) -> Result<Self, APIError>
@@ -12682,8 +12681,12 @@ where
12682
12681
value: Amount::from_sat(funding.get_value_satoshis()),
12683
12682
script_pubkey: funding.get_funding_redeemscript().to_p2wsh(),
12684
12683
};
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();
12687
12690
12688
12691
let interactive_tx_constructor = Some(InteractiveTxConstructor::new(
12689
12692
InteractiveTxConstructorArgs {
@@ -14119,6 +14122,8 @@ mod tests {
14119
14122
TOTAL_BITCOIN_SUPPLY_SATOSHIS,
14120
14123
};
14121
14124
use crate::ln::channel_keys::{RevocationBasepoint, RevocationKey};
14125
+ #[cfg(splicing)]
14126
+ use crate::ln::channelmanager::FundingTxInput;
14122
14127
use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
14123
14128
use crate::ln::msgs;
14124
14129
use crate::ln::msgs::{ChannelUpdate, UnsignedChannelUpdate, MAX_VALUE_MSAT};
@@ -14151,11 +14156,9 @@ mod tests {
14151
14156
use bitcoin::secp256k1::ffi::Signature as FFISignature;
14152
14157
use bitcoin::secp256k1::{ecdsa::Signature, Secp256k1};
14153
14158
use bitcoin::secp256k1::{PublicKey, SecretKey};
14154
- #[cfg(splicing)]
14155
- use bitcoin::transaction::TxIn;
14156
14159
use bitcoin::transaction::{Transaction, TxOut, Version};
14157
14160
#[cfg(splicing)]
14158
- use bitcoin::Weight ;
14161
+ use bitcoin::{ScriptBuf, Sequence, WPubkeyHash} ;
14159
14162
use bitcoin::{WitnessProgram, WitnessVersion};
14160
14163
use std::cmp;
14161
14164
@@ -15897,19 +15900,17 @@ mod tests {
15897
15900
15898
15901
#[cfg(splicing)]
15899
15902
#[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()),
15907
15907
};
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,
15911
15911
};
15912
- (input_1_txin, input_1_prev_tx, Weight::from_wu(P2WPKH_WITNESS_WEIGHT))
15912
+
15913
+ FundingTxInput::new_p2wpkh(prevtx, 0, Sequence::ZERO).unwrap()
15913
15914
}
15914
15915
15915
15916
#[cfg(splicing)]
@@ -15930,7 +15931,7 @@ mod tests {
15930
15931
true,
15931
15932
2000,
15932
15933
).unwrap(),
15933
- 2268 ,
15934
+ 2284 ,
15934
15935
);
15935
15936
15936
15937
// negative case, inputs clearly insufficient
@@ -15946,13 +15947,13 @@ mod tests {
15946
15947
);
15947
15948
assert_eq!(
15948
15949
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.",
15950
15951
);
15951
15952
}
15952
15953
15953
15954
// barely covers
15954
15955
{
15955
- let expected_fee: u64 = 2268 ;
15956
+ let expected_fee: u64 = 2284 ;
15956
15957
assert_eq!(
15957
15958
check_v2_funding_inputs_sufficient(
15958
15959
(300_000 - expected_fee - 20) as i64,
@@ -15982,13 +15983,13 @@ mod tests {
15982
15983
);
15983
15984
assert_eq!(
15984
15985
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.",
15986
15987
);
15987
15988
}
15988
15989
15989
15990
// barely covers, less fees (no extra weight, no init)
15990
15991
{
15991
- let expected_fee: u64 = 1076 ;
15992
+ let expected_fee: u64 = 1092 ;
15992
15993
assert_eq!(
15993
15994
check_v2_funding_inputs_sufficient(
15994
15995
(300_000 - expected_fee - 20) as i64,
0 commit comments