Skip to content

Conversation

@d4mr
Copy link
Contributor

@d4mr d4mr commented Sep 24, 2025

Summary by CodeRabbit

  • New Features

    • Clearer webhook events for confirmed vs. replaced transactions, improving downstream handling and visibility.
  • Bug Fixes

    • Eliminated duplicate processing per transaction, reducing redundant actions and notifications.
    • Corrected pending count updates to reflect actual state changes only when applicable.
    • Improved cleanup to remove stale transaction data, preventing stuck “submitted” statuses.
    • Ensured consistent Redis cleanup for confirmed and NOOP transactions, and safer retention when nonces are ahead.
    • Clarified operational messages around propagation delays to aid troubleshooting.

@coderabbitai
Copy link

coderabbitai bot commented Sep 24, 2025

Walkthrough

Introduces per-transaction_id deduplication in the processing loop, moves Redis cleanup into a post-match block with scenario-based rules, updates webhook queuing messages and logic for confirmed/replaced paths, adjusts pending count increments, and refines diagnostics around flashblock propagation. No exported/public API changes.

Changes

Cohort / File(s) Summary
Submitted processing and cleanup logic
executors/src/eoa/store/submitted.rs
Added first-occurrence deduplication by transaction_id. Moved Redis cleanup after main match with explicit scenarios (confirmed, NOOP, nonce-based removal). Updated webhook queuing messages for confirmed vs. replaced. Tweaked replaced-path behavior and pending count increments. Clarified flashblock delay diagnostics.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant P as SubmittedProcessor
  participant R as Redis (hashes)
  participant C as Chain/Flashblock
  participant W as WebhookQueue

  Note over P: Per-transaction_id dedup (processed_ids)

  P->>P: Receive submitted tx event
  alt first occurrence
    P->>C: Evaluate status (confirmed/replaced/pending)
    opt Confirmed
      P->>W: Enqueue "confirmed" webhook
      rect rgba(200,255,200,0.3)
      Note right of P: Post-match cleanup (Scenario 1)
      P->>R: Remove all hashes for transaction_id
      end
    end
    opt Replaced
      P->>W: Enqueue "replaced" webhook
      rect rgba(200,200,255,0.3)
      Note right of P: Increment pending counts only when needed
      end
      rect rgba(240,240,200,0.5)
      Note right of P: Post-match cleanup (Scenario 2)
      P->>C: Get latest confirmed nonce
      alt nonce <= latest confirmed
        P->>R: Remove hashes
      else
        P->>R: Keep submitted hashes
      end
      end
    end
    opt NOOP
      P->>W: Enqueue NOOP-related message (if any)
      rect rgba(255,240,200,0.4)
      Note right of P: Always remove hashes for NOOP
      P->>R: Remove hashes
      end
    end
    Note over P,C: Diagnostics note for flashblock propagation delays
  else duplicate
    P-->>P: Skip business logic (already processed)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Fix duplicate submitted -> pending in case of gas bumped transactions" concisely describes the primary change: preventing duplicate submitted→pending state transitions when transactions are gas-bumped. It directly matches the reported code changes (deduplication and adjusted handling for replaced transactions) and is specific enough for a reviewer scanning PR history. The phrasing is clear and focused without unnecessary detail.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch pb/eoa-gas-bump-duplicate-fix

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
executors/src/eoa/store/submitted.rs (5)

342-346: Good per-transaction_id dedup; prefer owning Strings to avoid borrow-coupling.

Using HashSet<&str> ties lifetimes to the hydrated slice and can become brittle with future refactors. Owning IDs here is cheap and safer.

Apply:

-        let mut processed_ids = HashSet::new();
+        let mut processed_ids: HashSet<String> = HashSet::new();
...
-            let is_first_occurrence = processed_ids.insert(tx.transaction_id());
+            let is_first_occurrence = processed_ids.insert(tx.transaction_id().to_string());

392-392: Add structured fields to the error log.

Include transaction_id/chain_id for debuggability; avoid losing context.

-                                    tracing::error!("Failed to queue webhook for confirmed transaction: {}", e);
+                                    tracing::error!(
+                                        transaction_id = %event.transaction_id,
+                                        chain_id = self.keys.chain_id,
+                                        error = %e,
+                                        "Failed to queue webhook for confirmed transaction"
+                                    );

