Skip to content

feat: track the rollups-node JSON-RPC API changes - #161

Draft
tuler wants to merge 3 commits into
prerelease/v2-alphafrom
claude/jsonrpc-api-changes-cartesi-xnjga6
Draft

feat: track the rollups-node JSON-RPC API changes#161
tuler wants to merge 3 commits into
prerelease/v2-alphafrom
claude/jsonrpc-api-changes-cartesi-xnjga6

Conversation

@tuler

@tuler tuler commented Aug 14, 2026

Copy link
Copy Markdown
Member

Mirrors the node API changes of cartesi/rollups-node#793 in @cartesi/rpc, and bubbles them down to @cartesi/client and @cartesi/react.

Derived from the internal/jsonrpc/jsonrpc-discover.json diff against that PR's base (next/2.0), cross-checked against internal/jsonrpc/api/params.go and internal/jsonrpc/jsonrpc.go. Tracked up to upstream head a5d2cef (the branch was force-pushed after the first commit here; the second sync is the third commit).

New methods

Node method @cartesi/client @cartesi/react
cartesi_getEpochByVirtualIndex getEpochByVirtualIndex useEpochByVirtualIndex
cartesi_getExecutedOutputCount getExecutedOutputCount useExecutedOutputCount
cartesi_getPendingExecutableOutputCount getPendingExecutableOutputCount usePendingExecutableOutputCount
cartesi_getNodeInfo getNodeInfo useNodeInfo

getNodeInfo returns the chain id, the semantic node version and the node's default block tag in a single call. It replaces getChainId and getNodeVersion, which the node deprecated and which are now marked @deprecated here too — they still work. defaultBlock is documented as the node's finality contract: everything the node exposes carries that tag's stability guarantees.

New listing filters

  • from/to, an inclusive index range, on listEpochs, listInputs, listOutputs and listReports.
  • listEpochs takes a list of statuses (status?: EpochStatus | NonEmptyArray<EpochStatus>).
  • listOutputs takes a list of output types (outputType?: OutputType | NonEmptyArray<OutputType>) and a new executed?: boolean filter.

The node rejects an empty filter list with invalid params, so both list-valued filters use a new NonEmptyArray<T> = [T, ...T[]] type exported by @cartesi/rpc and re-exported by @cartesi/client: status: [] and outputType: [] are compile errors rather than failed requests. Note this is stricter than a plain array in both directions — it also rejects an EpochStatus[]-typed variable, so callers building lists dynamically should type them as NonEmptyArray<EpochStatus>.

Synchronization patterns

These are the node's documented patterns, mirrored in the JSDoc and docs pages of all three packages:

  • Epochs — keep discovery and refresh separate: advance from to the next unseen epoch index to discover new epochs, and refresh the epochs already seen by filtering them on the non-terminal statuses. Terminal statuses never regress, so a settled epoch leaves the refresh set for good.
  • Output executions — poll getExecutedOutputCount (monotone) and, when it changes, re-query the bounded executable-output working set with executed: false and outputType: ["Voucher", "DelegateCallVoucher"], then diff that pending set against the previous result to identify the executions. getPendingExecutableOutputCount is a gauge and must not be used for change detection.

No resume cursor over the executed filter is sound — not an output index, a pagination offset, or the executed count — because executions are observed out of output-index order. The node documents a race-free execution cursor as expected in a future ingestion API.

Breaking changes

  • cartesi_getMatchAdvanced was renamed to cartesi_getMatchAdvance, following the node. The action is now getMatchAdvance, the hook is useMatchAdvance (with matchAdvanceOptions / matchAdvanceQueryKey), and GetMatchAdvancedParams / GetMatchAdvancedReturnType are now GetMatchAdvanceParams / GetMatchAdvanceReturnType. No back-compat aliases were kept — these packages are on 2.0.0-alpha prereleases and the node made the same break. The entity type MatchAdvanced keeps its name, matching the node's MatchAdvancedGetResult schema.
  • The node's application-level error codes moved out of the JSON-RPC reserved range: application not found is now -31002 (was -32002) and resource not found is now -31001 (was -32001).

Error codes and batch limits

@cartesi/rpc now exports the node's codes as errorCodes, including the new batch (-32040), timeout (-32070), response-size-limit (-31003) and batch-list-work (-31004) ones, alongside the constants that bound a batch: maxBatchSize (100), maxBatchListWork (10 000) and defaultListLimit (50).

Two budgets apply to a batch beyond its entry count:

  • Response size — 10 MB per HTTP request, cumulative across a batch. An entry whose response would exceed the remaining budget is discarded without consuming it and gets -31003; the budget then closes, so every later entry gets -31003 too, even one that would still have fit.
  • List work — before dispatching anything, the node sums the effective limit of every list entry, counting an omitted or zero limit as defaultListLimit and capping each entry at maxBatchListWork. A total above maxBatchListWork rejects the whole batch with a single -31004 and dispatches nothing.

