Skip to content

Subscription improvement#838

Merged
FabijanC merged 11 commits intomainfrom
subscription-improvement
Sep 5, 2025
Merged

Subscription improvement#838
FabijanC merged 11 commits intomainfrom
subscription-improvement

Conversation

@FabijanC
Copy link
Copy Markdown
Contributor

@FabijanC FabijanC commented Sep 5, 2025

Usage related changes

  • Fix the issue described in https://spaceshard.slack.com/archives/C03031Y0LKC/p1756721004727039
    • Tx receipt notifications were missing block info when sent for txs in the latest/pre-confirmed block.
    • This is now suppressed for both starknet_subscribeNewTransactions and starknet_subscribeNewTransactionReceipts, i.e. notifications are sent only for future txs.
  • Subscription ID generation done in loop to ensure no duplicates/overwriting.
  • Add tracing for subscription responses
  • Bugfix: Add missing block_number to receipts of pre_confirmed txs

Development related changes

  • Improve tests.
  • Add TODOs that should be removed when starknet-rs updated for improved response deserialization.
  • Minor refactor: unsubscription simplification

Checklist:

  • Checked out the contribution guidelines
  • Applied formatting - ./scripts/format.sh
  • No linter errors - ./scripts/clippy_check.sh
  • No unused dependencies - ./scripts/check_unused_deps.sh
  • No spelling errors - ./scripts/check_spelling.sh
  • Performed code self-review
  • Rebased to the latest commit of the target branch (or merged it into my branch)
    • Once you make the PR reviewable, please avoid force-pushing
  • Updated the docs if needed - ./website/README.md
  • Linked the issues resolvable by this PR - linking info
  • Updated the tests if needed; all passing - execution info

Summary by CodeRabbit

  • Bug Fixes
    • Pre-confirmed transaction receipts now include the correct block number, ensuring consistent, deterministic metadata.
    • Subscribing to new transactions or receipts no longer triggers immediate backfill notifications; only future events are delivered.
  • Refactor
    • More reliable subscription management: unique ID generation and simplified unsubscribe flow.
    • Added trace logging for outgoing subscription responses.
  • Tests
    • Expanded coverage for transaction and receipt subscriptions, including multi-subscriber scenarios, deploy-account notifications, and block-aware receipt validation.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Sep 5, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

  • Pre-confirmation flow now sets transaction.block_number during pre_confirm, not during block assembly. pre_confirm signature updated to accept a BlockNumber.
  • handle_accepted_transaction passes the pre_confirmed block number into pre_confirm.
  • WebSocket endpoints for NewTransactions and NewTransactionReceipts no longer emit historical notifications upon subscription; they only subscribe.
  • Subscription ID creation now ensures uniqueness via a retry loop; send path logs serialized responses; unsubscribe simplified.
  • Tests updated and expanded: block-aware receipts for pre-confirmed txs, deployment notifications, combined tx/receipt subscriptions, multi-subscriber scenarios, and finality-status coverage. Two test helpers made public.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch subscription-improvement

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@FabijanC
Copy link
Copy Markdown
Contributor Author

FabijanC commented Sep 5, 2025

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Sep 5, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@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 (11)
crates/starknet-devnet-core/src/transactions.rs (2)

57-57: Remove stray TODO marker.

The previous #[allow(unused)] was intentionally dropped; the TODO comment is noise now. Delete it.

-// TODO #[allow(unused)]

70-76: Pass TransactionWithHash by value to avoid clone and strip the inline note.

Callers already own TransactionWithHash and compute the hash before passing it, so moving it eliminates an extra clone here.

