feat: Add StarkNet v0.9+ subscription support and update RPC specs - #2318
feat: Add StarkNet v0.9+ subscription support and update RPC specs#2318EliasiOfir wants to merge 4 commits into
Conversation
Starknet 0.14.3 (and pathfinder v0.23.0, released 2026-07-20) removed JSON-RPC v0.8 and older; nodes now serve v0.9 (root default) and v0.10 (final v0.10.1 spec on the v0_10 routes). Update STRK and STRKS specs accordingly: - add /rpc/v0_10 and /ws/rpc/v0_10 collections (inheritance-only, mirroring the v0_9 pair) - remove the /rpc/v0_8 and /ws/rpc/v0_8 collections (RPC 0.8 removed by Starknet 0.14.3; pathfinder no longer serves these endpoints) - add missing spec methods: starknet_getBlockWithReceipts, starknet_getCompiledCasm, starknet_getMessagesStatus, starknet_getStorageProof - remove starknet_pendingTransactions (dropped from the RPC spec; no served version supports it) - replace the legacy pathfinder_subscribe/pathfinder_unsubscribe WS API (removed in pathfinder 0.18.0) with the spec WS subscription family: starknet_subscribeNewHeads/Events/TransactionStatus/NewTransactions/ NewTransactionReceipts + starknet_unsubscribe, one SUBSCRIBE parse directive per method (solana-style) - pathfinder extension collection: drop pathfinder_getProof and pathfinder_getTransactionStatus (removed in pathfinder 0.17.0, superseded by starknet_getStorageProof/starknet_getTransactionStatus), add pathfinder_lastL1AcceptedBlockHashAndNumber - average_block_time 30000/32000 -> 2000 for Starknet 0.14.x fast blocks (matches base/optimism convention for ~2s chains) Update TestJsonRpcInternalPathsMultipleVersionsStarkNet to the new path set and refresh the starknet provider example configs (v0_9/v0_10). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MC6w48eT5tW9K8iUNCm7PG
The starknet_subscribe* APIs added to the spec need runtime support the
node ws client lacked:
- notifications use methods named starknet_subscriptionXxx with params
{subscription_id, result}; none of the existing dispatch shapes
(ethereum "_subscription" suffix, solana "Notification" suffix,
legacy pathfinder top-level result) matched, so they were silently
dropped. Add a dedicated predicate and handler keyed by
params.subscription_id.
- Client.Subscribe rejected the canonical starknet subscribe forms:
by-name object params without a tendermint "query" key errored, and
omitted params hit "unknown parameters type". Make "query" optional
(tendermint-only) and accept nil params.
Also apply spec calibration from review: starknet_estimateFee block_id
positional index 1 -> 2 (v0.9/v0.10 params are [request,
simulation_flags, block_id]) and allowed_block_lag_for_qos_sync -> 5,
matching the base/optimism convention for ~2s block chains now that
average_block_time is 2000.
Adds predicate unit tests and an end-to-end mock-node websocket test
covering object params, string subscription ids, envelope delivery and
unknown-id drops.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MC6w48eT5tW9K8iUNCm7PG
handleResponse sent op.resp <- msg before writing op.err and registering the subscription in clientSubs, racing with requestOp.wait which reads op.err immediately after receiving. On an error response the caller could observe a stale nil error and treat a failed subscription as successful. The race was previously unreachable in tests; the new starknet subscription end-to-end test tripped it deterministically under -race. Move all op.err writes and subscription registration before the op.resp send for subscription responses (matching upstream go-ethereum's ordering) while preserving this fork's behavior of returning the raw response message to the caller. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MC6w48eT5tW9K8iUNCm7PG
PR Summary by QodoAdd StarkNet v0.9+ WS subscriptions and refresh RPC v0.9/v0.10 specs
AI Description
Diagram
High-Level Assessment
Files changed (11)
|
Codecov Report❌ Patch coverage is
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 6 files with indirect coverage changes 🚀 New features to boost your workflow:
|
Code Review by Qodo
1. Starknet casing inconsistent
|
| } | ||
| } | ||
|
|
||
| func (h *handler) handleSubscriptionResultStarknet(msg *JsonrpcMessage) { |
There was a problem hiding this comment.
1. starknet casing inconsistent 📘 Rule violation ⚙ Maintainability
New StarkNet-related identifiers use mixed casing (StarkNet vs Starknet) within the same package, which breaks repository naming conventions and makes identifiers harder to discover/grep consistently. This is visible in the new handleSubscriptionResultStarknet / isStarknetNotification additions alongside existing ...StarkNet... names.
Agent Prompt
## Issue description
StarkNet-related identifiers were introduced with inconsistent casing (`Starknet` vs `StarkNet`) in the same `rpcclient` package.
## Issue Context
The package already uses `StarkNet` casing in existing identifiers (e.g. `isStarkNetPathfinderNotification`, `handleSubscriptionResultStarkNetPathfinder`). The new functions `isStarknetNotification` and `handleSubscriptionResultStarknet` introduce a second style, which violates repository naming conventions and reduces consistency.
## Fix Focus Areas
- protocol/chainlib/chainproxy/rpcclient/handler.go[254-297]
- protocol/chainlib/chainproxy/rpcclient/json.go[93-103]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestIsStarknetNotification(t *testing.T) { |
There was a problem hiding this comment.
2. Tests not testx_y named 📘 Rule violation ⚙ Maintainability
The newly added tests do not follow the required TestComponent_Scenario naming convention (missing underscore-separated component/scenario). This reduces consistency and makes test intent/grouping harder to scan.
Agent Prompt
## Issue description
New tests are not named using the required `TestComponent_Scenario` convention.
## Issue Context
The compliance checklist requires new/updated tests to be named like `TestComponent_Scenario`. The added tests are currently named `TestIsStarknetNotification` and `TestStarknetSubscriptionEndToEnd`.
## Fix Focus Areas
- protocol/chainlib/chainproxy/rpcclient/starknet_subscription_test.go[16-67]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| case []interface{}: | ||
| msg, err = c.newMessageArrayWithID(method, id, p) | ||
| case map[string]interface{}: | ||
| msg, err = c.newMessageMapWithID(method, id, p) |
There was a problem hiding this comment.
3. Silent tendermint query failure 🐞 Bug ≡ Correctness
Client.Subscribe no longer errors when map params contain a missing/non-string query, which can register a Tendermint subscription under the server-returned id instead of the query and then drop all notifications (which are routed by result.query). This regresses prior behavior where malformed Tendermint subscription params failed fast with a clear error, making broken subscriptions harder to diagnose.
Agent Prompt
### Issue description
`Client.Subscribe` now does `subId, _ = p["query"].(string)` for map-based params. If a Tendermint subscription is passed with a malformed `query` (wrong type) or an unexpected shape, `subId` becomes empty, and `handleResponse` will register the subscription under the response `result` instead. Tendermint notifications are delivered by `result.query`, so the client will silently drop notifications.
### Issue Context
- Tendermint notifications are routed by `result.query` (not by subscription id).
- `handleResponse` registers by `op.subId` only when non-empty.
- StarkNet named params should still be supported (no `query` key).
### Fix Focus Areas
- protocol/chainlib/chainproxy/rpcclient/client.go[505-518]
### Suggested fix
In the `case map[string]interface{}` branch:
- If the `query` key is **present**:
- Require it to be a `string` (return the prior type-assertion error if not).
- Set `subId` to that string.
- If the `query` key is **absent**:
- Leave `subId` empty so non-Tendermint chains (e.g. StarkNet) use the response `result` as the subscription id.
This preserves the StarkNet-by-name behavior while restoring fail-fast safety for Tendermint-shaped params.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Description
This PR adds support for StarkNet v0.9+ subscription APIs and updates the mainnet and testnet RPC specifications to reflect the latest StarkNet protocol changes.
Key Changes
StarkNet Subscription Support
handleSubscriptionResultStarknet) inhandler.goto process StarkNet v0.9+ style notifications with the envelope format{method: starknet_subscription*, params: {subscription_id, result}}isStarknetNotification()) injson.goto identify StarkNet subscription notifications by method prefixstarknet_subscriptionTestStarknetSubscriptionEndToEnd) in new filestarknet_subscription_test.gothat validates the full subscription lifecycle including subscription ID tracking and notification deliveryclient.goto support StarkNet's by-name parameter style (map-based) in addition to Tendermint's query-based subscriptionsRPC Specification Updates
starknet_getBlockWithReceipts(20 compute units)starknet_getCompiledCasm(100 compute units)starknet_getMessagesStatus(10 compute units)starknet_getStorageProof(20 compute units)starknet_subscribeEvents,starknet_subscribeNewHeads,starknet_subscribeNewTransactionReceipts,starknet_subscribeNewTransactions,starknet_subscribeTransactionStatus(1000 compute units each)starknet_unsubscribe(replacingpathfinder_unsubscribe)pathfinder_subscribe,pathfinder_unsubscribe,pathfinder_getProof, andpathfinder_getTransactionStatusin favor of native StarkNet subscription methodsstarknet_getBlockWithTxsparser argument from "1" to "2" for proper block number indexingstarknet_getTransactionByBlockIdAndIndexnow uses proper block parsing with "0" indexstarknet_getTransactionReceiptmarked as deterministic (was incorrectly non-deterministic)average_block_timefrom 30000/32000ms to 2000ms andallowed_block_lag_for_qos_syncfrom 1-2 to 5 for both mainnet and testnetpending-block-supportverification check that was causing issuesConfiguration Examples
/wspath in favor of empty internal-path)Testing
TestStarknetSubscriptionEndToEndto validate subscription flow with mock StarkNet nodeTestIsStarknetNotificationto verify notification detection logicTestJsonRpcInternalPathsMultipleVersionsStarkNetto reflect new API versionsFiles Changed
specs/mainnet-1/specs/starknet.json- Updated RPC specs and methodsprotocol/chainlib/chainproxy/rpcclient/handler.go- Added StarkNet subscription handlerprotocol/chainlib/chainproxy/rpcclient/json.go- Added StarkNet notification detectionprotocol/chainlib/chainproxy/rpcclient/client.go- Updated subscription parameter handlinghttps://claude.ai/code/session_01MC6w48eT5tW9K8iUNCm7PG