Skip to content

Commit 8ed27b0

Browse files
committed
Move NegotiationContext checks into ConstructedTransaction
Both NegotiationContext::validate_tx and ConstructedTransaction::new contain validity checks. Move the former into the latter in order to consolidate the checks in a single place. This will also allow for reusing error construction in an upcoming commit.
1 parent 6473fc6 commit 8ed27b0

File tree

1 file changed

+40
-47
lines changed

1 file changed

+40
-47
lines changed

lightning/src/ln/interactivetxs.rs

Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,10 @@ impl_writeable_tlv_based!(ConstructedTransaction, {
248248

249249
impl ConstructedTransaction {
250250
fn new(context: NegotiationContext) -> Result<Self, AbortReason> {
251+
let remote_inputs_value = context.remote_inputs_value();
252+
let remote_outputs_value = context.remote_outputs_value();
253+
let remote_weight_contributed = context.remote_weight_contributed();
254+
251255
let satisfaction_weight =
252256
Weight::from_wu(context.inputs.iter().fold(0u64, |value, (_, input)| {
253257
value.saturating_add(input.satisfaction_weight().to_wu())
@@ -284,6 +288,29 @@ impl ConstructedTransaction {
284288
shared_input_index,
285289
};
286290

291+
// The receiving node:
292+
// MUST fail the negotiation if:
293+
// - the peer's total input satoshis is less than their outputs
294+
if remote_inputs_value < remote_outputs_value {
295+
return Err(AbortReason::OutputsValueExceedsInputsValue);
296+
}
297+
298+
// - the peer's paid feerate does not meet or exceed the agreed feerate (based on the minimum fee).
299+
let remote_fees_contributed = remote_inputs_value.saturating_sub(remote_outputs_value);
300+
let required_remote_contribution_fee =
301+
fee_for_weight(context.feerate_sat_per_kw, remote_weight_contributed);
302+
if remote_fees_contributed < required_remote_contribution_fee {
303+
return Err(AbortReason::InsufficientFees);
304+
}
305+
306+
// - there are more than 252 inputs
307+
// - there are more than 252 outputs
308+
if tx.tx.input.len() > MAX_INPUTS_OUTPUTS_COUNT
309+
|| tx.tx.output.len() > MAX_INPUTS_OUTPUTS_COUNT
310+
{
311+
return Err(AbortReason::ExceededNumberOfInputsOrOutputs);
312+
}
313+
287314
if let Some(shared_funding_input) = &context.shared_funding_input {
288315
if !tx.tx.input.iter().any(|txin| {
289316
txin.previous_output == shared_funding_input.input.previous_output
@@ -889,6 +916,18 @@ impl NegotiationContext {
889916
)
890917
}
891918

919+
fn remote_weight_contributed(&self) -> u64 {
920+
self.remote_inputs_weight()
921+
.to_wu()
922+
.saturating_add(self.remote_outputs_weight().to_wu())
923+
// The receiving node:
924+
// - MUST fail the negotiation if
925+
// - if is the non-initiator:
926+
// - the initiator's fees do not cover the common fields (version, segwit marker + flag,
927+
// input count, output count, locktime)
928+
.saturating_add(if !self.holder_is_initiator { TX_COMMON_FIELDS_WEIGHT } else { 0 })
929+
}
930+
892931
fn remote_outputs_weight(&self) -> Weight {
893932
Weight::from_wu(
894933
self.outputs
@@ -1191,52 +1230,6 @@ impl NegotiationContext {
11911230
self.outputs.remove(&msg.serial_id);
11921231
Ok(())
11931232
}
1194-
1195-
fn check_counterparty_fees(
1196-
&self, counterparty_fees_contributed: u64,
1197-
) -> Result<(), AbortReason> {
1198-
let mut counterparty_weight_contributed = self
1199-
.remote_inputs_weight()
1200-
.to_wu()
1201-
.saturating_add(self.remote_outputs_weight().to_wu());
1202-
if !self.holder_is_initiator {
1203-
// if is the non-initiator:
1204-
// - the initiator's fees do not cover the common fields (version, segwit marker + flag,
1205-
// input count, output count, locktime)
1206-
counterparty_weight_contributed += TX_COMMON_FIELDS_WEIGHT;
1207-
}
1208-
let required_counterparty_contribution_fee =
1209-
fee_for_weight(self.feerate_sat_per_kw, counterparty_weight_contributed);
1210-
if counterparty_fees_contributed < required_counterparty_contribution_fee {
1211-
return Err(AbortReason::InsufficientFees);
1212-
}
1213-
Ok(())
1214-
}
1215-
1216-
fn validate_tx(self) -> Result<ConstructedTransaction, AbortReason> {
1217-
// The receiving node:
1218-
// MUST fail the negotiation if:
1219-
1220-
// - the peer's total input satoshis is less than their outputs
1221-
let remote_inputs_value = self.remote_inputs_value();
1222-
let remote_outputs_value = self.remote_outputs_value();
1223-
if remote_inputs_value < remote_outputs_value {
1224-
return Err(AbortReason::OutputsValueExceedsInputsValue);
1225-
}
1226-
1227-
// - there are more than 252 inputs
1228-
// - there are more than 252 outputs
1229-
if self.inputs.len() > MAX_INPUTS_OUTPUTS_COUNT
1230-
|| self.outputs.len() > MAX_INPUTS_OUTPUTS_COUNT
1231-
{
1232-
return Err(AbortReason::ExceededNumberOfInputsOrOutputs);
1233-
}
1234-
1235-
// - the peer's paid feerate does not meet or exceed the agreed feerate (based on the minimum fee).
1236-
self.check_counterparty_fees(remote_inputs_value.saturating_sub(remote_outputs_value))?;
1237-
1238-
ConstructedTransaction::new(self)
1239-
}
12401233
}
12411234

12421235
// The interactive transaction construction protocol allows two peers to collaboratively build a
@@ -1375,7 +1368,7 @@ macro_rules! define_state_transitions {
13751368
let holder_node_id = context.holder_node_id;
13761369
let counterparty_node_id = context.counterparty_node_id;
13771370

1378-
let tx = context.validate_tx()?;
1371+
let tx = ConstructedTransaction::new(context)?;
13791372

13801373
// Strict ordering prevents deadlocks during tx_signatures exchange
13811374
let local_contributed_input_value = tx.local_contributed_input_value();

0 commit comments

Comments
 (0)