-    pub fn pre_confirm(
-        transaction: &TransactionWithHash, // consider passing the object, not reference
+    pub fn pre_confirm(
+        transaction: TransactionWithHash,
         execution_info: TransactionExecutionInfo,
         trace: TransactionTrace,
         pre_confirmed_block_number: BlockNumber,
     ) -> Self {
         Self {
             finality_status: TransactionFinalityStatus::PreConfirmed,
@@
-            inner: transaction.clone(),
+            inner: transaction,

Also update call sites (examples):

  • crates/starknet-devnet-core/src/starknet/mod.rs (Lines 451–456): pass transaction (no &).
  • Tests in this file (Lines 279, 289, 312): pass tx.clone() to keep later equality checks using tx. See patch below for tests.
-        let sn_tx = StarknetTransaction::pre_confirm(
-            &tx,
+        let sn_tx = StarknetTransaction::pre_confirm(
+            tx.clone(),
             TransactionExecutionInfo::default(),
             trace.clone(),
             block_number,
         );
@@
-            StarknetTransaction::pre_confirm(
-                &tx,
+            StarknetTransaction::pre_confirm(
+                tx.clone(),
                 TransactionExecutionInfo::default(),
                 trace,
                 block_number,
             ),
@@
-        let sn_tran = StarknetTransaction::pre_confirm(
-            &tx,
+        let sn_tran = StarknetTransaction::pre_confirm(
+            tx.clone(),
             TransactionExecutionInfo::default(),
             trace,
             block_number,
         );
crates/starknet-devnet-core/src/starknet/mod.rs (2)

392-400: Optional invariant check: ensure tx.block_number matches the finalized block.

Block number is now set during pre_confirm; add a debug assertion here to guard against future divergence.

-        // update block hash for each pre_confirmed tx; block number should already be set
+        // update block hash for each pre_confirmed tx; block number should already be set
         new_block.get_transactions().iter().for_each(|tx_hash| {
             if let Some(tx) = self.transactions.get_by_hash_mut(tx_hash) {
+                debug_assert_eq!(
+                    tx.block_number,
+                    Some(new_block_number),
+                    "pre_confirmed tx has block_number {:?}, expected {:?}",
+                    tx.block_number,
+                    new_block_number
+                );
                 tx.block_hash = Some(new_block_hash);
                 tx.finality_status = TransactionFinalityStatus::AcceptedOnL2;
             } else {
                 error!("Transaction is not present in the transactions collection");
             }
         });

451-456: If adopting pass-by-value, update this call.

Drop & to avoid cloning in pre_confirm.

-        let transaction_to_add = StarknetTransaction::pre_confirm(
-            &transaction,
+        let transaction_to_add = StarknetTransaction::pre_confirm(
+            transaction,
             tx_info,
             trace,
             self.blocks.pre_confirmed_block.block_number(),
         );
crates/starknet-devnet-server/src/subscribe.rs (2)

332-336: Use structured tracing for cheaper logging.

Avoid string interpolation in the message; emit as a field to keep formatting lazy and searchable.

-        tracing::trace!("Subscription response: {resp_serialized}");
+        tracing::trace!(target: "ws.subscriptions", response = %resp_serialized, "subscription response");

367-374: Confirm unsubscribe API semantics (error vs. false) and consider idempotency.

Changing missing-ID behavior to ApiError::InvalidSubscriptionId alters the contract; many WS APIs return result=false instead. If you prefer idempotent unsubscribe, consider this tweak.

-        self.subscriptions.remove(&subscription_id).ok_or(ApiError::InvalidSubscriptionId)?;
-        self.send(SubscriptionResponse::Confirmation {
-            rpc_request_id,
-            result: SubscriptionConfirmation::Unsubscription(true),
-        })
+        let ok = self.subscriptions.remove(&subscription_id).is_some();
+        self.send(SubscriptionResponse::Confirmation {
+            rpc_request_id,
+            result: SubscriptionConfirmation::Unsubscription(ok),
+        })
             .await;
         Ok(())
crates/starknet-devnet-server/src/api/json_rpc/endpoints_ws.rs (2)

142-166: NewTx subscriptions now “future-only” — LGTM; drop unnecessary clone.

Behavior aligns with PR goal (no pre-population). Minor nit: StatusFilter is moved; cloning is unnecessary.

-        let subscription =
-            Subscription::NewTransactions { address_filter, status_filter: status_filter.clone() };
+        let subscription =
+            Subscription::NewTransactions { address_filter, status_filter };

189-205: Receipts subscriptions also “future-only” — LGTM; drop unnecessary clone.

Same clone nit as above.

-        let subscription = Subscription::NewTransactionReceipts {
-            address_filter,
-            status_filter: status_filter.clone(),
-        };
+        let subscription = Subscription::NewTransactionReceipts {
+            address_filter,
+            status_filter,
+        };
tests/integration/test_subscription_to_new_txs.rs (2)

23-35: Make shared WS helpers a common module to decouple tests.

These helpers are reused across integration tests; consider moving them under tests/common (e.g., tests/common/ws.rs) and importing from there to avoid inter-test coupling.


121-144: Unsubscribe flow looks stable; tiny robustness tweak optional.

Draining one WS message before unsubscribe helps ordering. If flakes surface, consider draining all pending messages (with a short timeout) before asserting the unsubscribe ack.

tests/integration/test_subscription_to_new_tx_receipts.rs (1)

161-181: Guard against out-of-order notifications when subscribing to both streams.

TX and receipt events can interleave. If flakes appear, read two messages per iteration and branch by method instead of assuming TX arrives first.

-        let tx_raw = receive_new_tx(&mut ws, tx_subscription_id.clone()).await.unwrap();
+        // Read until we have both a tx and a receipt for this iteration
+        let mut maybe_tx: Option<serde_json::Value> = None;
+        let mut maybe_receipt: Option<serde_json::Value> = None;
+        while maybe_tx.is_none() || maybe_receipt.is_none() {
+            // Try TX first, then receipt; ignore non-matching messages
+            if maybe_tx.is_none() {
+                if let Ok(val) = receive_new_tx(&mut ws, tx_subscription_id.clone()).await {
+                    maybe_tx = Some(val);
+                    continue;
+                }
+            }
+            if maybe_receipt.is_none() {
+                if let Ok(val) = receive_new_tx_receipt(&mut ws, receipt_subscription_id.clone()).await {
+                    maybe_receipt = Some(val);
+                }
+            }
+        }
+        let tx_raw = maybe_tx.unwrap();
+        let receipt_raw = maybe_receipt.unwrap();
-        let receipt_raw =
-            receive_new_tx_receipt(&mut ws, receipt_subscription_id.clone()).await.unwrap();
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 c0d931e and cad3384.

📒 Files selected for processing (7)
  • crates/starknet-devnet-core/src/starknet/mod.rs (3 hunks)
  • crates/starknet-devnet-core/src/transactions.rs (6 hunks)
  • crates/starknet-devnet-server/src/api/json_rpc/endpoints_ws.rs (4 hunks)
  • crates/starknet-devnet-server/src/subscribe.rs (2 hunks)
  • tests/integration/test_subscription_to_events.rs (1 hunks)
  • tests/integration/test_subscription_to_new_tx_receipts.rs (7 hunks)
  • tests/integration/test_subscription_to_new_txs.rs (6 hunks)
🔇 Additional comments (9)
crates/starknet-devnet-core/src/transactions.rs (2)

90-93: Good: set block_number at pre-confirm time.

This fixes missing block_number in pre-confirmed receipts and aligns with block-context semantics.


278-285: Tests correctly assert block_number propagation.

Assertions match the new pre_confirm semantics and protect against regressions.

Also applies to: 288-294, 310-316, 321-321

crates/starknet-devnet-core/src/starknet/mod.rs (2)

2154-2154: Test update LGTM.

Receipt now includes Some(BlockNumber(..)) for pre-confirmed txs; assertion is correct.


451-456: All pre_confirm calls include the block number and no block_number assignments overwrite the pre‐confirmed value.

tests/integration/test_subscription_to_events.rs (1)

81-81: Good defensive assertion.

Ensures deployed contract address differs from the account address; avoids false positives in event filtering.

crates/starknet-devnet-server/src/subscribe.rs (1)

346-360: Good: collision-safe subscription ID generation.

The retry loop eliminates overwrite risk, and using u64 makes collisions practically impossible per-socket. Looks good.

tests/integration/test_subscription_to_new_txs.rs (1)

337-354: Deploy-account TX notification test — LGTM.

Using raw JSON field until starknet-rs 0.17 lands is a pragmatic choice.

tests/integration/test_subscription_to_new_tx_receipts.rs (2)

25-26: TODO placement is fine.

Agree to extend deserialization once starknet-rs 0.17 is in; current scope is appropriate.


388-408: Deploy-account receipt with block info — LGTM.

Asserting transaction_hash via TransactionReceiptWithBlockInfo matches the intended server payload.

@FabijanC FabijanC merged commit 427b391 into main Sep 5, 2025
2 checks passed
@FabijanC FabijanC deleted the subscription-improvement branch September 5, 2025 11:56
@coderabbitai coderabbitai bot mentioned this pull request Sep 16, 2025
10 tasks
@coderabbitai coderabbitai bot mentioned this pull request Mar 13, 2026
10 tasks
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.

1 participant