Notes

  • Batch requests needed no transport change — the underlying json-rpc-2.0 client already batches — so they are documented rather than implemented.
  • Upstream gave the two output counts their own result schemas, but both are { data: UnsignedInteger }, which the separate return types here already matched. No wire-shape change.
  • Upstream also fixed the repository layer to treat an empty output-type list as no filter (avoiding invalid SQL). That sits below the JSON-RPC handler, which still rejects empty status and output_type lists with invalid params, so NonEmptyArray continues to match node behavior.
  • Two OpenRPC fixes needed no code change: prev_randao and voucher value are now typed as 256-bit hex in the spec, which is what the wire types and converters already assumed.
  • chainId in NodeInfo is a number, matching what the existing getChainId action returns.
  • listOutputs maps output types to selectors through the head of the list separately, because Array.prototype.map would widen the tuple back to Hex[]. That keeps non-emptiness proven rather than asserted.
  • Beyond the API tracking, four @cartesi/react hooks (useApplication, useCommitments, useTournaments, useWithdrawals) were already failing biome check on the base branch for import formatting; this branch lets biome fix them so pnpm lint passes.

Testing

  • pnpm lint clean across the workspace.
  • @cartesi/client (11), @cartesi/react (122), @cartesi/codec (70) and @cartesi/rollup (24) suites pass. Coverage added for the new nodeInfoConverter, the renamed match-advance query keys, and the stringification of the new from/to bigints in every listing query key.
  • The empty-list constraint is guarded by a __tests__/params.test-d.ts type suite, which required enabling vitest type testing in @cartesi/client — CI runs pnpm test but no tsc --noEmit over test files, so without it a regression would go unnoticed. Verified non-vacuous: reverting the type to EpochStatus[] makes the suite fail, including Unused '@ts-expect-error' directive.
  • All packages type-check, and the vocs docs site builds with no dead links.
  • @cartesi/machine's suite is not run here — it needs an installed cartesi-machine emulator — and is untouched by this change.

A changeset marking all three packages major is included.

Mirror the node API changes of cartesi/rollups-node#793 in @cartesi/rpc,
and bubble them down to @cartesi/client and @cartesi/react.

New methods:

- cartesi_getEpochByVirtualIndex, fetching an epoch by its dense
  insertion rank (getEpochByVirtualIndex / useEpochByVirtualIndex)
- cartesi_getExecutedOutputCount and
  cartesi_getPendingExecutableOutputCount (getExecutedOutputCount /
  useExecutedOutputCount, getPendingExecutableOutputCount /
  usePendingExecutableOutputCount)
- cartesi_getNodeInfo, returning the chain id, the node version and the
  node's default block tag in one call (getNodeInfo / useNodeInfo). It
  replaces cartesi_getChainId and cartesi_getNodeVersion, which the node
  deprecated and which are now marked @deprecated here too.

New listing filters:

- from/to inclusive index ranges on listEpochs, listInputs, listOutputs
  and listReports
- a list of statuses on listEpochs, and a list of output types plus the
  new executed flag on listOutputs

Breaking changes:

- cartesi_getMatchAdvanced is now cartesi_getMatchAdvance, so the
  getMatchAdvanced action is getMatchAdvance, the useMatchAdvanced hook
  is useMatchAdvance and the GetMatchAdvanced* types are GetMatchAdvance*
- the node's application-level error codes moved out of the JSON-RPC
  reserved range (-31001/-31002 instead of -32001/-32002); they are now
  exported from @cartesi/rpc as errorCodes, along with the new batch,
  timeout and response-size-limit codes

Also reformats four @cartesi/react hooks that biome was already
reporting as unformatted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UJpa3KXxvUarBGpHvW8Qdb
@changeset-bot

changeset-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: fcff0f9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@cartesi/rpc Major
@cartesi/client Major
@cartesi/react Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@tuler
tuler changed the base branch from main to prerelease/v2-alpha August 14, 2026 16:01
The node rejects an empty `status` or `output_type` list with invalid
params, so type the list-valued filters as `NonEmptyArray<T>` rather than
`T[]`: `status: []` and `outputType: []` are now compile errors instead
of failed requests.

`listOutputs` maps the output types to selectors through the head of the
list separately, so the result stays a non-empty array for the type
checker, which `Array.prototype.map` would widen back to `Hex[]`.

Guarded by a `*.test-d.ts` suite in @cartesi/client, which needed vitest
type testing enabled there — CI runs `pnpm test` but no `tsc --noEmit`
over the test files, so without it the constraint would go unchecked.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UJpa3KXxvUarBGpHvW8Qdb
The upstream branch was force-pushed (ea9ccde -> a5d2cef), squashing the
fixups and adding a batch list-work budget on top.

- new error code -31004 (batch list item limit exceeded), exported as
  `errorCodes.batchListItemLimitExceeded`, with the `maxBatchListWork`
  (10000) and `defaultListLimit` (50) constants that define the budget:
  the node sums the effective limit of every list entry in a batch and
  rejects the whole batch before dispatching any of it
- the response-size budget is now documented as closing once exhausted,
  so every later entry of the batch gets -31003 too, even one whose
  response would still have fit
- the executed-output sync pattern gained a step: on a change of
  `getExecutedOutputCount`, diff the pending set from `listOutputs`
  against its previous result, rather than just re-reading it. The node
  documents a race-free execution cursor as future work
- the epoch watch pattern now separates discovery (advance `from`) from
  refresh (filter seen epochs by non-terminal status)
- `default_block` is documented as the node's finality contract

No wire-shape change: the two output counts got their own result schemas
upstream, but both are `{ data: UnsignedInteger }`, which the separate
return types here already matched. The API still rejects empty `status`
and `output_type` lists, so `NonEmptyArray` stands; the upstream
repository fix for empty type lists sits below that check.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UJpa3KXxvUarBGpHvW8Qdb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants