Conversation
* next: with_tx_details_and_filtered_address_happy_path * [skip ci]
…ithout L1; test_spec_methods passing
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughAdds finality-awareness across events and subscriptions. Core: get_events gains finality_status_filter and applies runtime filtering by TransactionFinalityStatus. Starknet API propagates this parameter. WebSocket JSON-RPC replaces PendingTransactions with NewTransactions and NewTransactionReceipts, introduces new subscription input types, and wraps emitted events in SubscriptionEmittedEvent carrying finality_status. Broadcasting paths and handlers updated to emit finality-tagged notifications for pre-confirmed and latest blocks. Types: TransactionFinalityStatus extended and made orderable; helpers added for sender address and receipt finality. RPC spec version bumped to 0.9.0. Postman endpoint lock handling adjusted. Extensive integration tests updated/added; pending-txs tests removed. Estimated code review effort🎯 5 (Critical) | ⏱️ ~120–180 minutes Possibly related PRs
✨ Finishing Touches🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/starknet-devnet-server/src/api/json_rpc/mod.rs (1)
259-321: Avoid holding the Starknet lock across awaits; also handle N>1 new pre-confirmed txs.Two issues:
- The
starknetmutex guard remains held until afternotify_subscribers(...).await. Holding locks across.awaithurts concurrency and can cause priority inversions.- If multiple txs enter the pre-confirmed block in one mutation, only the last is broadcast.
Address both by iterating the delta slice and dropping the lock before notifying:
async fn broadcast_pre_confirmed_tx_changes( &self, old_pre_confirmed_block: StarknetBlock, ) -> Result<(), error::ApiError> { let new_pre_confirmed_block = self.get_block_by_tag(BlockTag::PreConfirmed).await; let old_pre_confirmed_txs = old_pre_confirmed_block.get_transactions(); let new_pre_confirmed_txs = new_pre_confirmed_block.get_transactions(); - if new_pre_confirmed_txs.len() > old_pre_confirmed_txs.len() { - #[allow(clippy::expect_used)] - let new_tx_hash = new_pre_confirmed_txs.last().expect("has at least one element"); - - let mut notifications = vec![]; - let starknet = self.api.starknet.lock().await; + if new_pre_confirmed_txs.len() > old_pre_confirmed_txs.len() { + let mut notifications = vec![]; + let old_len = old_pre_confirmed_txs.len(); + let starknet = self.api.starknet.lock().await; - let status = starknet - .get_transaction_execution_and_finality_status(*new_tx_hash) - .map_err(error::ApiError::StarknetDevnetError)?; - notifications.push(NotificationData::TransactionStatus(NewTransactionStatus { - transaction_hash: *new_tx_hash, - status, - })); - - let tx = starknet - .get_transaction_by_hash(*new_tx_hash) - .map_err(error::ApiError::StarknetDevnetError)?; - notifications.push(NotificationData::NewTransaction(NewTransactionNotification { - tx: tx.clone(), - finality_status: TransactionFinalityStatus::PreConfirmed, - })); - - let receipt = starknet - .get_transaction_receipt_by_hash(new_tx_hash) - .map_err(error::ApiError::StarknetDevnetError)?; - notifications.push(NotificationData::NewTransactionReceipt( - NewTransactionReceiptNotification { - tx_receipt: receipt, - sender_address: tx.get_sender_address(), - }, - )); - - let events = starknet.get_unlimited_events( - Some(BlockId::Tag(BlockTag::PreConfirmed)), - Some(BlockId::Tag(BlockTag::PreConfirmed)), - None, - None, - None, // pre-confirmed block only has pre-confirmed txs - )?; - for emitted_event in events.into_iter().filter(|e| &e.transaction_hash == new_tx_hash) { - let subscription_event = SubscriptionEmittedEvent { - emitted_event, - // pre-confirmed block only has pre-confirmed txs - finality_status: TransactionFinalityStatus::PreConfirmed, - }; - notifications.push(NotificationData::Event(subscription_event)); - } - - self.api.sockets.lock().await.notify_subscribers(¬ifications).await; + for new_tx_hash in &new_pre_confirmed_txs[old_len..] { + let status = starknet + .get_transaction_execution_and_finality_status(*new_tx_hash) + .map_err(error::ApiError::StarknetDevnetError)?; + notifications.push(NotificationData::TransactionStatus(NewTransactionStatus { + transaction_hash: *new_tx_hash, + status, + })); + + let tx = starknet + .get_transaction_by_hash(*new_tx_hash) + .map_err(error::ApiError::StarknetDevnetError)?; + notifications.push(NotificationData::NewTransaction(NewTransactionNotification { + tx: tx.clone(), + finality_status: TransactionFinalityStatus::PreConfirmed, + })); + + let receipt = starknet + .get_transaction_receipt_by_hash(new_tx_hash) + .map_err(error::ApiError::StarknetDevnetError)?; + notifications.push(NotificationData::NewTransactionReceipt( + NewTransactionReceiptNotification { + tx_receipt: receipt, + sender_address: tx.get_sender_address(), + }, + )); + + let events = starknet.get_unlimited_events( + Some(BlockId::Tag(BlockTag::PreConfirmed)), + Some(BlockId::Tag(BlockTag::PreConfirmed)), + None, + None, + None, // pre-confirmed block only has pre-confirmed txs + )?; + for emitted_event in events.into_iter().filter(|e| &e.transaction_hash == new_tx_hash) + { + notifications.push(NotificationData::Event(SubscriptionEmittedEvent { + emitted_event, + finality_status: TransactionFinalityStatus::PreConfirmed, + })); + } + } + drop(starknet); // release before awaiting I/O + self.api.sockets.lock().await.notify_subscribers(¬ifications).await; } Ok(()) }
🧹 Nitpick comments (21)
crates/starknet-devnet-server/src/api/http/endpoints/postman.rs (2)
75-81: Make lock release explicit; clarify the comment to reference the lock guard.The chained call holds the Starknet lock until fetch_messages_to_l2().await completes (which is fine), and then drops it before executing RPCs. To make this intent unambiguous and resilient to future edits, consider scoping the guard explicitly and rewording the comment to reference the lock guard rather than api.starknet.
Apply this diff to scope the lock and clarify the comment:
- // It is important that api.starknet is dropped immediately to allow rpc execution - messages_to_l2 = api.starknet.lock().await.fetch_messages_to_l2().await.map_err(|e| { - ApiError::RpcError(RpcError::internal_error_with(format!( - "Error in fetching messages to L2: {e}" - ))) - })?; + // Important: acquire a short-lived Starknet lock only to fetch messages; + // drop it before executing JSON-RPC calls to avoid deadlocks. + { + let mut starknet = api.starknet.lock().await; + messages_to_l2 = starknet.fetch_messages_to_l2().await.map_err(|e| { + ApiError::RpcError(RpcError::internal_error_with(format!( + "Error in fetching messages to L2: {e}" + ))) + })?; + } // lock dropped here
95-111: Tighten Starknet lock around L1 calls & confirm dry-run side effects
collect_messages_to_l1mutates internal state (it extendsl2_to_l1_messages_to_flushand advanceslast_local_block). In dry-run mode this will enqueue messages and bump the block pointer—please confirm this behavior is intended.- Reduce the scope of
api.starknet.lock().awaitto only each async operation (collect, send, get_ethereum_url) to minimize mutex contention around potentially slow network calls.Suggested refactor:
- let mut starknet = api.starknet.lock().await; - let messages_to_l1 = starknet.collect_messages_to_l1().await.map_err(|e| { - ApiError::RpcError(RpcError::internal_error_with(format!( - "Error in collecting messages to L1: {e}" - ))) - })?; - - let l1_provider = if is_dry_run { - "dry run".to_string() - } else { - starknet.send_messages_to_l1().await.map_err(|e| { - ApiError::RpcError(RpcError::internal_error_with(format!( - "Error in sending messages to L1: {e}" - ))) - })?; - starknet.get_ethereum_url().unwrap_or("Not set".to_string()) - }; + // Lock only for collecting messages + let messages_to_l1 = { + let mut starknet = api.starknet.lock().await; + starknet.collect_messages_to_l1().await.map_err(|e| { + ApiError::RpcError(RpcError::internal_error_with(format!( + "Error in collecting messages to L1: {e}" + ))) + })? + }; + + let l1_provider = if is_dry_run { + "dry run".to_string() + } else { + // Lock only for sending + { + let mut starknet = api.starknet.lock().await; + starknet.send_messages_to_l1().await.map_err(|e| { + ApiError::RpcError(RpcError::internal_error_with(format!( + "Error in sending messages to L1: {e}" + ))) + })?; + } + // Short lock just to read the URL + api.starknet + .lock() + .await + .get_ethereum_url() + .unwrap_or_else(|| "Not set".to_string()) + };website/docs/intro.md (2)
18-25: Tighten phrasing and punctuation in the new finality semantics bullets.Minor grammar/punctuation issues. Suggest:
- End the last bullet with a period, not a comma.
Apply this minimal fix:
- - Transactions are never automatically `ACCEPTED_ON_L1`, unless the user performs an action, + - Transactions are never automatically `ACCEPTED_ON_L1` unless the user performs an action.
14-17: Typos: “transactions” singular and “free” → “fee”.Two small nits above the changed block for clarity:
- - By default, a new block is mined for each new transactions. + - By default, a new block is mined for each new transaction. - This can be modified by directing all new transactions into a pre-confirmed block, and at some point triggering block creation. - - Transactions in a pre-confirmed block cannot be replaced by sending a transaction with a higher free from the same account. + - Transactions in a pre-confirmed block cannot be replaced by sending a transaction with a higher fee from the same account.crates/starknet-devnet-types/src/rpc/transaction_receipt.rs (1)
39-49: Consider returning the finality status by value to avoid tying callers to a borrowIf TransactionFinalityStatus is Clone (likely) or Copy, returning by value improves ergonomics and avoids exposing an internal borrow.
Apply this diff if acceptable:
-impl TransactionReceipt { - pub fn finality_status(&self) -> &TransactionFinalityStatus { +impl TransactionReceipt { + pub fn finality_status(&self) -> TransactionFinalityStatus { let common = match self { TransactionReceipt::Deploy(receipt) => &receipt.common, TransactionReceipt::L1Handler(receipt) => &receipt.common, TransactionReceipt::Common(common) => common, }; - &common.finality_status + common.finality_status.clone() } }crates/starknet-devnet-core/src/starknet/mod.rs (1)
1201-1222: get_events now supports finality filtering — consider an options struct to reduce arg countFunctionally correct. To avoid growing argument lists and the need for allow(too_many_arguments), consider introducing a GetEventsOptions struct to carry address/keys/finality/skip/limit in a single parameter.
crates/starknet-devnet-types/src/rpc/transactions.rs (2)
105-114: Clarify semantics of get_sender_address across variants (especially Deploy/DeployAccount).The mapping looks correct w.r.t. how we surface “sender”:
- Declare/Invoke: actual sender_address
- DeployAccount: derived contract address
- L1Handler: contract handling the L1 message
- Deploy: None
To avoid ambiguity for downstream users, please document this contract explicitly at the API point.
Apply this inline doc to make the intent unambiguous:
impl Transaction { + /// Returns the logical initiator address for the transaction: + /// - DECLARE / INVOKE: the `sender_address` + /// - DEPLOY_ACCOUNT: the derived `contract_address` of the deployed account + /// - L1_HANDLER: the `contract_address` handling the message + /// - DEPLOY: `None` (no L2 sender) pub fn gas_vector_computation_mode(&self) -> GasVectorComputationMode {
1024-1032: Be explicit about ordering semantics for TransactionFinalityStatus and update affected documentation• In
crates/starknet-devnet-types/src/rpc/transactions.rs, add a doc comment above the enum to spell out the ascending progression and guard against variant reordering.
• (Optional) Add a unit test that asserts the expected ordering, e.g.:#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Copy)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] +/// Finality progresses in ascending order as declared below; do not reorder +/// without adjusting comparisons relying on `PartialOrd`: +/// RECEIVED < CANDIDATE < PRE_CONFIRMED < ACCEPTED_ON_L2 < ACCEPTED_ON_L1 pub enum TransactionFinalityStatus { Received, Candidate, PreConfirmed, AcceptedOnL2, AcceptedOnL1, }• Update the docs in
website/docs/intro.md(around line 21) to remove the legacy “PENDING” reference and simply describe the new status:- - `PRE_CONFIRMED` behaves like the old `PENDING` status - it is the status assigned to the transactions in a pre-confirmed block, which is a precursor to a stable latest block. + - `PRE_CONFIRMED` is the status assigned to transactions in a pre-confirmed block, which is a precursor to a stable latest block.• You can re-run the provided script to ensure no other “Pending…” references remain:
rg -n -C2 -g '!**/target/**' -P '\bPending(Transaction|Transactions)\b|PENDING(_ON_\w+)?'tests/integration/test_subscription_to_new_txs.rs (1)
140-175: Sender-address filtering coverage looks solid; consider also covering Deploy (None) sender.You cover Declare and Invoke via a predeployed account, which is great. Since
Transaction::get_sender_address()returnsNonefor plain Deploy, consider adding a negative test asserting that asender_addressfilter does not match a Deploy tx, to lock in semantics.I can add a small test that deploys via UDC (or any Deploy path) and asserts no notifications when filtering by a concrete sender address. Want me to draft it?
crates/starknet-devnet-core/src/starknet/events.rs (2)
11-22: Update function docs to include finality_status_filter.The signature gained
finality_status_filter, but the docstring doesn’t mention it. Please include it and clarify semantics (“returns events whose transaction finality >= filter”)./// * `keys_filter` - Optional. The keys to filter the events by. -/// * `skip` - The number of elements to skip. -/// * `limit` - Optional. The maximum number of elements to return. +/// * `finality_status_filter` - Optional. Minimum transaction finality required for events to be included. +/// Events from txs with finality strictly lower than the filter are skipped. +/// * `skip` - The number of elements to skip (applied after filtering). +/// * `limit` - Optional. The maximum number of elements to return. #[allow(clippy::too_many_arguments)] pub(crate) fn get_events(
44-49: Finality filter logic aligns with derived ordering.
if transaction.finality_status < finality_status_filter { continue }correctly implements “minimum finality” semantics when combined with the new enum ordering.Two nits:
- Minor shadowing: consider renaming the inner
finality_status_filterbinding to avoid shadowing the arg.- Add a unit test covering this filter (e.g., PreConfirmed filter excludes events from a Received tx but includes AcceptedOnL2/L1).
I can add a focused unit test around
get_eventsto assert the filter behavior using a small in-memory setup. Want me to include it?tests/integration/test_subscription_to_events.rs (2)
206-249: Pre-confirmed-only subscription behavior is pinned well.Asserting no re-notify after
pre_confirmed -> latestconfirms dedup semantics for the same event across finalities. Good coverage.Two small suggestions:
- Consider one extra assertion that
block_hash/block_numberare absent in the pre-confirmed notification (you already implicitly do by not including them in the expected JSON).- Add a comment clarifying that
finality_statusin payload reflects the tx’s current finality at emission time.
251-327: Avoid brittle assumption on block_number; use runtime value.Hardcoding
"block_number": 1may become flaky if the devnet boots with a different genesis/state in future. Capture the latest block aftercreate_block()and assert that number instead.Apply this refactor:
- let created_block_hash = devnet.create_block().await.unwrap(); + let created_block_hash = devnet.create_block().await.unwrap(); + let created_block = devnet.get_latest_block_with_tx_hashes().await.unwrap(); ... - json!({ - "block_hash": created_block_hash, - "block_number": 1, // the only created block + json!({ + "block_hash": created_block_hash, + "block_number": created_block.block_number, "transaction_hash": invocation.transaction_hash, "from_address": contract_address, "keys": [static_event_key()], "data": [], "finality_status": finality_status, })tests/integration/test_subscription_to_new_tx_receipts.rs (1)
167-189: Sender filter on receipts: solid; consider adding explicit Received/Candidate subscription case.Given the PR note that subscribing with CANDIDATE or RECEIVED maps to PRE_CONFIRMED, consider a minimal extra test where
finality_status: [RECEIVED]still yields a PreConfirmed receipt notification. That will lock in the “promotion” logic.If helpful, I can draft a small test mirroring this one but with
finality_status: [TransactionFinalityStatus::Received]and assert the received receipt hasfinality_status: PreConfirmed.tests/integration/test_subscription_to_tx_status.rs (1)
197-211: Minor ergonomics nit: avoid moving sockets if you plan to reuse them.Using
for (mut ws, subscription_id) in [(ws_before_tx, id_before), (ws_after_tx, id_after)]moves both sockets. It’s fine here since you don’t reuse them later in this test, but in similar patterns consider iterating over mutable references to avoid accidental moves if future assertions are added.Apply this localized refactor for future-proofing:
- for (mut ws, subscription_id) in - [(ws_before_tx, subscription_id_before), (ws_after_tx, subscription_id_after)] - { - let notification = receive_rpc_via_ws(&mut ws).await.unwrap(); + for (ws, subscription_id) in + [&mut ws_before_tx, &mut ws_after_tx].into_iter().zip([subscription_id_before, subscription_id_after]) + { + let notification = receive_rpc_via_ws(ws).await.unwrap(); - assert_no_notifications(&mut ws).await; + assert_no_notifications(ws).await; }crates/starknet-devnet-server/src/api/json_rpc/models.rs (2)
14-15: Coupling to subscribe.rs types is acceptable, but keep layering in mind.Importing
TransactionFinalityStatusWithoutL1andTransactionStatusWithoutL1fromcrate::subscribekeeps enums single-sourced but ties models to the subscription layer. If these inputs are reused outside WS, consider moving the enums to a neutral module (e.g.,typesormodels) to avoid circular concerns later.
251-256: EventsSubscriptionInput: consider documenting finality semantics.You accept a single
finality_statusfor events. Downstream code uses it to both filter and determine the historical scan window. A short doc comment here would prevent misuse and clarify that “no value” defaults to L2-accepted.crates/starknet-devnet-server/src/api/json_rpc/mod.rs (1)
411-420: Prefer stable error message without “should be defined.”The internal error string is fine for now, but consider a more actionable message (e.g., “No aborted block recorded in state”). Not critical.
crates/starknet-devnet-server/src/api/json_rpc/endpoints_ws.rs (2)
176-226: Transactions subscription: inputs OK; consider semantics for RECEIVED/CANDIDATE.You accept
TransactionStatusWithoutL1(including RECEIVED/CANDIDATE), but the server only emits PRE_CONFIRMED and ACCEPTED_ON_L2 notifications for transactions. As-is, filters containing only RECEIVED/CANDIDATE will never match. If that’s by design, document it; otherwise, map RECEIVED/CANDIDATE to PRE_CONFIRMED similarly to receipts.Would you like a small patch that normalizes
RECEIVED|CANDIDATEtoPRE_CONFIRMEDfor NewTransactions subscriptions?
229-281: Receipts subscription: good filter construction; same lock-holding caveat.The filter/scan logic is sound. However, as in other subs, you hold the sockets mutex while sending the initial backlog. Consider reducing lock scope to the subscribe step and perform notifications without holding the collection lock.
crates/starknet-devnet-server/src/subscribe.rs (1)
395-401: Notification payload for receipts drops sender_address.You include
sender_addressinNewTransactionReceiptNotificationfor filtering, but the serialized notification sends only theTransactionReceipt. If the spec later requires including sender for receipts, you’ll need to adjustSubscriptionNotification::NewTransactionReceiptaccordingly. For now, this is fine and intentional.
📜 Review details
Configuration used: .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.
⛔ Files ignored due to path filters (6)
crates/starknet-devnet-server/test_data/spec/0.9.0/edit_spec_instructions.yamlis excluded by!crates/starknet-devnet-server/test_data/spec/**crates/starknet-devnet-server/test_data/spec/0.9.0/starknet_api_openrpc.jsonis excluded by!crates/starknet-devnet-server/test_data/spec/**crates/starknet-devnet-server/test_data/spec/0.9.0/starknet_executables.jsonis excluded by!crates/starknet-devnet-server/test_data/spec/**crates/starknet-devnet-server/test_data/spec/0.9.0/starknet_trace_api_openrpc.jsonis excluded by!crates/starknet-devnet-server/test_data/spec/**crates/starknet-devnet-server/test_data/spec/0.9.0/starknet_write_api.jsonis excluded by!crates/starknet-devnet-server/test_data/spec/**crates/starknet-devnet-server/test_data/spec/0.9.0/starknet_ws_api.jsonis excluded by!crates/starknet-devnet-server/test_data/spec/**
📒 Files selected for processing (22)
crates/starknet-devnet-core/src/starknet/events.rs(8 hunks)crates/starknet-devnet-core/src/starknet/mod.rs(1 hunks)crates/starknet-devnet-server/src/api/http/endpoints/postman.rs(2 hunks)crates/starknet-devnet-server/src/api/json_rpc/endpoints.rs(5 hunks)crates/starknet-devnet-server/src/api/json_rpc/endpoints_ws.rs(5 hunks)crates/starknet-devnet-server/src/api/json_rpc/mod.rs(9 hunks)crates/starknet-devnet-server/src/api/json_rpc/models.rs(2 hunks)crates/starknet-devnet-server/src/subscribe.rs(6 hunks)crates/starknet-devnet-types/src/rpc/block.rs(2 hunks)crates/starknet-devnet-types/src/rpc/emitted_event.rs(2 hunks)crates/starknet-devnet-types/src/rpc/transaction_receipt.rs(1 hunks)crates/starknet-devnet-types/src/rpc/transactions.rs(3 hunks)tests/integration/general_rpc_tests.rs(1 hunks)tests/integration/lib.rs(1 hunks)tests/integration/test_subscription_to_events.rs(12 hunks)tests/integration/test_subscription_to_new_tx_receipts.rs(1 hunks)tests/integration/test_subscription_to_new_txs.rs(1 hunks)tests/integration/test_subscription_to_pending_txs.rs(0 hunks)tests/integration/test_subscription_to_reorg.rs(2 hunks)tests/integration/test_subscription_to_tx_status.rs(2 hunks)tests/integration/test_subscription_with_invalid_block_id.rs(3 hunks)website/docs/intro.md(1 hunks)
💤 Files with no reviewable changes (1)
- tests/integration/test_subscription_to_pending_txs.rs
🧰 Additional context used
🪛 LanguageTool
website/docs/intro.md
[grammar] ~21-~21: There might be a mistake here.
Context: ...is a precursor to a stable latest block. - Transactions are never automatically `AC...
(QB_NEW_EN)
🔇 Additional comments (47)
crates/starknet-devnet-server/src/api/http/endpoints/postman.rs (1)
70-73: Good ordering: handle L1→L2 before L2→L1.Processing L1→L2 first avoids missing any L2→L1 messages produced by those transactions. The rationale is sound.
tests/integration/test_subscription_to_reorg.rs (2)
13-13: Renamed test accurately reflects new semantics (all subs notified on reorg).Test intent is clear and aligned with PR behavior change. Good rename.
26-27: Good: reorg coverage extended; no stale PendingTransactions subscriptions remain
Verified across code, tests, and docs with:rg -nC2 -g '!**/target/**' -e 'starknet_subscribePendingTransactions|PendingTransactions'No matches found. Ready to approve.
crates/starknet-devnet-types/src/rpc/block.rs (2)
162-172: Deserialize: Explicitly reject 'pre_confirmed' and 'l1_accepted' for SubscriptionBlockId.This matches the API intent and integration tests: only 'latest', hash, and number are permitted for subscriptions. Error messages are precise and map nicely to -32602 at the RPC layer.
256-259: Tests: Consolidated rejection of non-latest tags is clean and future-proof.Looping over ["pending", "pre_confirmed", "l1_accepted"] keeps intent clear without over-specifying error messages for the "pending" case (which is rejected earlier in BlockId).
tests/integration/test_subscription_with_invalid_block_id.rs (3)
16-19: Helper for 'l1_accepted' error mirrors the pre_confirmed case.Keeps assertions DRY and consistent. Good addition.
65-85: Renamed test to pre_confirmed appropriately; assertions look correct.Covers both relevant subscription methods and asserts the exact error payload.
86-102: New test: 'l1_accepted' not allowed for block/events subscriptions.Accurately validates the new restriction and expected error shape. Nice inclusion of the assertion message with the method name for easier debugging.
tests/integration/general_rpc_tests.rs (1)
30-30: No stale “-rc” references detected – changes approved
Spec version assertion updated to0.9.0, fully aligned with the server constant.tests/integration/lib.rs (2)
37-38: WS tests migrated from pending-txs to new tx/receipt topics — LGTMModules line up with the new WS API surface (NewTransactions and NewTransactionReceipts).
37-38: Pending-txs tests cleanup confirmed
test_subscription_to_pending_txs.rs has been removed and no remaining ‘pending_tx’ or ‘pending-tx’ references were found in the tests directory.crates/starknet-devnet-types/src/rpc/transaction_receipt.rs (1)
39-49: finality_status accessor is correct and minimalCleanly extracts the inner CommonTransactionReceipt and returns a reference to the finality status.
crates/starknet-devnet-server/src/api/json_rpc/endpoints.rs (5)
63-69: Lock chaining in get_block_with_txs is fine; error mapping preservedNo semantic changes; happy with the concise style.
96-101: Pre-confirmed state update handling added — goodReturning PreConfirmedStateUpdate via the correct StarknetResponse variant aligns with the new finality-aware flow.
291-309: call: minor lock style change — LGTMLock scope and error mapping remain correct, including NoStateAtBlock and execution errors.
318-330: estimate_fee: concise locking pattern — LGTMMapping covers simulation and execution errors as before.
535-549: Intentional omission of finality filter ingetEventsRPC
The JSON-RPCEventFilter(crates/starknet-devnet-types/src/rpc/transactions.rs) doesn’t include afinality_statusfield, so passingNoneinto the coreget_eventscall is correct and aligns with the current 0.9.0 spec. If a future spec revision adds a finality filter forgetEvents, we can thread it through the RPC layer then.crates/starknet-devnet-core/src/starknet/mod.rs (1)
1186-1199: get_unlimited_events: finality filter propagation — LGTMThe extra parameter cleanly forwards to events::get_events. Return shape unchanged.
crates/starknet-devnet-types/src/rpc/emitted_event.rs (3)
5-5: New import for TransactionFinalityStatus — OKThis aligns with finality-tagged subscription payloads.
73-77: From for Event via existing ref conversion — LGTMKeeps the single cloning implementation centralized.
79-85: SubscriptionEmittedEvent fully wired through WS subscriptions and covered by testsVerified with:
- rg – found
SubscriptionEmittedEventusages insubscribe.rs,endpoints_ws.rs, andapi/json_rpc/mod.rs.- rg in
tests/– confirmed integration tests exercisefinality_statusin:
• Transaction status subscriptions
• New‐tx subscriptions
• New‐tx‐receipt subscriptions
• Event subscriptions
• Messaging and receipt lookupsNo further changes needed.
crates/starknet-devnet-types/src/rpc/transactions.rs (1)
173-175: LGTM: Delegation to inner transaction is correct.The delegation preserves the Option semantics and keeps the single source of truth in
Transaction::get_sender_address.tests/integration/test_subscription_to_new_txs.rs (3)
19-35: Helpers are clean and consistent with the new WS surface.
send_dummy_mint_tx,subscribe_new_txs, andreceive_new_txkeep tests readable and DRY. Good abstraction.
55-65: Good pattern: assert and then parse; ensures finality field is validated.Removing
finality_statusbefore deserializing intoTransactionavoids unknown-field issues and keeps the test robust if payloads evolve.
196-215: Empty sender_address array semantics: verify and document.You expect that
"sender_address": []behaves as “no sender filter” (i.e., wildcard). That’s reasonable, but easy to misinterpret server-side (some APIs treat empty arrays as “match nothing”). Please confirm this is the intended contract and document it in the WS subscription schema.Do we guarantee
"sender_address": []== no filter? If yes, consider adding a comment in the API model (TransactionSubscriptionInput) and a server-side unit test to pin the behavior.crates/starknet-devnet-core/src/starknet/events.rs (1)
354-377: Callsite updates look correct (new param None).The tests were updated to pass
Nonefor the new parameter, preserving previous behavior. Good.tests/integration/test_subscription_to_events.rs (1)
1-20: Event payload assertions include finality_status everywhere; nice consistency.Good job updating assertions to include
finality_statusin all relevant tests (both filtered and unfiltered). This matches the newSubscriptionEmittedEventpayload design.tests/integration/test_subscription_to_new_tx_receipts.rs (3)
20-41: Helper trio is tidy and mirrors the NewTransactions tests.The helpers keep the test suite maintainable and aligned with the WS surface; naming is consistent.
61-74: Receipt decoding and finality assertion are correct for PreConfirmed.Deserializing into
InvokeTransactionReceiptand asserting bothtransaction_hashandfinality_statuspins the contract well.
212-231: Empty sender_address filter semantics: please confirm.As with the transactions test, this treats
"sender_address": []as no filter. Please ensure the server treats empty array as wildcard rather than “match nothing” and document it in the input schema.If this is intended, add a note in
TransactionReceiptSubscriptionInputdocs and a unit test to pin behavior.tests/integration/test_subscription_to_tx_status.rs (3)
140-144: Good refactor: pass WS connections from the caller.Threading externally created sockets makes the helper reusable and removes hidden side effects. Returning
(tx_hash, sub_id_before, sub_id_after)is also convenient for downstream assertions.
147-162: Solid sequencing and assertions around pre/post-subscription.The flow validates both “subscribed-before” and “subscribed-after” paths and ensures no extra notifications linger. The explicit
.clone()on subscription IDs is fine given test ergonomics.
241-257: Clear coverage for “transaction mode” (no post-block extra notifications).This is a good complement to the on-demand flow and prevents regressions around duplicate status transitions.
crates/starknet-devnet-server/src/api/json_rpc/models.rs (2)
260-264: Transactions subscription inputs look correct and spec-aligned.Accepting multiple
finality_status(without L1) and a list of sender addresses gives flexibility and maps neatly to the server-side filters.
267-270: Receipts input intentionally limits finality statuses.Constraining to
TransactionFinalityStatusWithoutL1(no RECEIVED/CANDIDATE) matches the PR description. Good to see the API preventing unsupported combinations at the type level.crates/starknet-devnet-server/src/api/json_rpc/mod.rs (3)
10-10: Spec version bump to 0.9.0 is straightforward.Ensure all client-facing docs and tests assert “0.9.0” now (you already cover spec deserialization tests in this crate).
380-405: broadcast_changes flow looks correct.Pre-confirmed diffs are processed before latest-block comparison, and reorgs produce a dedicated notification. This aligns with the finality-aware design.
940-956: New WS subscription variants are consistent with the spec surface.The rename strings match the method names used in tests and endpoints. Looks good.
crates/starknet-devnet-server/src/api/json_rpc/endpoints_ws.rs (3)
138-157: Type-safe accessors for txs-with-receipts are solid.Returning typed errors when encountering unexpected variants (Hashes/Full) is good defensive programming.
329-336: Finality-aware events: clarify initial scan window.You default
finality_statustoAcceptedOnL2, which is good. The initial scan window is determined downstream; see next comment for a correctness fix.
355-360: Event payload wrapping is correct.Wrapping emitted events with finality in
SubscriptionEmittedEventaligns with the new spec.crates/starknet-devnet-server/src/subscribe.rs (6)
79-92: StatusFilter is simple and effective.Empty container means “allow all,” which is a sensible default for absent filters.
97-113: Subscription enum evolution is clean.Replacing legacy pending-tx variants with finality-aware NewTransactions/NewTransactionReceipts plus an Events status filter reads well and matches the new surface.
136-167: Matcher logic is precise; nice use of sender_address for filtering.
- Transactions: pass through when both address and finality filters match; ignore when sender unavailable (Some networks may not populate it).
- Receipts: finality from receipt plus optional sender match.
- Events: filter via
check_if_filter_applies_for_eventand finality status.
222-257: WithoutL1 enums and conversions are well-scoped.Encoding “no L1” at the type level prevents unsupported statuses from leaking into the API. Conversions to
TransactionFinalityStatusare straightforward.
261-266: Flattening tx fields in NewTransactionNotification is a good UX.Clients get a flat object with
finality_statusalongside tx fields; clean and spec-friendly.
414-420: All subscriptions receive reorg notifications.This unified behavior is helpful for clients to reconcile state.
Usage related changes
CANDIDATEandRECEIVEDtx statuses still not used.Development related changes
api.starknetChecklist:
./scripts/format.sh./scripts/clippy_check.sh./scripts/check_unused_deps.sh./scripts/check_spelling.sh./website/README.mdSummary by CodeRabbit