@@ -13,8 +13,8 @@ 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};
17
- use bitcoin::{Weight, Witness} ;
16
+ use bitcoin::transaction::{Transaction, TxOut};
17
+ use bitcoin::Witness;
18
18
19
19
use bitcoin::hash_types::{BlockHash, Txid};
20
20
use bitcoin::hashes::sha256::Hash as Sha256;
@@ -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,
@@ -37,16 +37,15 @@ use crate::chain::channelmonitor::{
37
37
};
38
38
use crate::chain::transaction::{OutPoint, TransactionData};
39
39
use crate::chain::BestBlock;
40
- use crate::events::bump_transaction::BASE_INPUT_WEIGHT;
40
+ use crate::events::bump_transaction::{ BASE_INPUT_WEIGHT, EMPTY_SCRIPT_SIG_WEIGHT} ;
41
41
use crate::events::ClosureReason;
42
42
use crate::ln::chan_utils;
43
- #[cfg(splicing)]
44
- use crate::ln::chan_utils::FUNDING_TRANSACTION_WITNESS_WEIGHT;
45
43
use crate::ln::chan_utils::{
46
44
get_commitment_transaction_number_obscure_factor, max_htlcs, second_stage_tx_fees_sat,
47
45
selected_commitment_sat_per_1000_weight, ChannelPublicKeys, ChannelTransactionParameters,
48
46
ClosingTransaction, CommitmentTransaction, CounterpartyChannelTransactionParameters,
49
47
CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HolderCommitmentTransaction,
48
+ FUNDING_TRANSACTION_WITNESS_WEIGHT,
50
49
};
51
50
use crate::ln::channel_state::{
52
51
ChannelShutdownState, CounterpartyForwardingInfo, InboundHTLCDetails, InboundHTLCStateDetails,
@@ -57,6 +56,7 @@ use crate::ln::channelmanager::{
57
56
PaymentClaimDetails, PendingHTLCInfo, PendingHTLCStatus, RAACommitmentOrder, SentHTLCId,
58
57
BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA,
59
58
};
59
+ use crate::ln::funding::FundingTxInput;
60
60
#[cfg(splicing)]
61
61
use crate::ln::interactivetxs::{
62
62
calculate_change_output_value, AbortReason, InteractiveTxMessageSend,
@@ -5883,16 +5883,15 @@ fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satos
5883
5883
#[allow(dead_code)] // TODO(dual_funding): TODO(splicing): Remove allow once used.
5884
5884
#[rustfmt::skip]
5885
5885
fn estimate_v2_funding_transaction_fee(
5886
- is_initiator: bool, input_count: usize, witness_weight: Weight ,
5886
+ funding_inputs: &[FundingTxInput], is_initiator: bool, is_splice: bool ,
5887
5887
funding_feerate_sat_per_1000_weight: u32,
5888
5888
) -> u64 {
5889
- // Inputs
5890
- let mut weight = (input_count as u64) * BASE_INPUT_WEIGHT;
5891
-
5892
- // Witnesses
5893
- weight = weight.saturating_add(witness_weight.to_wu());
5889
+ let mut weight: u64 = funding_inputs
5890
+ .iter()
5891
+ .map(|input| BASE_INPUT_WEIGHT.saturating_add(input.utxo.satisfaction_weight))
5892
+ .fold(0, |total_weight, input_weight| total_weight.saturating_add(input_weight));
5894
5893
5895
- // If we are the initiator, we must pay for weight of all common fields in the funding transaction.
5894
+ // The initiator pays for all common fields and the shared output in the funding transaction.
5896
5895
if is_initiator {
5897
5896
weight = weight
5898
5897
.saturating_add(TX_COMMON_FIELDS_WEIGHT)
@@ -5901,7 +5900,15 @@ fn estimate_v2_funding_transaction_fee(
5901
5900
// to calculate the contributed weight, so we use an all-zero hash.
5902
5901
.saturating_add(get_output_weight(&ScriptBuf::new_p2wsh(
5903
5902
&WScriptHash::from_raw_hash(Hash::all_zeros())
5904
- )).to_wu())
5903
+ )).to_wu());
5904
+
5905
+ // The splice initiator pays for the input spending the previous funding output.
5906
+ if is_splice {
5907
+ weight = weight
5908
+ .saturating_add(BASE_INPUT_WEIGHT)
5909
+ .saturating_add(EMPTY_SCRIPT_SIG_WEIGHT)
5910
+ .saturating_add(FUNDING_TRANSACTION_WITNESS_WEIGHT);
5911
+ }
5905
5912
}
5906
5913
5907
5914
fee_for_weight(funding_feerate_sat_per_1000_weight, weight)
@@ -5916,28 +5923,16 @@ fn estimate_v2_funding_transaction_fee(
5916
5923
#[cfg(splicing)]
5917
5924
#[rustfmt::skip]
5918
5925
fn check_v2_funding_inputs_sufficient(
5919
- contribution_amount: i64, funding_inputs: &[(TxIn, Transaction, Weight) ], is_initiator: bool,
5926
+ contribution_amount: i64, funding_inputs: &[FundingTxInput ], is_initiator: bool,
5920
5927
is_splice: bool, funding_feerate_sat_per_1000_weight: u32,
5921
5928
) -> Result<u64, ChannelError> {
5922
- let mut total_input_witness_weight = Weight::from_wu(funding_inputs.iter().map(|(_, _, w)| w.to_wu()).sum());
5923
- let mut funding_inputs_len = funding_inputs.len();
5924
- if is_initiator && is_splice {
5925
- // consider the weight of the input and witness needed for spending the old funding transaction
5926
- funding_inputs_len += 1;
5927
- total_input_witness_weight += Weight::from_wu(FUNDING_TRANSACTION_WITNESS_WEIGHT);
5928
- }
5929
- let estimated_fee = estimate_v2_funding_transaction_fee(is_initiator, funding_inputs_len, total_input_witness_weight, funding_feerate_sat_per_1000_weight);
5929
+ let estimated_fee = estimate_v2_funding_transaction_fee(
5930
+ funding_inputs, is_initiator, is_splice, funding_feerate_sat_per_1000_weight,
5931
+ );
5930
5932
5931
5933
let mut total_input_sats = 0u64;
5932
- for (idx, input) in funding_inputs.iter().enumerate() {
5933
- if let Some(output) = input.1.output.get(input.0.previous_output.vout as usize) {
5934
- total_input_sats = total_input_sats.saturating_add(output.value.to_sat());
5935
- } else {
5936
- return Err(ChannelError::Warn(format!(
5937
- "Transaction with txid {} does not have an output with vout of {} corresponding to TxIn at funding_inputs[{}]",
5938
- input.1.compute_txid(), input.0.previous_output.vout, idx
5939
- )));
5940
- }
5934
+ for FundingTxInput { utxo, .. } in funding_inputs.iter() {
5935
+ total_input_sats = total_input_sats.saturating_add(utxo.output.value.to_sat());
5941
5936
}
5942
5937
5943
5938
// If the inputs are enough to cover intended contribution amount, with fees even when
@@ -5979,7 +5974,7 @@ pub(super) struct FundingNegotiationContext {
5979
5974
pub shared_funding_input: Option<SharedOwnedInput>,
5980
5975
/// The funding inputs we will be contributing to the channel.
5981
5976
#[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
5982
- pub our_funding_inputs: Vec<(TxIn, Transaction, Weight) >,
5977
+ pub our_funding_inputs: Vec<FundingTxInput >,
5983
5978
/// The change output script. This will be used if needed or -- if not set -- generated using
5984
5979
/// `SignerProvider::get_destination_script`.
5985
5980
#[allow(dead_code)] // TODO(splicing): Remove once splicing is enabled.
@@ -6051,8 +6046,13 @@ impl FundingNegotiationContext {
6051
6046
}
6052
6047
}
6053
6048
6054
- let funding_inputs =
6055
- self.our_funding_inputs.into_iter().map(|(txin, tx, _)| (txin, tx)).collect();
6049
+ let funding_inputs = self
6050
+ .our_funding_inputs
6051
+ .into_iter()
6052
+ .map(|FundingTxInput { utxo, sequence, prevtx }| {
6053
+ (TxIn { previous_output: utxo.outpoint, sequence, ..Default::default() }, prevtx)
6054
+ })
6055
+ .collect();
6056
6056
6057
6057
let constructor_args = InteractiveTxConstructorArgs {
6058
6058
entropy_source,
@@ -10605,9 +10605,8 @@ where
10605
10605
/// generated by `SignerProvider::get_destination_script`.
10606
10606
#[cfg(splicing)]
10607
10607
pub fn splice_channel(
10608
- &mut self, our_funding_contribution_satoshis: i64,
10609
- our_funding_inputs: Vec<(TxIn, Transaction, Weight)>, change_script: Option<ScriptBuf>,
10610
- funding_feerate_per_kw: u32, locktime: u32,
10608
+ &mut self, our_funding_contribution_satoshis: i64, our_funding_inputs: Vec<FundingTxInput>,
10609
+ change_script: Option<ScriptBuf>, funding_feerate_per_kw: u32, locktime: u32,
10611
10610
) -> Result<msgs::SpliceInit, APIError> {
10612
10611
// Check if a splice has been initiated already.
10613
10612
// Note: only a single outstanding splice is supported (per spec)
@@ -10673,21 +10672,22 @@ where
10673
10672
),
10674
10673
})?;
10675
10674
10676
- for (txin, tx, _) in our_funding_inputs.iter() {
10675
+ for FundingTxInput { utxo, prevtx, .. } in our_funding_inputs.iter() {
10677
10676
const MESSAGE_TEMPLATE: msgs::TxAddInput = msgs::TxAddInput {
10678
10677
channel_id: ChannelId([0; 32]),
10679
10678
serial_id: 0,
10680
10679
prevtx: None,
10681
10680
prevtx_out: 0,
10682
10681
sequence: 0,
10682
+ // Mutually exclusive with prevtx, which is accounted for below.
10683
10683
shared_input_txid: None,
10684
10684
};
10685
- let message_len = MESSAGE_TEMPLATE.serialized_length() + tx .serialized_length();
10685
+ let message_len = MESSAGE_TEMPLATE.serialized_length() + prevtx .serialized_length();
10686
10686
if message_len > LN_MAX_MSG_LEN {
10687
10687
return Err(APIError::APIMisuseError {
10688
10688
err: format!(
10689
10689
"Funding input references a prevtx that is too large for tx_add_input: {}",
10690
- txin.previous_output ,
10690
+ utxo.outpoint ,
10691
10691
),
10692
10692
});
10693
10693
}
@@ -12469,7 +12469,7 @@ where
12469
12469
pub fn new_outbound<ES: Deref, F: Deref, L: Deref>(
12470
12470
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
12471
12471
counterparty_node_id: PublicKey, their_features: &InitFeatures, funding_satoshis: u64,
12472
- funding_inputs: Vec<(TxIn, Transaction, Weight) >, user_id: u128, config: &UserConfig,
12472
+ funding_inputs: Vec<FundingTxInput >, user_id: u128, config: &UserConfig,
12473
12473
current_chain_height: u32, outbound_scid_alias: u64, funding_confirmation_target: ConfirmationTarget,
12474
12474
logger: L,
12475
12475
) -> Result<Self, APIError>
@@ -12683,8 +12683,12 @@ where
12683
12683
value: Amount::from_sat(funding.get_value_satoshis()),
12684
12684
script_pubkey: funding.get_funding_redeemscript().to_p2wsh(),
12685
12685
};
12686
- let inputs_to_contribute =
12687
- our_funding_inputs.into_iter().map(|(txin, tx, _)| (txin, tx)).collect();
12686
+ let inputs_to_contribute = our_funding_inputs
12687
+ .into_iter()
12688
+ .map(|FundingTxInput { utxo, sequence, prevtx }| {
12689
+ (TxIn { previous_output: utxo.outpoint, sequence, ..Default::default() }, prevtx)
12690
+ })
12691
+ .collect();
12688
12692
12689
12693
let interactive_tx_constructor = Some(InteractiveTxConstructor::new(
12690
12694
InteractiveTxConstructorArgs {
@@ -14121,6 +14125,8 @@ mod tests {
14121
14125
};
14122
14126
use crate::ln::channel_keys::{RevocationBasepoint, RevocationKey};
14123
14127
use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
14128
+ #[cfg(splicing)]
14129
+ use crate::ln::funding::FundingTxInput;
14124
14130
use crate::ln::msgs;
14125
14131
use crate::ln::msgs::{ChannelUpdate, UnsignedChannelUpdate, MAX_VALUE_MSAT};
14126
14132
use crate::ln::onion_utils::{AttributionData, LocalHTLCFailureReason};
@@ -14152,11 +14158,9 @@ mod tests {
14152
14158
use bitcoin::secp256k1::ffi::Signature as FFISignature;
14153
14159
use bitcoin::secp256k1::{ecdsa::Signature, Secp256k1};
14154
14160
use bitcoin::secp256k1::{PublicKey, SecretKey};
14155
- #[cfg(splicing)]
14156
- use bitcoin::transaction::TxIn;
14157
14161
use bitcoin::transaction::{Transaction, TxOut, Version};
14158
14162
#[cfg(splicing)]
14159
- use bitcoin::Weight ;
14163
+ use bitcoin::{ScriptBuf, Sequence, WPubkeyHash} ;
14160
14164
use bitcoin::{WitnessProgram, WitnessVersion};
14161
14165
use std::cmp;
14162
14166
@@ -15863,54 +15867,65 @@ mod tests {
15863
15867
#[rustfmt::skip]
15864
15868
fn test_estimate_v2_funding_transaction_fee() {
15865
15869
use crate::ln::channel::estimate_v2_funding_transaction_fee;
15866
- use bitcoin::Weight;
15867
15870
15868
- // 2 inputs with weight 300, initiator, 2000 sat/kw feerate
15871
+ let one_input = [funding_input_sats(1_000)];
15872
+ let two_inputs = [funding_input_sats(1_000), funding_input_sats(1_000)];
15873
+
15874
+ // 2 inputs, initiator, 2000 sat/kw feerate
15869
15875
assert_eq!(
15870
- estimate_v2_funding_transaction_fee(true, 2, Weight::from_wu(300) , 2000),
15871
- 1668
15876
+ estimate_v2_funding_transaction_fee(&two_inputs, true, false , 2000),
15877
+ 1520,
15872
15878
);
15873
15879
15874
15880
// higher feerate
15875
15881
assert_eq!(
15876
- estimate_v2_funding_transaction_fee(true, 2, Weight::from_wu(300) , 3000),
15877
- 2502
15882
+ estimate_v2_funding_transaction_fee(&two_inputs, true, false , 3000),
15883
+ 2280,
15878
15884
);
15879
15885
15880
15886
// only 1 input
15881
15887
assert_eq!(
15882
- estimate_v2_funding_transaction_fee(true, 1, Weight::from_wu(300) , 2000),
15883
- 1348
15888
+ estimate_v2_funding_transaction_fee(&one_input, true, false , 2000),
15889
+ 974,
15884
15890
);
15885
15891
15886
- // 0 input weight
15892
+ // 0 inputs
15887
15893
assert_eq!(
15888
- estimate_v2_funding_transaction_fee(true, 1, Weight::from_wu(0) , 2000),
15889
- 748
15894
+ estimate_v2_funding_transaction_fee(&[], true, false , 2000),
15895
+ 428,
15890
15896
);
15891
15897
15892
15898
// not initiator
15893
15899
assert_eq!(
15894
- estimate_v2_funding_transaction_fee(false, 1, Weight::from_wu(0), 2000),
15895
- 320
15900
+ estimate_v2_funding_transaction_fee(&[], false, false, 2000),
15901
+ 0,
15902
+ );
15903
+
15904
+ // splice initiator
15905
+ assert_eq!(
15906
+ estimate_v2_funding_transaction_fee(&one_input, true, true, 2000),
15907
+ 1746,
15908
+ );
15909
+
15910
+ // splice acceptor
15911
+ assert_eq!(
15912
+ estimate_v2_funding_transaction_fee(&one_input, false, true, 2000),
15913
+ 546,
15896
15914
);
15897
15915
}
15898
15916
15899
- #[cfg(splicing)]
15900
15917
#[rustfmt::skip]
15901
- fn funding_input_sats(input_value_sats: u64) -> (TxIn, Transaction, Weight) {
15902
- use crate::sign::P2WPKH_WITNESS_WEIGHT;
15903
-
15904
- let input_1_prev_out = TxOut { value: Amount::from_sat(input_value_sats), script_pubkey: bitcoin::ScriptBuf::default() };
15905
- let input_1_prev_tx = Transaction {
15906
- input: vec![], output: vec![input_1_prev_out],
15907
- version: Version::TWO, lock_time: bitcoin::absolute::LockTime::ZERO,
15918
+ fn funding_input_sats(input_value_sats: u64) -> FundingTxInput {
15919
+ let prevout = TxOut {
15920
+ value: Amount::from_sat(input_value_sats),
15921
+ script_pubkey: ScriptBuf::new_p2wpkh(&WPubkeyHash::all_zeros()),
15908
15922
};
15909
- let input_1_txin = TxIn {
15910
- previous_output: bitcoin::OutPoint { txid: input_1_prev_tx.compute_txid(), vout: 0 } ,
15911
- ..Default::default()
15923
+ let prevtx = Transaction {
15924
+ input: vec![], output: vec![prevout] ,
15925
+ version: Version::TWO, lock_time: bitcoin::absolute::LockTime::ZERO,
15912
15926
};
15913
- (input_1_txin, input_1_prev_tx, Weight::from_wu(P2WPKH_WITNESS_WEIGHT))
15927
+
15928
+ FundingTxInput::new_p2wpkh(prevtx, 0, Sequence::ZERO).unwrap()
15914
15929
}
15915
15930
15916
15931
#[cfg(splicing)]
@@ -15931,7 +15946,7 @@ mod tests {
15931
15946
true,
15932
15947
2000,
15933
15948
).unwrap(),
15934
- 2268 ,
15949
+ 2284 ,
15935
15950
);
15936
15951
15937
15952
// negative case, inputs clearly insufficient
@@ -15947,13 +15962,13 @@ mod tests {
15947
15962
);
15948
15963
assert_eq!(
15949
15964
format!("{:?}", res.err().unwrap()),
15950
- "Warn: Total input amount 100000 is lower than needed for contribution 220000, considering fees of 1730 . Need more inputs.",
15965
+ "Warn: Total input amount 100000 is lower than needed for contribution 220000, considering fees of 1738 . Need more inputs.",
15951
15966
);
15952
15967
}
15953
15968
15954
15969
// barely covers
15955
15970
{
15956
- let expected_fee: u64 = 2268 ;
15971
+ let expected_fee: u64 = 2284 ;
15957
15972
assert_eq!(
15958
15973
check_v2_funding_inputs_sufficient(
15959
15974
(300_000 - expected_fee - 20) as i64,
@@ -15983,13 +15998,13 @@ mod tests {
15983
15998
);
15984
15999
assert_eq!(
15985
16000
format!("{:?}", res.err().unwrap()),
15986
- "Warn: Total input amount 300000 is lower than needed for contribution 298032, considering fees of 2495 . Need more inputs.",
16001
+ "Warn: Total input amount 300000 is lower than needed for contribution 298032, considering fees of 2513 . Need more inputs.",
15987
16002
);
15988
16003
}
15989
16004
15990
16005
// barely covers, less fees (no extra weight, no init)
15991
16006
{
15992
- let expected_fee: u64 = 1076 ;
16007
+ let expected_fee: u64 = 1092 ;
15993
16008
assert_eq!(
15994
16009
check_v2_funding_inputs_sufficient(
15995
16010
(300_000 - expected_fee - 20) as i64,
0 commit comments