Repository navigation
feat(rpcclient): support Starknet v0.9+ websocket subscriptions - #2318
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 5 files with indirect coverage changes 🚀 New features to boost your workflow:
|
Code Review by Qodo
1. Starknet casing inconsistent
|
Restore the STRK/STRKS spec, the Starknet provider examples and the Starknet internal-path test to main. They move to the ofir/starknet-spec-v010 PR, which must merge only after this code is released and providers have upgraded. This PR keeps the rpcclient runtime support. Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9
The consumer only matched an unsubscribe to its subscription when the
id came positionally (["0x1"]). starknet.js sends starknet_unsubscribe
by name ({"subscription_id": "0x1"}), which got "subscription not
found" and left the subscription open until the websocket closed.
When the raw params match nothing and they are a single-entry object
with a string value, retry with that value. The raw match still runs
first, so tendermint (whose id is the whole params object) is
unchanged.
Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9
Subscribe stopped erroring when by-name params carried a "query" that was not a string. That subscription then registered under the response id, while tendermint notifications are routed by query, so they were all dropped silently. Error again when "query" is present but not a string. When "query" is absent (starknet by-name params), the id still comes from the response. Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9
Rename TestIsStarknetNotification and TestStarknetSubscriptionEndToEnd to TestStarknetNotification_Detection and TestStarknetSubscription_EndToEnd, per the repo's test naming convention. Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9
Gives the release with the Starknet v0.9+ subscription support its own protocol version, so ProviderMin/ProviderTarget can require it before the Starknet spec (#2341) goes live. Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9
Starknet 0.14.3 nodes (pathfinder v0.23+) serve only JSON-RPC v0.9 and v0.10. Update the STRK and STRKS specs and the provider examples: - add /rpc/v0_10 and /ws/rpc/v0_10; drop /rpc/v0_8 and /ws/rpc/v0_8, including the pending-block-support check that lived there - add starknet_getBlockWithReceipts, starknet_getCompiledCasm, starknet_getMessagesStatus and starknet_getStorageProof - replace pathfinder_subscribe/pathfinder_unsubscribe with the starknet_subscribe* family and starknet_unsubscribe - drop starknet_pendingTransactions, pathfinder_getProof and pathfinder_getTransactionStatus; add pathfinder_lastL1AcceptedBlockHashAndNumber - parse starknet_estimateFee block_id from param index 2 - average_block_time 30000/32000 -> 2000 (mainnet measures ~1.84s) and allowed_block_lag_for_qos_sync -> 5 Split out of #2318. Merge only after #2318 is released and providers have upgraded: older providers accept starknet_subscribe* but drop every notification. Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9
Description
Closes: N/A
Runtime support for Starknet JSON-RPC v0.9+ websocket subscriptions. The STRK/STRKS spec that turns them on now lives in #2341. That PR merges only after this one ships and providers have upgraded.
Changes
rpcclient/json.go,rpcclient/handler.gostarknet_subscription*notifications ({subscription_id, result}envelope) and deliver them bysubscription_id. Before this, no dispatch rule matched them and they were droppedrpcclient/client.goSubscribeaccepts by-name params without aquerykey (Starknet) and omitted params. Aquerythat is present but not a string still errors (Tendermint)rpcclient/handler.goop.erris set and the subscription is registered before the waiting caller is unblocked. A failed node subscribe could previously look like a successconsumer_ws_subscription_manager.go{"subscription_id":"0x1"}, which is what starknet.js sends. Positional and Tendermint matching are unchangedx/protocol/types/params.goTARGET_VERSION6.2.8 → 6.2.9, so this release has its own protocol versionNo proto, gRPC or relay-format change, so mixed consumer and provider versions stay compatible. Until #2341 lands, nothing on STRK calls the new Starknet paths.
Rollout
ProviderTarget/ProviderMinto 6.2.9 upgrades providers that run under lavavisor. The lavap binary itself doesn't enforce the minimum (ValidateProtocolVersionis a no-op), so other providers have to upgrade by hand. The health monitor flags providers that are off the target version./rpc/v0_10isn't served until a restart.Testing
TestStarknetNotification_DetectionandTestStarknetSubscription_EndToEnd: notification detection, plus a full subscribe → notify flow against a mock node (by-name params, string ids, unknown-id drops)TestClientSubscribe_NonStringQueryParam: a non-stringqueryfails fastTestConsumerWSSubscriptionManager_FindSubscriptionByUnsubscribeParams: positional, by-name, Tendermint and not-found casesgo test ./protocol/... ./x/spec/...passes on this branch by itself, without feat(specs): update Starknet spec to JSON-RPC v0.9/v0.10 and WS subscriptions #2341go build ./...plusgo test ./x/protocol/... ./protocol/upgrade/... ./protocol/statetracker/...golangci-lintv1.62.0 (the CI version): 0 issuesAuthor Checklist
All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.
I have...
!in the type prefix if API or client breaking change (not breaking)mainbranchReviewers Checklist
All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.
I have...
https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9