428-428: Add structured context to the replaced-webhook error log.

Same rationale as confirmed-path.

-                                        tracing::error!("Failed to queue webhook for replaced transaction: {}", e);
+                                        tracing::error!(
+                                            transaction_id = %event.transaction_id,
+                                            chain_id = self.keys.chain_id,
+                                            error = %e,
+                                            "Failed to queue webhook for replaced transaction"
+                                        );

452-471: Ensure cleanup prevents dual-state presence after moving to pending.

Augment the cleanup to always remove submitted hashes for ids moved to pending.

-            match (tx.transaction_id(), confirmed_ids.get(tx.transaction_id())) {
+            match (tx.transaction_id(), confirmed_ids.get(tx.transaction_id())) {
                 // SCENARIO 1: Transaction ID was confirmed - remove ALL hashes (even if beyond latest due to flashblocks)
                 (_, Some(_)) => {
                     self.remove_transaction_from_redis_submitted_zset(pipeline, tx);
                 }
                 // NOOP transactions: always clean up
                 (NO_OP_TRANSACTION_ID, _) => {
                     self.remove_transaction_from_redis_submitted_zset(pipeline, tx);
                 }
                 // SCENARIO 2: Transaction ID was NOT confirmed - only clean up if within latest confirmed nonce range
                 _ => {
-                    if let SubmittedTransactionHydrated::Real(_) = tx {
-                        if tx_nonce <= self.transaction_counts.latest {
+                    if let SubmittedTransactionHydrated::Real(_) = tx {
+                        // If this id was moved to pending, remove all its submitted hashes to avoid dual-state presence.
+                        if moved_to_pending_ids.contains(tx.transaction_id()) {
+                            self.remove_transaction_from_redis_submitted_zset(pipeline, tx);
+                        } else if tx_nonce <= self.transaction_counts.latest {
                             self.remove_transaction_from_redis_submitted_zset(pipeline, tx);
                         }
                         // If beyond latest confirmed nonce, keep in submitted state (don't clean up)
                     }
                 }
             }

Note: ensure moved_to_pending_ids is declared as suggested in the previous comment.


342-346: Redundant range gate.

Because validation already restricts submitted_txs to max(preconfirmed, latest), the should_process check is redundant. Removing it slightly simplifies control flow.

Also applies to: 400-447, 452-471

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 08bd0e1 and ba87295.

📒 Files selected for processing (1)
  • executors/src/eoa/store/submitted.rs (4 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-20T06:58:40.230Z
Learnt from: d4mr
PR: thirdweb-dev/engine-core#48
File: executors/src/eoa/store/submitted.rs:229-230
Timestamp: 2025-09-20T06:58:40.230Z
Learning: The diff in executors/src/eoa/store/submitted.rs shows correct brace structure - the first closing brace closes the remove_transaction_from_redis_submitted_zset method and the second closing brace closes the impl CleanSubmittedTransactions block. The change only adds whitespace formatting.

Applied to files:

  • executors/src/eoa/store/submitted.rs
🔇 Additional comments (2)
executors/src/eoa/store/submitted.rs (2)

352-399: Confirmed-path updates and metrics look correct.

Status/receipt writes, metrics, and webhook enqueue are coherently scoped to the first occurrence per transaction_id.


400-447: Prevent dual presence of transaction_id in pending + submitted

Moving a tx to pending while leaving other submitted hashes for the same transaction_id (nonce > latest) can cause duplicate downstream processing. Track ids moved to pending and remove all their submitted hashes (regardless of nonce).

Add near replaced_transactions:

// declare alongside `replaced_transactions`
let mut moved_to_pending_ids: HashSet<String> = HashSet::new();

Mark ids when pushing to pending (inside SCENARIO 2):

                                 replaced_transactions
                                     .push((tx.queued_at, tx.transaction_id.clone()));
+                                moved_to_pending_ids.insert(tx.transaction_id.clone());

Amend cleanup (see next comment) to remove all submitted hashes if id ∈ moved_to_pending_ids.

Confirm whether any consumers assume uniqueness of transaction_id across states; if so, this change is required before merge.

@d4mr d4mr merged commit 404dfe1 into main Sep 24, 2025
3 checks passed
@d4mr d4mr deleted the pb/eoa-gas-bump-duplicate-fix branch September 24, 2025 03:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants