Skip to content

Commit 0e30acc

Browse files
committed
Remove TransactionU16LenLimited
TransactionU16LenLimited was used to limit Transaction serialization size to u16::MAX. This was because messages can not be longer than u16::MAX bytes when serialized for the transport layer. However, this limit doesn't take into account other fields in a message containing a Transaction, including the length of the transaction itself. Remove TransactionU16LenLimited and instead check any user supplied transactions in the context of the enclosing message (e.g. TxAddInput).
1 parent fe6f003 commit 0e30acc

File tree

6 files changed

+105
-124
lines changed

6 files changed

+105
-124
lines changed

lightning/src/ln/channel.rs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,7 @@ use crate::util::config::{
8585
use crate::util::errors::APIError;
8686
use crate::util::logger::{Logger, Record, WithContext};
8787
use crate::util::scid_utils::{block_from_scid, scid_from_parts};
88-
use crate::util::ser::{
89-
Readable, ReadableArgs, RequiredWrapper, TransactionU16LenLimited, Writeable, Writer,
90-
};
88+
use crate::util::ser::{Readable, ReadableArgs, RequiredWrapper, Writeable, Writer};
9189

9290
use alloc::collections::{btree_map, BTreeMap};
9391

@@ -5979,7 +5977,7 @@ pub(super) struct FundingNegotiationContext {
59795977
pub shared_funding_input: Option<SharedOwnedInput>,
59805978
/// The funding inputs we will be contributing to the channel.
59815979
#[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
5982-
pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
5980+
pub our_funding_inputs: Vec<(TxIn, Transaction)>,
59835981
/// The change output script. This will be used if needed or -- if not set -- generated using
59845982
/// `SignerProvider::get_destination_script`.
59855983
#[allow(dead_code)] // TODO(splicing): Remove once splicing is enabled.
@@ -10678,10 +10676,23 @@ where
1067810676
})?;
1067910677
// Convert inputs
1068010678
let mut funding_inputs = Vec::new();
10681-
for (tx_in, tx, _w) in our_funding_inputs.into_iter() {
10682-
let tx16 = TransactionU16LenLimited::new(tx)
10683-
.map_err(|_e| APIError::APIMisuseError { err: format!("Too large transaction") })?;
10684-
funding_inputs.push((tx_in, tx16));
10679+
for (txin, tx, _) in our_funding_inputs.into_iter() {
10680+
const MESSAGE_TEMPLATE: msgs::TxAddInput = msgs::TxAddInput {
10681+
channel_id: ChannelId([0; 32]),
10682+
serial_id: 0,
10683+
prevtx: None,
10684+
prevtx_out: 0,
10685+
sequence: 0,
10686+
shared_input_txid: None,
10687+
};
10688+
let message_len = MESSAGE_TEMPLATE.serialized_length() + tx.serialized_length();
10689+
if message_len > u16::MAX as usize {
10690+
return Err(APIError::APIMisuseError {
10691+
err: format!("Funding input's prevtx is too large for tx_add_input"),
10692+
});
10693+
}
10694+
10695+
funding_inputs.push((txin, tx));
1068510696
}
1068610697

1068710698
let prev_funding_input = self.funding.to_splice_funding_input();
@@ -12458,7 +12469,7 @@ where
1245812469
pub fn new_outbound<ES: Deref, F: Deref, L: Deref>(
1245912470
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
1246012471
counterparty_node_id: PublicKey, their_features: &InitFeatures, funding_satoshis: u64,
12461-
funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>, user_id: u128, config: &UserConfig,
12472+
funding_inputs: Vec<(TxIn, Transaction)>, user_id: u128, config: &UserConfig,
1246212473
current_chain_height: u32, outbound_scid_alias: u64, funding_confirmation_target: ConfirmationTarget,
1246312474
logger: L,
1246412475
) -> Result<Self, APIError>

lightning/src/ln/dual_funding_tests.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ use {
2323
crate::ln::msgs::{CommitmentSigned, TxAddInput, TxAddOutput, TxComplete, TxSignatures},
2424
crate::ln::types::ChannelId,
2525
crate::prelude::*,
26-
crate::util::ser::TransactionU16LenLimited,
2726
crate::util::test_utils,
2827
bitcoin::Witness,
2928
};
@@ -51,7 +50,7 @@ fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession)
5150
&[session.initiator_input_value_satoshis],
5251
)
5352
.into_iter()
54-
.map(|(txin, tx, _)| (txin, TransactionU16LenLimited::new(tx).unwrap()))
53+
.map(|(txin, tx, _)| (txin, tx))
5554
.collect();
5655

