@@ -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 let Some ( shared_funding_input) = & context. shared_funding_input {
288
315
if !tx. tx . input . iter ( ) . any ( |txin| {
289
316
txin. previous_output == shared_funding_input. input . previous_output
@@ -889,6 +916,18 @@ impl NegotiationContext {
889
916
)
890
917
}
891
918
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
+
892
931
fn remote_outputs_weight ( & self ) -> Weight {
893
932
Weight :: from_wu (
894
933
self . outputs
@@ -1191,52 +1230,6 @@ impl NegotiationContext {
1191
1230
self . outputs . remove ( & msg. serial_id ) ;
1192
1231
Ok ( ( ) )
1193
1232
}
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
- }
1240
1233
}
1241
1234
1242
1235
// The interactive transaction construction protocol allows two peers to collaboratively build a
@@ -1375,7 +1368,7 @@ macro_rules! define_state_transitions {
1375
1368
let holder_node_id = context. holder_node_id;
1376
1369
let counterparty_node_id = context. counterparty_node_id;
1377
1370
1378
- let tx = context . validate_tx ( ) ?;
1371
+ let tx = ConstructedTransaction :: new ( context ) ?;
1379
1372
1380
1373
// Strict ordering prevents deadlocks during tx_signatures exchange
1381
1374
let local_contributed_input_value = tx. local_contributed_input_value( ) ;
0 commit comments