[WIP] statement-store: implement the new JSON-RPC API - #3330
Closed
AndreiEres wants to merge 13 commits into
Closed
Conversation
Contributor
|
@AndreiEres would this PR get simplified by the suggestion in: paritytech/json-rpc-interface-spec#185 (comment)? |
This was referenced Aug 7, 2026
Merged
Contributor
Author
|
Split into reviewable parts, identical content in total:
Parts 2-5 are stacked drafts, each based on the previous; they get retargeted and marked ready as their bases merge. The spec-divergence notes from this description live on in the doc comments and the parts' descriptions. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the statement store JSON-RPC API from json-rpc-interface-spec#185, implemented in polkadot-sdk by #11989. The legacy
statement_submit/statement_subscribeStatement/statement_unsubscribeStatementstay untouched.One commit per step:
statement_unstable_submitmatchAll, which the specification forbidsstatement_unstable_subscribe/unsubscribestatement_unstable_add_filter/remove_filter+subscribeEventstopwhen a subscription's deduplication cache overflowssubmitvalidationMirrors polkadot-sdk's
Store::submitorder, limited to checks needing neither a local store nor chain state:-32602invalid/alreadyExpiredexpiry >> 32is in the pastinvalid/encodingTooLargeMAX_STATEMENT_SIZE(1 MiB − 1)invalid/noProof-32603newknownandrejectedare never returned: both report a store decision, and a light client keeps no store.knownis in fact unreachable through local RPC submission in polkadot-sdk too, sinceStatementSource::Localcan always be resubmitted.badProofis not returned either, and deliberately so: telling a bad proof from a good one means verifying a signature, which is more CPU than a light client should spend on a submission. Only the presence of a proof is checked. The trade-off is that smoldot will relay a statement whose signature is invalid, and peers that verify it answer with a reputation penalty.Subscriptions
One registry serves both APIs: a legacy subscription is a subscription holding a single filter. Filters are capped at 128 per subscription;
add_filteranswers{"result":"limitReached"}beyond that, and-32801for an unknown subscription.topicFilteraccepts only"any"and{"matchAll": [1..4 topics]}—matchAnyis turned down with-32602, as in polkadot-sdk.add_filteremitsreplayDoneimmediately over an empty snapshot,replayStatementsnever being emitted. Peers then resend everything matching the updated affinity filter, and the per-subscription deduplication drops what was already delivered, so only unseen statements reach the client throughnewStatements.A subscription is stopped, with a
stopevent, once its deduplication cache is full: remembering one more statement would evict the oldest entry, after which that statement could be reported twice. With the defaultmaxSeenStatementsof 65536 a subscription therefore dies after roughly that many distinct statements and the client resubscribes. Legacy subscriptions keep evicting silently, the old API having no way to report this.-32800is never returned, as the number of statement subscriptions per client is not capped. The specification requires accepting at least 2 and only permits erroring beyond that, so this is compliant.To raise on the spec PR
Three points where a storeless light client diverges from what the specification seems to assume:
replayDonearrives before the effective backlog. Smoldot's store is genuinely empty, so the replay is legitimately empty, but a client that treatsreplayDoneas "I now have what the server had" concludes it too early — the backlog arrives afterwards throughnewStatements, delayed by up to the affinity update interval.newStatementsis what the at-most-once guarantee forbids. A complete backlog for a filter requires a fresh subscription.knownis unreachable through local RPC submission in the reference implementation, so the specification documents an outcome that never occurs for this method.Noted, not addressed here
Smoldot's codec still accepts
Proof::OnChain, which polkadot-sdk removed in favour of cryptographic-only proofs and now rejects at decode. Smoldot will therefore relay statements that SDK nodes drop. Worth its own issue.🤖 Generated with Claude Code
Closes #3319