Skip to content

Commit 49a2fc6

Browse files
committed
fixup! simplify CommitmentTransaction constructor
1 parent ded0873 commit 49a2fc6

File tree

3 files changed

+56
-70
lines changed

3 files changed

+56
-70
lines changed

lightning/src/ln/chan_utils.rs

Lines changed: 40 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -736,8 +736,8 @@ impl HolderCommitmentTransaction {
736736
counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: channel_pubkeys.clone(), selected_contest_delay: 0 }),
737737
funding_outpoint: Some(chain::transaction::OutPoint { txid: Default::default(), index: 0 })
738738
};
739-
let aux: Vec<()> = Vec::new();
740-
let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, keys, 0, Vec::new(), aux, &channel_parameters.as_counterparty_broadcastable()).0;
739+
let mut htlcs_with_aux: Vec<(_, ())> = Vec::new();
740+
let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, keys, 0, &mut htlcs_with_aux, &channel_parameters.as_counterparty_broadcastable());
741741
HolderCommitmentTransaction {
742742
inner,
743743
counterparty_sig: dummy_sig,
@@ -887,32 +887,20 @@ impl_writeable!(CommitmentTransaction, 0, {
887887
impl CommitmentTransaction {
888888
/// Construct an object of the class while assigning transaction output indices to HTLCs.
889889
///
890-
/// Also keeps track of auxiliary HTLC data and returns it along with the mutated and sorted HTLCs.
891-
/// This allows the caller to match the HTLC output index with the auxiliary data.
890+
/// Populates HTLCOutputInCommitment.transaction_output_index in htlcs_with_aux.
891+
///
892+
/// The generic T allows the caller to match the HTLC output index with auxiliary data.
892893
/// This auxiliary data is not stored in this object.
893894
///
894895
/// Only include HTLCs that are above the dust limit for the channel.
895-
///
896-
/// Panics if the length of htlcs and aux are different.
897-
pub fn new_with_auxiliary_htlc_data<T>(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, keys: TxCreationKeys, feerate_per_kw: u32, htlcs: Vec<HTLCOutputInCommitment>, aux: Vec<T>, channel_parameters: &DirectedChannelTransactionParameters) -> (CommitmentTransaction, Vec<(HTLCOutputInCommitment, T)>) {
896+
pub fn new_with_auxiliary_htlc_data<T>(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction {
898897
// Sort outputs and populate output indices while keeping track of the auxiliary data
899-
let mut txouts = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, &htlcs, aux, channel_parameters).unwrap();
900-
let mut result_htlcs_with_aux = Vec::new();
901-
let mut htlcs = Vec::new();
902-
let mut outputs = Vec::new();
903-
for (idx, mut out) in txouts.drain(..).enumerate() {
904-
if let Some(mut htlc) = (out.1).1.take() {
905-
htlc.0.transaction_output_index = Some(idx as u32);
906-
result_htlcs_with_aux.push((htlc.0.clone(), htlc.1));
907-
htlcs.push(htlc.0);
908-
}
909-
outputs.push(out.0);
910-
}
898+
let (outputs, htlcs, _) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters).unwrap();
911899

912900
let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(commitment_number, channel_parameters);
913901
let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs);
914902
let txid = transaction.txid();
915-
let info = CommitmentTransaction {
903+
CommitmentTransaction {
916904
commitment_number,
917905
to_broadcaster_value_sat,
918906
to_countersignatory_value_sat,
@@ -923,44 +911,32 @@ impl CommitmentTransaction {
923911
transaction,
924912
txid
925913
},
926-
};
927-
(info, result_htlcs_with_aux)
914+
}
928915
}
929916

930917
#[cfg(feature = "_test_utils")]
931-
/// Re-build the Bitcoin transaction.
932-
///
933-
/// This function ignores the pre-built transaction and the pre-derived TxCreationKeys
934-
/// for use in an environment, such as an external signer, where we don't trust these to be
935-
/// derived by the Lightning node.
918+
/// Get the transaction output scripts.
936919
///
937-
/// The second return value are the scripts that were built for debugging purposes, since
938-
/// only the hash is present in the actual transaction.
939-
pub fn rebuild_transaction(&self, keys: &TxCreationKeys, channel_parameters: &DirectedChannelTransactionParameters) -> Result<(BuiltCommitmentTransaction, Vec<Script>), ()> {
940-
self.internal_rebuild_transaction(keys, channel_parameters)
920+
/// For debugging purposes, since only the hash is present in the actual transaction.
921+
pub fn get_output_scripts(&self, keys: &TxCreationKeys, channel_parameters: &DirectedChannelTransactionParameters) -> Result<Vec<Script>, ()> {
922+
let mut htlcs_with_aux = self.htlcs.iter().map(|h| (h.clone(), ())).collect();
923+
let (_, _, scripts) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, channel_parameters)?;
924+
Ok(scripts)
941925
}
942926

943-
fn internal_rebuild_transaction(&self, keys: &TxCreationKeys, channel_parameters: &DirectedChannelTransactionParameters) -> Result<(BuiltCommitmentTransaction, Vec<Script>), ()> {
927+
fn internal_rebuild_transaction(&self, keys: &TxCreationKeys, channel_parameters: &DirectedChannelTransactionParameters) -> Result<BuiltCommitmentTransaction, ()> {
944928
let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(self.commitment_number, channel_parameters);
945929

946-
let mut aux = Vec::with_capacity(self.htlcs.len());
947-
aux.resize(self.htlcs.len(), ());
948-
let mut txouts = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &self.htlcs, aux, channel_parameters)?;
949-
950-
let mut outputs = Vec::with_capacity(txouts.len());
951-
let mut scripts = Vec::with_capacity(txouts.len());
952-
for (txout, (script, _)) in txouts.drain(..) {
953-
outputs.push(txout);
954-
scripts.push(script);
955-
}
930+
let mut htlcs_with_aux = self.htlcs.iter().map(|h| (h.clone(), ())).collect();
931+
let (outputs, _, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, channel_parameters)?;
956932

957933
let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs);
958934
let txid = transaction.txid();
959935
let built_transaction = BuiltCommitmentTransaction {
960936
transaction,
961937
txid
962938
};
963-
Ok((built_transaction, scripts))
939+
Ok(built_transaction)
964940
}
965941

966942
fn make_transaction(obscured_commitment_transaction_number: u64, txins: Vec<TxIn>, outputs: Vec<TxOut>) -> Transaction {
@@ -976,12 +952,11 @@ impl CommitmentTransaction {
976952
// - initial sorting of outputs / HTLCs in the constructor, in which case T is auxiliary data the
977953
// caller needs to have sorted together with the HTLCs so it can keep track of the output index
978954
// - building of a bitcoin transaction (build -> build_outputs), in which case T is just ()
979-
fn internal_build_outputs<T>(keys: &TxCreationKeys, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, htlcs: &Vec<HTLCOutputInCommitment>, aux: Vec<T>, channel_parameters: &DirectedChannelTransactionParameters) -> Result<Vec<(TxOut, (Script, Option<(HTLCOutputInCommitment, T)>))>, ()> {
980-
assert_eq!(htlcs.len(), aux.len(), "htlcs vs aux length mismatch");
955+
fn internal_build_outputs<T>(keys: &TxCreationKeys, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> Result<(Vec<TxOut>, Vec<HTLCOutputInCommitment>, Vec<Script>), ()> {
981956
let countersignatory_pubkeys = channel_parameters.countersignatory_pubkeys();
982957
let contest_delay = channel_parameters.contest_delay();
983958

984-
let mut txouts: Vec<(TxOut, (Script, Option<(HTLCOutputInCommitment, T)>))> = Vec::new();
959+
let mut txouts: Vec<(TxOut, (Script, Option<&mut HTLCOutputInCommitment>))> = Vec::new();
985960

986961
if to_countersignatory_value_sat > 0 {
987962
let script = script_for_p2wpkh(&countersignatory_pubkeys.payment_point);
@@ -1009,29 +984,43 @@ impl CommitmentTransaction {
1009984
));
1010985
}
1011986

1012-
for (htlc, t) in htlcs.iter().zip(aux) {
987+
let mut htlcs = Vec::with_capacity(htlcs_with_aux.len());
988+
for (htlc, _) in htlcs_with_aux {
1013989
let script = chan_utils::get_htlc_redeemscript(&htlc, &keys);
1014990
let txout = TxOut {
1015991
script_pubkey: script.to_v0_p2wsh(),
1016992
value: htlc.amount_msat / 1000,
1017993
};
1018-
txouts.push((txout, (script, Some((htlc.clone(), t)))));
994+
txouts.push((txout, (script, Some(htlc))));
1019995
}
1020996

1021997
// Sort output in BIP-69 order (amount, scriptPubkey). Tie-breaks based on HTLC
1022998
// CLTV expiration height.
1023999
sort_outputs(&mut txouts, |a, b| {
10241000
if let &(_, Some(ref a_htlcout)) = a {
10251001
if let &(_, Some(ref b_htlcout)) = b {
1026-
a_htlcout.0.cltv_expiry.cmp(&b_htlcout.0.cltv_expiry)
1002+
a_htlcout.cltv_expiry.cmp(&b_htlcout.cltv_expiry)
10271003
} else {
10281004
cmp::Ordering::Equal
10291005
}
10301006
} else {
10311007
cmp::Ordering::Equal
10321008
}
10331009
});
1034-
Ok(txouts)
1010+
1011+
let mut outputs = Vec::with_capacity(txouts.len());
1012+
let mut scripts = Vec::new();
1013+
scripts.clear(); // Prevent mut warning
1014+
for (idx, out) in txouts.drain(..).enumerate() {
1015+
if let Some(htlc) = (out.1).1 {
1016+
htlc.transaction_output_index = Some(idx as u32);
1017+
htlcs.push(htlc.clone());
1018+
}
1019+
outputs.push(out.0);
1020+
#[cfg(feature = "_test_utils")]
1021+
scripts.push((out.1).0);
1022+
}
1023+
Ok((outputs, htlcs, scripts))
10351024
}
10361025

10371026
fn internal_build_inputs(commitment_number: u64, channel_parameters: &DirectedChannelTransactionParameters) -> (u64, Vec<TxIn>) {
@@ -1116,7 +1105,7 @@ impl CommitmentTransaction {
11161105
if keys != self.keys {
11171106
return Err(());
11181107
}
1119-
let (tx, _) = self.internal_rebuild_transaction(&keys, channel_parameters)?;
1108+
let tx = self.internal_rebuild_transaction(&keys, channel_parameters)?;
11201109
if self.built.transaction != tx.transaction || self.built.txid != tx.txid {
11211110
return Err(());
11221111
}

lightning/src/ln/channel.rs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -839,8 +839,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
839839
fn build_commitment_transaction<L: Deref>(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u32, logger: &L) -> (CommitmentTransaction, usize, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>) where L::Target: Logger {
840840
let mut included_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::new();
841841
let num_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len();
842-
let mut included_non_dust_htlcs: Vec<HTLCOutputInCommitment> = Vec::with_capacity(num_htlcs);
843-
let mut included_non_dust_sources: Vec<Option<&HTLCSource>> = Vec::with_capacity(num_htlcs);
842+
let mut included_non_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(num_htlcs);
844843

845844
let broadcaster_dust_limit_satoshis = if local { self.holder_dust_limit_satoshis } else { self.counterparty_dust_limit_satoshis };
846845
let mut remote_htlc_total_msat = 0;
@@ -867,8 +866,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
867866
let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
868867
if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + (feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) {
869868
log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
870-
included_non_dust_htlcs.push(htlc_in_tx);
871-
included_non_dust_sources.push($source);
869+
included_non_dust_htlcs.push((htlc_in_tx, $source));
872870
} else {
873871
log_trace!(logger, " ...including {} {} dust HTLC {} (hash {}) with value {} due to dust limit", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
874872
included_dust_htlcs.push((htlc_in_tx, $source));
@@ -877,8 +875,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
877875
let htlc_in_tx = get_htlc_in_commitment!($htlc, false);
878876
if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + (feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) {
879877
log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
880-
included_non_dust_htlcs.push(htlc_in_tx);
881-
included_non_dust_sources.push($source);
878+
included_non_dust_htlcs.push((htlc_in_tx, $source));
882879
} else {
883880
log_trace!(logger, " ...including {} {} dust HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
884881
included_dust_htlcs.push((htlc_in_tx, $source));
@@ -993,19 +990,20 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
993990
let channel_parameters =
994991
if local { self.channel_transaction_parameters.as_holder_broadcastable() }
995992
else { self.channel_transaction_parameters.as_counterparty_broadcastable() };
996-
let (info, mut htlcs_included) = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number,
997-
value_to_a as u64,
998-
value_to_b as u64,
999-
keys.clone(),
1000-
feerate_per_kw,
1001-
included_non_dust_htlcs,
1002-
included_non_dust_sources,
1003-
&channel_parameters
993+
let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number,
994+
value_to_a as u64,
995+
value_to_b as u64,
996+
keys.clone(),
997+
feerate_per_kw,
998+
&mut included_non_dust_htlcs,
999+
&channel_parameters
10041000
);
1005-
1001+
let mut htlcs_included = included_non_dust_htlcs;
1002+
// The unwrap is safe, because all non-dust HTLCs have been assigned an output index
1003+
htlcs_included.sort_unstable_by_key(|h| h.0.transaction_output_index.unwrap());
10061004
htlcs_included.append(&mut included_dust_htlcs);
10071005

1008-
(info, num_nondust_htlcs, htlcs_included)
1006+
(tx, num_nondust_htlcs, htlcs_included)
10091007
}
10101008

10111009
#[inline]

lightning/src/ln/functional_tests.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,11 +1663,10 @@ fn test_fee_spike_violation_fails_htlc() {
16631663
local_chan_balance,
16641664
commit_tx_keys.clone(),
16651665
feerate_per_kw,
1666-
vec![accepted_htlc_info],
1667-
vec![()],
1666+
&mut vec![(accepted_htlc_info, ())],
16681667
&local_chan.channel_transaction_parameters.as_counterparty_broadcastable()
16691668
);
1670-
local_chan_keys.sign_counterparty_commitment(&commitment_tx.0, &secp_ctx).unwrap()
1669+
local_chan_keys.sign_counterparty_commitment(&commitment_tx, &secp_ctx).unwrap()
16711670
};
16721671

16731672
let commit_signed_msg = msgs::CommitmentSigned {

0 commit comments

Comments
 (0)