Skip to content

Commit 89e1f33

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 9c4cb91 commit 89e1f33

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 context.shared_funding_input.is_some() && tx.shared_input_index.is_none() {
288315
return Err(AbortReason::MissingFundingInput);
289316
}
@@ -886,6 +913,18 @@ impl NegotiationContext {
886913
)
887914
}
888915

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

12391232
// The interactive transaction construction protocol allows two peers to collaboratively build a
@@ -1372,7 +1365,7 @@ macro_rules! define_state_transitions {
13721365
let holder_node_id = context.holder_node_id;
13731366
let counterparty_node_id = context.counterparty_node_id;
13741367

1375-
let tx = context.validate_tx()?;
1368+
let tx = ConstructedTransaction::new(context)?;
13761369

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

0 commit comments

Comments
 (0)