5756
// Alice creates a dual-funded channel as initiator.
@@ -94,7 +93,7 @@ fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession)
9493
sequence: initiator_funding_inputs[0].0.sequence.0,
9594
shared_input_txid: None,
9695
};
97-
let input_value = tx_add_input_msg.prevtx.as_ref().unwrap().as_transaction().output
96+
let input_value = tx_add_input_msg.prevtx.as_ref().unwrap().output
9897
[tx_add_input_msg.prevtx_out as usize]
9998
.value;
10099
assert_eq!(input_value.to_sat(), session.initiator_input_value_satoshis);

lightning/src/ln/interactivetxs.rs

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use crate::ln::msgs;
2727
use crate::ln::msgs::{MessageSendEvent, SerialId, TxSignatures};
2828
use crate::ln::types::ChannelId;
2929
use crate::sign::{EntropySource, P2TR_KEY_PATH_WITNESS_WEIGHT, P2WPKH_WITNESS_WEIGHT};
30-
use crate::util::ser::TransactionU16LenLimited;
3130

3231
use core::fmt::Display;
3332
use core::ops::Deref;
@@ -676,10 +675,9 @@ impl NegotiationContext {
676675
return Err(AbortReason::UnexpectedFundingInput);
677676
}
678677
} else if let Some(prevtx) = &msg.prevtx {
679-
let transaction = prevtx.as_transaction();
680-
let txid = transaction.compute_txid();
678+
let txid = prevtx.compute_txid();
681679

682-
if let Some(tx_out) = transaction.output.get(msg.prevtx_out as usize) {
680+
if let Some(tx_out) = prevtx.output.get(msg.prevtx_out as usize) {
683681
if !tx_out.script_pubkey.is_witness_program() {
684682
// The receiving node:
685683
// - MUST fail the negotiation if:
@@ -860,14 +858,9 @@ impl NegotiationContext {
860858
return Err(AbortReason::UnexpectedFundingInput);
861859
}
862860
} else if let Some(prevtx) = &msg.prevtx {
863-
let prev_txid = prevtx.as_transaction().compute_txid();
861+
let prev_txid = prevtx.compute_txid();
864862
let prev_outpoint = OutPoint { txid: prev_txid, vout: msg.prevtx_out };
865-
let prev_output = prevtx
866-
.as_transaction()
867-
.output
868-
.get(vout)
869-
.ok_or(AbortReason::PrevTxOutInvalid)?
870-
.clone();
863+
let prev_output = prevtx.output.get(vout).ok_or(AbortReason::PrevTxOutInvalid)?.clone();
871864
let txin = TxIn {
872865
previous_output: prev_outpoint,
873866
sequence: Sequence(msg.sequence),
@@ -1247,7 +1240,7 @@ impl_writeable_tlv_based_enum!(AddingRole,
12471240
#[derive(Clone, Debug, Eq, PartialEq)]
12481241
struct SingleOwnedInput {
12491242
input: TxIn,
1250-
prev_tx: TransactionU16LenLimited,
1243+
prev_tx: Transaction,
12511244
prev_output: TxOut,
12521245
}
12531246

@@ -1652,7 +1645,7 @@ where
16521645
pub feerate_sat_per_kw: u32,
16531646
pub is_initiator: bool,
16541647
pub funding_tx_locktime: AbsoluteLockTime,
1655-
pub inputs_to_contribute: Vec<(TxIn, TransactionU16LenLimited)>,
1648+
pub inputs_to_contribute: Vec<(TxIn, Transaction)>,
16561649
pub shared_funding_input: Option<SharedOwnedInput>,
16571650
pub shared_funding_output: SharedOwnedOutput,
16581651
pub outputs_to_contribute: Vec<TxOut>,
@@ -1694,7 +1687,7 @@ impl InteractiveTxConstructor {
16941687
// Check for the existence of prevouts'
16951688
for (txin, tx) in inputs_to_contribute.iter() {
16961689
let vout = txin.previous_output.vout as usize;
1697-
if tx.as_transaction().output.get(vout).is_none() {
1690+
if tx.output.get(vout).is_none() {
16981691
return Err(AbortReason::PrevTxOutInvalid);
16991692
}
17001693
}
@@ -1703,7 +1696,7 @@ impl InteractiveTxConstructor {
17031696
.map(|(txin, tx)| {
17041697
let serial_id = generate_holder_serial_id(entropy_source, is_initiator);
17051698
let vout = txin.previous_output.vout as usize;
1706-
let prev_output = tx.as_transaction().output.get(vout).unwrap().clone(); // checked above
1699+
let prev_output = tx.output.get(vout).unwrap().clone(); // checked above
17071700
let input =
17081701
InputOwned::Single(SingleOwnedInput { input: txin, prev_tx: tx, prev_output });
17091702
(serial_id, input)
@@ -1892,12 +1885,11 @@ pub(super) fn calculate_change_output_value(
18921885
let mut total_input_satoshis = 0u64;
18931886
let mut our_funding_inputs_weight = 0u64;
18941887
for (txin, tx) in context.our_funding_inputs.iter() {
1895-
let txid = tx.as_transaction().compute_txid();
1888+
let txid = tx.compute_txid();
18961889
if txin.previous_output.txid != txid {
18971890
return Err(AbortReason::PrevTxOutInvalid);
18981891
}
18991892
let output = tx
1900-
.as_transaction()
19011893
.output
19021894
.get(txin.previous_output.vout as usize)
19031895
.ok_or(AbortReason::PrevTxOutInvalid)?;
@@ -1954,7 +1946,6 @@ mod tests {
19541946
use crate::ln::types::ChannelId;
19551947
use crate::sign::EntropySource;
19561948
use crate::util::atomic_counter::AtomicCounter;
1957-
use crate::util::ser::TransactionU16LenLimited;
19581949
use bitcoin::absolute::LockTime as AbsoluteLockTime;
19591950
use bitcoin::amount::Amount;
19601951
use bitcoin::hashes::Hash;
@@ -2018,12 +2009,12 @@ mod tests {
20182009

20192010
struct TestSession {
20202011
description: &'static str,
2021-
inputs_a: Vec<(TxIn, TransactionU16LenLimited)>,
2012+
inputs_a: Vec<(TxIn, Transaction)>,
20222013
a_shared_input: Option<(OutPoint, TxOut, u64)>,
20232014
/// The funding output, with the value contributed
20242015
shared_output_a: (TxOut, u64),
20252016
outputs_a: Vec<TxOut>,
2026-
inputs_b: Vec<(TxIn, TransactionU16LenLimited)>,
2017+
inputs_b: Vec<(TxIn, Transaction)>,
20272018
b_shared_input: Option<(OutPoint, TxOut, u64)>,
20282019
/// The funding output, with the value contributed
20292020
shared_output_b: (TxOut, u64),
@@ -2289,7 +2280,7 @@ mod tests {
22892280
}
22902281
}
22912282

2292-
fn generate_inputs(outputs: &[TestOutput]) -> Vec<(TxIn, TransactionU16LenLimited)> {
2283+
fn generate_inputs(outputs: &[TestOutput]) -> Vec<(TxIn, Transaction)> {
22932284
let tx = generate_tx(outputs);
22942285
let txid = tx.compute_txid();
22952286
tx.output
@@ -2302,7 +2293,7 @@ mod tests {
23022293
sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
23032294
witness: Default::default(),
23042295
};
2305-
(txin, TransactionU16LenLimited::new(tx.clone()).unwrap())
2296+
(txin, tx.clone())
23062297
})
23072298
.collect()
23082299
}
@@ -2350,12 +2341,12 @@ mod tests {
23502341
(generate_txout(&TestOutput::P2WSH(value)), local_value)
23512342
}
23522343

2353-
fn generate_fixed_number_of_inputs(count: u16) -> Vec<(TxIn, TransactionU16LenLimited)> {
2344+
fn generate_fixed_number_of_inputs(count: u16) -> Vec<(TxIn, Transaction)> {
23542345
// Generate transactions with a total `count` number of outputs such that no transaction has a
23552346
// serialized length greater than u16::MAX.
23562347
let max_outputs_per_prevtx = 1_500;
23572348
let mut remaining = count;
2358-
let mut inputs: Vec<(TxIn, TransactionU16LenLimited)> = Vec::with_capacity(count as usize);
2349+
let mut inputs: Vec<(TxIn, Transaction)> = Vec::with_capacity(count as usize);
23592350

23602351
while remaining > 0 {
23612352
let tx_output_count = remaining.min(max_outputs_per_prevtx);
@@ -2368,7 +2359,7 @@ mod tests {
23682359
);
23692360
let txid = tx.compute_txid();
23702361

2371-
let mut temp: Vec<(TxIn, TransactionU16LenLimited)> = tx
2362+
let mut temp: Vec<(TxIn, Transaction)> = tx
23722363
.output
23732364
.iter()
23742365
.enumerate()
@@ -2379,7 +2370,7 @@ mod tests {
23792370
sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
23802371
witness: Default::default(),
23812372
};
2382-
(input, TransactionU16LenLimited::new(tx.clone()).unwrap())
2373+
(input, tx.clone())
23832374
})
23842375
.collect();
23852376

@@ -2590,10 +2581,9 @@ mod tests {
25902581
expect_error: Some((AbortReason::PrevTxOutInvalid, ErrorCulprit::NodeA)),
25912582
});
25922583

2593-
let tx =
2594-
TransactionU16LenLimited::new(generate_tx(&[TestOutput::P2WPKH(1_000_000)])).unwrap();
2584+
let tx = generate_tx(&[TestOutput::P2WPKH(1_000_000)]);
25952585
let invalid_sequence_input = TxIn {
2596-
previous_output: OutPoint { txid: tx.as_transaction().compute_txid(), vout: 0 },
2586+
previous_output: OutPoint { txid: tx.compute_txid(), vout: 0 },
25972587
..Default::default()
25982588
};
25992589
do_test_interactive_tx_constructor(TestSession {
@@ -2609,7 +2599,7 @@ mod tests {
26092599
expect_error: Some((AbortReason::IncorrectInputSequenceValue, ErrorCulprit::NodeA)),
26102600
});
26112601
let duplicate_input = TxIn {
2612-
previous_output: OutPoint { txid: tx.as_transaction().compute_txid(), vout: 0 },
2602+
previous_output: OutPoint { txid: tx.compute_txid(), vout: 0 },
26132603
sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
26142604
..Default::default()
26152605
};
@@ -2627,7 +2617,7 @@ mod tests {
26272617
});
26282618
// Non-initiator uses same prevout as initiator.
26292619
let duplicate_input = TxIn {
2630-
previous_output: OutPoint { txid: tx.as_transaction().compute_txid(), vout: 0 },
2620+
previous_output: OutPoint { txid: tx.compute_txid(), vout: 0 },
26312621
sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
26322622
..Default::default()
26332623
};
@@ -2644,7 +2634,7 @@ mod tests {
26442634
expect_error: Some((AbortReason::PrevTxOutInvalid, ErrorCulprit::NodeA)),
26452635
});
26462636
let duplicate_input = TxIn {
2647-
previous_output: OutPoint { txid: tx.as_transaction().compute_txid(), vout: 0 },
2637+
previous_output: OutPoint { txid: tx.compute_txid(), vout: 0 },
26482638
sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
26492639
..Default::default()
26502640
};
@@ -2977,9 +2967,9 @@ mod tests {
29772967
sequence: Sequence::ZERO,
29782968
witness: Witness::new(),
29792969
};
2980-
(txin, TransactionU16LenLimited::new(tx).unwrap())
2970+
(txin, tx)
29812971
})
2982-
.collect::<Vec<(TxIn, TransactionU16LenLimited)>>();
2972+
.collect::<Vec<(TxIn, Transaction)>>();
29832973
let our_contributed = 110_000;
29842974
let txout = TxOut { value: Amount::from_sat(10_000), script_pubkey: ScriptBuf::new() };
29852975
let outputs = vec![txout];

0 commit comments

Comments
 (0)