@@ -339,21 +339,18 @@ impl SafeRedisTransaction for CleanSubmittedTransactions<'_> {
339
339
continue ;
340
340
}
341
341
342
- // Process each unique transaction_id once
343
- if processed_ids. insert ( tx. transaction_id ( ) ) {
342
+ // Do business logic only once per unique transaction_id
343
+ let is_first_occurrence = processed_ids. insert ( tx. transaction_id ( ) ) ;
344
+
345
+ if is_first_occurrence {
344
346
match ( tx. transaction_id ( ) , confirmed_ids. get ( tx. transaction_id ( ) ) ) {
345
347
// if the transaction id is noop, we don't do anything but still clean up
346
348
( NO_OP_TRANSACTION_ID , _) => {
347
- // Clean up noop transaction from Redis
348
- self . remove_transaction_from_redis_submitted_zset ( pipeline, tx) ;
349
349
report. noop_count += 1 ;
350
350
}
351
351
352
- // in case of a valid ID, we check if it's in the confirmed transactions
353
- // if it is confirmed, we succeed it and queue success jobs
352
+ // SCENARIO 1: Transaction ID was confirmed - do confirmed business logic
354
353
( id, Some ( confirmed_tx) ) => {
355
- // Clean up confirmed transaction from Redis
356
- self . remove_transaction_from_redis_submitted_zset ( pipeline, tx) ;
357
354
let data_key_name = self . keys . transaction_data_key_name ( id) ;
358
355
pipeline. hset ( & data_key_name, "status" , "confirmed" ) ;
359
356
pipeline. hset ( & data_key_name, "completed_at" , now) ;
@@ -392,26 +389,20 @@ impl SafeRedisTransaction for CleanSubmittedTransactions<'_> {
392
389
& mut tx_context,
393
390
self . webhook_queue . clone ( ) ,
394
391
) {
395
- tracing:: error!( "Failed to queue webhook for fail : {}" , e) ;
392
+ tracing:: error!( "Failed to queue webhook for confirmed transaction : {}" , e) ;
396
393
}
397
394
}
398
395
}
399
396
400
397
report. moved_to_success += 1 ;
401
398
}
402
399
403
- // if the ID is not in the confirmed transactions, we queue it for pending
400
+ // SCENARIO 2: Transaction ID was NOT confirmed - check if we should replace it
404
401
_ => {
405
402
if let SubmittedTransactionHydrated :: Real ( tx) = tx {
406
403
// Only move to pending (replaced) if it's within the latest transaction count range
407
404
// This prevents false replacements due to flashblocks propagation delays
408
405
if tx_nonce <= self . transaction_counts . latest {
409
- // Clean up replaced transaction from Redis
410
- self . remove_transaction_from_redis_submitted_zset (
411
- pipeline,
412
- & SubmittedTransactionHydrated :: Real ( tx. clone ( ) ) ,
413
- ) ;
414
-
415
406
// zadd_multiple expects (score, member)
416
407
replaced_transactions
417
408
. push ( ( tx. queued_at , tx. transaction_id . clone ( ) ) ) ;
@@ -434,7 +425,7 @@ impl SafeRedisTransaction for CleanSubmittedTransactions<'_> {
434
425
& mut tx_context,
435
426
self . webhook_queue . clone ( ) ,
436
427
) {
437
- tracing:: error!( "Failed to queue webhook for fail : {}" , e) ;
428
+ tracing:: error!( "Failed to queue webhook for replaced transaction : {}" , e) ;
438
429
}
439
430
}
440
431
@@ -451,11 +442,33 @@ impl SafeRedisTransaction for CleanSubmittedTransactions<'_> {
451
442
"Keeping transaction in submitted state due to potential flashblocks propagation delay"
452
443
) ;
453
444
// Don't increment any counter - transaction stays in submitted state
445
+ // Note: We still need to check if we should clean up this hash below
454
446
}
455
447
}
456
448
}
457
449
}
458
450
}
451
+
452
+ // Redis cleanup logic: Clean up hashes based on transaction-level decisions
453
+ match ( tx. transaction_id ( ) , confirmed_ids. get ( tx. transaction_id ( ) ) ) {
454
+ // SCENARIO 1: Transaction ID was confirmed - remove ALL hashes (even if beyond latest due to flashblocks)
455
+ ( _, Some ( _) ) => {
456
+ self . remove_transaction_from_redis_submitted_zset ( pipeline, tx) ;
457
+ }
458
+ // NOOP transactions: always clean up
459
+ ( NO_OP_TRANSACTION_ID , _) => {
460
+ self . remove_transaction_from_redis_submitted_zset ( pipeline, tx) ;
461
+ }
462
+ // SCENARIO 2: Transaction ID was NOT confirmed - only clean up if within latest confirmed nonce range
463
+ _ => {
464
+ if let SubmittedTransactionHydrated :: Real ( _) = tx {
465
+ if tx_nonce <= self . transaction_counts . latest {
466
+ self . remove_transaction_from_redis_submitted_zset ( pipeline, tx) ;
467
+ }
468
+ // If beyond latest confirmed nonce, keep in submitted state (don't clean up)
469
+ }
470
+ }
471
+ }
459
472
}
460
473
461
474
if !replaced_transactions. is_empty ( ) {
0 commit comments