@@ -248,6 +248,10 @@ impl_writeable_tlv_based!(ConstructedTransaction, {
248
248
249
249
impl ConstructedTransaction {
250
250
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
+
251
255
let satisfaction_weight =
252
256
Weight :: from_wu ( context. inputs . iter ( ) . fold ( 0u64 , |value, ( _, input) | {
253
257
value. saturating_add ( input. satisfaction_weight ( ) . to_wu ( ) )
@@ -284,6 +288,29 @@ impl ConstructedTransaction {
284
288
shared_input_index,
285
289
} ;
286
290
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
+
287
314
if context. shared_funding_input . is_some ( ) && tx. shared_input_index . is_none ( ) {
288
315
return Err ( AbortReason :: MissingFundingInput ) ;
289
316
}
@@ -886,6 +913,18 @@ impl NegotiationContext {
886
913
)
887
914
}
888
915
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
+
889
928
fn remote_outputs_weight ( & self ) -> Weight {
890
929
Weight :: from_wu (
891
930
self . outputs
@@ -1188,52 +1227,6 @@ impl NegotiationContext {
1188
1227
self . outputs . remove ( & msg. serial_id ) ;
1189
1228
Ok ( ( ) )
1190
1229
}
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
- }
1237
1230
}
1238
1231
1239
1232
// The interactive transaction construction protocol allows two peers to collaboratively build a
@@ -1372,7 +1365,7 @@ macro_rules! define_state_transitions {
1372
1365
let holder_node_id = context. holder_node_id;
1373
1366
let counterparty_node_id = context. counterparty_node_id;
1374
1367
1375
- let tx = context . validate_tx ( ) ?;
1368
+ let tx = ConstructedTransaction :: new ( context ) ?;
1376
1369
1377
1370
// Strict ordering prevents deadlocks during tx_signatures exchange
1378
1371
let local_contributed_input_value = tx. local_contributed_input_value( ) ;
0 commit comments