Skip to content

Commit e262326

Browse files
committed
Compute ConstructedTransaction weight from Transaction
Instead of defining a custom function for calculating a transaction's weight, have ConstructedTransaction hold a Transaction so that its weight method can be re-used. As a result NegotiatedTxInput no longer needs to store the transaction inputs.
1 parent 0a1d445 commit e262326

File tree

3 files changed

+56
-80
lines changed

3 files changed

+56
-80
lines changed

lightning/src/ln/channel.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8615,7 +8615,7 @@ where
86158615
return Err(APIError::APIMisuseError { err });
86168616
};
86178617

8618-
let tx = signing_session.unsigned_tx().build_unsigned_tx();
8618+
let tx = signing_session.unsigned_tx().tx();
86198619
if funding_txid_signed != tx.compute_txid() {
86208620
return Err(APIError::APIMisuseError {
86218621
err: "Transaction was malleated prior to signing".to_owned(),
@@ -8627,7 +8627,7 @@ where
86278627
let sig = match &self.context.holder_signer {
86288628
ChannelSignerType::Ecdsa(signer) => signer.sign_splice_shared_input(
86298629
&self.funding.channel_transaction_parameters,
8630-
&tx,
8630+
tx,
86318631
splice_input_index as usize,
86328632
&self.context.secp_ctx,
86338633
),

lightning/src/ln/channelmanager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9137,7 +9137,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
91379137
{
91389138
if signing_session.has_local_contribution() {
91399139
let mut pending_events = self.pending_events.lock().unwrap();
9140-
let unsigned_transaction = signing_session.unsigned_tx().build_unsigned_tx();
9140+
let unsigned_transaction = signing_session.unsigned_tx().tx().clone();
91419141
let event_action = (
91429142
Event::FundingTransactionReadyForSigning {
91439143
unsigned_transaction,

lightning/src/ln/interactivetxs.rs

Lines changed: 53 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -200,21 +200,20 @@ pub(crate) struct ConstructedTransaction {
200200

201201
inputs: Vec<NegotiatedTxInput>,
202202
outputs: Vec<InteractiveTxOutput>,
203+
tx: Transaction,
203204

204205
local_inputs_value_satoshis: u64,
205206
local_outputs_value_satoshis: u64,
206207

207208
remote_inputs_value_satoshis: u64,
208209
remote_outputs_value_satoshis: u64,
209210

210-
lock_time: AbsoluteLockTime,
211211
shared_input_index: Option<u32>,
212212
}
213213

214214
#[derive(Clone, Debug, Eq, PartialEq)]
215215
pub(crate) struct NegotiatedTxInput {
216216
serial_id: SerialId,
217-
txin: TxIn,
218217
prev_output: TxOut,
219218
}
220219

@@ -230,19 +229,18 @@ impl NegotiatedTxInput {
230229

231230
impl_writeable_tlv_based!(NegotiatedTxInput, {
232231
(1, serial_id, required),
233-
(3, txin, required),
234-
(5, prev_output, required),
232+
(3, prev_output, required),
235233
});
236234

237235
impl_writeable_tlv_based!(ConstructedTransaction, {
238236
(1, holder_is_initiator, required),
239237
(3, inputs, required),
240238
(5, outputs, required),
241-
(7, local_inputs_value_satoshis, required),
242-
(9, local_outputs_value_satoshis, required),
243-
(11, remote_inputs_value_satoshis, required),
244-
(13, remote_outputs_value_satoshis, required),
245-
(15, lock_time, required),
239+
(7, tx, required),
240+
(9, local_inputs_value_satoshis, required),
241+
(11, local_outputs_value_satoshis, required),
242+
(13, remote_inputs_value_satoshis, required),
243+
(15, remote_outputs_value_satoshis, required),
246244
(17, shared_input_index, option),
247245
});
248246

@@ -281,23 +279,37 @@ impl ConstructedTransaction {
281279
value.saturating_add(input.satisfaction_weight().to_wu())
282280
}));
283281

284-
let mut inputs: Vec<NegotiatedTxInput> =
285-
context.inputs.into_values().map(|tx_input| tx_input.into_negotiated_input()).collect();
282+
let mut inputs: Vec<(TxIn, NegotiatedTxInput)> = context
283+
.inputs
284+
.into_values()
285+
.map(|input| input.into_txin_and_negotiated_input())
286+
.collect();
286287
let mut outputs: Vec<InteractiveTxOutput> = context.outputs.into_values().collect();
287-
inputs.sort_unstable_by_key(|input| input.serial_id);
288+
inputs.sort_unstable_by_key(|(_, input)| input.serial_id);
288289
outputs.sort_unstable_by_key(|output| output.serial_id);
289290

290291
let shared_input_index =
291292
context.shared_funding_input.as_ref().and_then(|shared_funding_input| {
292293
inputs
293294
.iter()
294-
.position(|input| {
295-
input.txin.previous_output == shared_funding_input.input.previous_output
295+
.position(|(txin, _)| {
296+
txin.previous_output == shared_funding_input.input.previous_output
296297
})
297298
.map(|position| position as u32)
298299
});
299300

300-
let constructed_tx = Self {
301+
let (input, inputs): (Vec<TxIn>, Vec<NegotiatedTxInput>) = inputs.into_iter().unzip();
302+
let output = outputs.iter().map(|output| output.tx_out().clone()).collect();
303+
304+
let tx =
305+
Transaction { version: Version::TWO, lock_time: context.tx_locktime, input, output };
306+
307+
let tx_weight = tx.weight().checked_add(satisfaction_weight).unwrap_or(Weight::MAX);
308+
if tx_weight > Weight::from_wu(MAX_STANDARD_TX_WEIGHT as u64) {
309+
return Err(AbortReason::TransactionTooLarge);
310+
}
311+
312+
Ok(Self {
301313
holder_is_initiator: context.holder_is_initiator,
302314

303315
local_inputs_value_satoshis,
@@ -308,39 +320,14 @@ impl ConstructedTransaction {
308320

309321
inputs,
310322
outputs,
323+
tx,
311324

312-
lock_time: context.tx_locktime,
313325
shared_input_index,
314-
};
315-
316-
let tx_weight = constructed_tx.weight(satisfaction_weight);
317-
if tx_weight > Weight::from_wu(MAX_STANDARD_TX_WEIGHT as u64) {
318-
return Err(AbortReason::TransactionTooLarge);
319-
}
320-
321-
Ok(constructed_tx)
326+
})
322327
}
323328

324-
fn weight(&self, satisfaction_weight: Weight) -> Weight {
325-
let inputs_weight = Weight::from_wu(self.inputs.len() as u64 * BASE_INPUT_WEIGHT)
326-
.checked_add(satisfaction_weight)
327-
.unwrap_or(Weight::MAX);
328-
let outputs_weight = self.outputs.iter().fold(Weight::from_wu(0), |weight, output| {
329-
weight.checked_add(get_output_weight(output.script_pubkey())).unwrap_or(Weight::MAX)
330-
});
331-
Weight::from_wu(TX_COMMON_FIELDS_WEIGHT)
332-
.checked_add(inputs_weight)
333-
.and_then(|weight| weight.checked_add(outputs_weight))
334-
.unwrap_or(Weight::MAX)
335-
}
336-
337-
pub fn build_unsigned_tx(&self) -> Transaction {
338-
let ConstructedTransaction { inputs, outputs, .. } = self;
339-
340-
let input: Vec<TxIn> = inputs.iter().map(|input| input.txin.clone()).collect();
341-
let output: Vec<TxOut> = outputs.iter().map(|output| output.tx_out().clone()).collect();
342-
343-
Transaction { version: Version::TWO, lock_time: self.lock_time, input, output }
329+
pub fn tx(&self) -> &Transaction {
330+
&self.tx
344331
}
345332

346333
pub fn outputs(&self) -> impl Iterator<Item = &InteractiveTxOutput> {
@@ -352,23 +339,25 @@ impl ConstructedTransaction {
352339
}
353340

354341
pub fn compute_txid(&self) -> Txid {
355-
self.build_unsigned_tx().compute_txid()
342+
self.tx().compute_txid()
356343
}
357344

358345
/// Adds provided holder witnesses to holder inputs of unsigned transaction.
359346
///
360347
/// Note that it is assumed that the witness count equals the holder input count.
361348
fn add_local_witnesses(&mut self, witnesses: Vec<Witness>) {
362-
self.inputs
349+
self.tx
350+
.input
363351
.iter_mut()
352+
.zip(self.inputs.iter())
364353
.enumerate()
365-
.filter(|(_, input)| input.is_local(self.holder_is_initiator))
354+
.filter(|(_, (_, input))| input.is_local(self.holder_is_initiator))
366355
.filter(|(index, _)| {
367356
self.shared_input_index
368357
.map(|shared_index| *index != shared_index as usize)
369358
.unwrap_or(true)
370359
})
371-
.map(|(_, input)| &mut input.txin)
360+
.map(|(_, (txin, _))| txin)
372361
.zip(witnesses)
373362
.for_each(|(input, witness)| input.witness = witness);
374363
}
@@ -377,16 +366,18 @@ impl ConstructedTransaction {
377366
///
378367
/// Note that it is assumed that the witness count equals the counterparty input count.
379368
fn add_remote_witnesses(&mut self, witnesses: Vec<Witness>) {
380-
self.inputs
369+
self.tx
370+
.input
381371
.iter_mut()
372+
.zip(self.inputs.iter())
382373
.enumerate()
383-
.filter(|(_, input)| !input.is_local(self.holder_is_initiator))
374+
.filter(|(_, (_, input))| !input.is_local(self.holder_is_initiator))
384375
.filter(|(index, _)| {
385376
self.shared_input_index
386377
.map(|shared_index| *index != shared_index as usize)
387378
.unwrap_or(true)
388379
})
389-
.map(|(_, input)| &mut input.txin)
380+
.map(|(_, (txin, _))| txin)
390381
.zip(witnesses)
391382
.for_each(|(input, witness)| input.witness = witness);
392383
}
@@ -594,18 +585,7 @@ impl InteractiveTxSigningSession {
594585
}
595586

596587
fn finalize_funding_tx(&mut self) -> Transaction {
597-
let lock_time = self.unsigned_tx.lock_time;
598-
let ConstructedTransaction { inputs, outputs, shared_input_index, .. } =
599-
&mut self.unsigned_tx;
600-
601-
let mut tx = Transaction {
602-
version: Version::TWO,
603-
lock_time,
604-
input: inputs.iter().cloned().map(|input| input.txin).collect(),
605-
output: outputs.iter().cloned().map(|output| output.into_tx_out()).collect(),
606-
};
607-
608-
if let Some(shared_input_index) = shared_input_index {
588+
if let Some(shared_input_index) = self.unsigned_tx.shared_input_index {
609589
if let Some(holder_shared_input_sig) = self
610590
.holder_tx_signatures
611591
.as_ref()
@@ -628,7 +608,7 @@ impl InteractiveTxSigningSession {
628608
witness.push_ecdsa_signature(&holder_sig);
629609
}
630610
witness.push(&shared_input_sig.witness_script);
631-
tx.input[*shared_input_index as usize].witness = witness;
611+
self.unsigned_tx.tx.input[shared_input_index as usize].witness = witness;
632612
} else {
633613
debug_assert!(false);
634614
}
@@ -640,19 +620,19 @@ impl InteractiveTxSigningSession {
640620
}
641621
}
642622

643-
tx
623+
self.unsigned_tx.tx.clone()
644624
}
645625

646626
fn verify_interactive_tx_signatures<C: bitcoin::secp256k1::Verification>(
647627
&self, secp_ctx: &Secp256k1<C>, witnesses: &Vec<Witness>,
648628
) -> Result<(), String> {
649629
let unsigned_tx = self.unsigned_tx();
650-
let built_tx = unsigned_tx.build_unsigned_tx();
630+
let built_tx = unsigned_tx.tx();
651631
let prev_outputs: Vec<&TxOut> =
652632
unsigned_tx.inputs().map(|input| input.prev_output()).collect::<Vec<_>>();
653633
let all_prevouts = sighash::Prevouts::All(&prev_outputs[..]);
654634

655-
let mut cache = SighashCache::new(&built_tx);
635+
let mut cache = SighashCache::new(built_tx);
656636

657637
let script_pubkeys = unsigned_tx
658638
.inputs()
@@ -1855,9 +1835,9 @@ impl InteractiveTxInput {
18551835
self.input.satisfaction_weight()
18561836
}
18571837

1858-
fn into_negotiated_input(self) -> NegotiatedTxInput {
1838+
fn into_txin_and_negotiated_input(self) -> (TxIn, NegotiatedTxInput) {
18591839
let (txin, prev_output) = self.input.into_tx_in_with_prev_output();
1860-
NegotiatedTxInput { serial_id: self.serial_id, txin, prev_output }
1840+
(txin, NegotiatedTxInput { serial_id: self.serial_id, prev_output })
18611841
}
18621842
}
18631843

@@ -3321,16 +3301,12 @@ mod tests {
33213301
fn do_verify_tx_signatures(
33223302
transaction: Transaction, prev_outputs: Vec<TxOut>,
33233303
) -> Result<(), String> {
3324-
let inputs: Vec<NegotiatedTxInput> = transaction
3325-
.input
3326-
.iter()
3327-
.cloned()
3328-
.zip(prev_outputs.into_iter())
3304+
let inputs: Vec<NegotiatedTxInput> = prev_outputs
3305+
.into_iter()
33293306
.enumerate()
3330-
.map(|(idx, (txin, prev_output))| {
3307+
.map(|(idx, prev_output)| {
33313308
NegotiatedTxInput {
33323309
serial_id: idx as u64, // even values will be holder (initiator in this test)
3333-
txin,
33343310
prev_output,
33353311
}
33363312
})
@@ -3351,11 +3327,11 @@ mod tests {
33513327
holder_is_initiator: true,
33523328
inputs,
33533329
outputs,
3330+
tx: transaction.clone(),
33543331
local_inputs_value_satoshis: 0, // N/A for test
33553332
local_outputs_value_satoshis: 0, // N/A for test
33563333
remote_inputs_value_satoshis: 0, // N/A for test
33573334
remote_outputs_value_satoshis: 0, // N/A for test
3358-
lock_time: transaction.lock_time,
33593335
shared_input_index: None,
33603336
};
33613337

0 commit comments

Comments
 (0)