Track the rollups-node JSON-RPC API changes - #161
Merged
tuler merged 1 commit intoAug 24, 2026
Conversation
🦋 Changeset detectedLatest commit: 3d6c2bc The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
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
force-pushed
the
claude/jsonrpc-api-changes-cartesi-xnjga6
branch
from
August 24, 2026 18:58
0760176 to
0041415
Compare
Mirror the JSON-RPC API changes of the Cartesi node in @cartesi/rpc, and bubble them down to @cartesi/client and @cartesi/react. Derived from cartesi/rollups-node#793, which has since merged into next/2.0 as 7558af6, so this is no longer a forward-looking port. It was verified against the merged jsonrpc-discover.json rather than the pull request diff: @cartesi/rpc declares exactly the 28 methods the merged specification defines, and every schema and parameter change between the pre-793 base (9bdd988) and merged next/2.0 is reflected here. Cross-checked against internal/jsonrpc/api/params.go, internal/jsonrpc/jsonrpc.go and internal/model/models.go. New methods: - cartesi_getEpochByVirtualIndex, fetching an epoch by its dense insertion rank (getEpochByVirtualIndex / useEpochByVirtualIndex) - cartesi_getExecutedOutputCount and cartesi_getPendingExecutableOutputCount (getExecutedOutputCount / useExecutedOutputCount, getPendingExecutableOutputCount / usePendingExecutableOutputCount). The executed count is monotone and meant to be polled for change detection; the pending count is a gauge and is not. - 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 The node rejects an empty status or output_type list with invalid params, so the list-valued filters are typed as NonEmptyArray<T> rather than T[]: `status: []` and `outputType: []` are compile errors instead of failed requests. listOutputs maps the output types to selectors through the head of the list separately, so the result stays non-empty for the type checker, which Array.prototype.map would widen back to Hex[]. The constraint is 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. Input completion changes, which landed on next/2.0 alongside but not as part of #793: - InputStatus loses its resource-limit members. The node collapsed OUTPUTS_LIMIT_EXCEEDED, REPORTS_LIMIT_EXCEEDED, CYCLE_LIMIT_EXCEEDED, TIME_LIMIT_EXCEEDED and PAYLOAD_LENGTH_LIMIT_EXCEEDED into the remaining outcomes, leaving NONE, ACCEPTED, REJECTED, EXCEPTION and MACHINE_HALTED. waitForInput listed four of them under rejectErrors; it now aborts on EXCEPTION, MACHINE_HALTED and REJECTED, which is every terminal status other than ACCEPTED — and no longer omits a failure status the way the old list omitted REPORTS_LIMIT_EXCEEDED. - Input gains exception_data / exceptionData, the raw guest-provided CMIO exception payload, non-null only when the status is EXCEPTION and empty-encoded as 0x. The bytes are passed through undecoded, matching how raw_data is handled. 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 (-32040), timeout (-32070), response-size-limit (-31003) and batch-list-work (-31004) codes, plus the maxBatchSize (100), maxBatchListWork (10000) and defaultListLimit (50) constants that bound a batch - InputStatus shrank, as described above Batch requests needed no transport change — the underlying json-rpc-2.0 client already batches — so they are documented rather than implemented, including the two budgets that apply beyond the entry count: the response-size budget closes once exhausted, so every later entry gets -31003 even if its response would still have fit, and the list-work budget rejects the whole batch with a single -31004 before dispatching anything. Neither meters the COUNT queries behind pagination nor offset traversal, so a deep offset over a broad filter can still make the database scan and discard rows before the requested page. Two OpenRPC typing fixes needed no code change: prev_randao and voucher value are now UnsignedInteger256 in the specification, and both were already 256-bit-safe here. 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
tuler
force-pushed
the
claude/jsonrpc-api-changes-cartesi-xnjga6
branch
from
August 24, 2026 19:01
0041415 to
3d6c2bc
Compare
tuler
marked this pull request as ready for review
August 24, 2026 19:03
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.
Mirrors the JSON-RPC API changes of the Cartesi node in
@cartesi/rpc, and bubbles them down to@cartesi/clientand@cartesi/react.This started as a forward-looking port of cartesi/rollups-node#793, which has since merged into
next/2.0as7558af6, so what follows is no longer provisional. It was re-verified against the merged specification rather than against the pull request diff:@cartesi/rpcdeclares exactly the 28 methods the mergedjsonrpc-discover.jsondefines — no gaps, no leftovers — and every schema and parameter change between the pre-793 base (9bdd988) and mergednext/2.0is reflected here. Cross-checked againstinternal/jsonrpc/api/params.go,internal/jsonrpc/jsonrpc.goandinternal/model/models.go.New methods
@cartesi/client@cartesi/reactcartesi_getEpochByVirtualIndexgetEpochByVirtualIndexuseEpochByVirtualIndexcartesi_getExecutedOutputCountgetExecutedOutputCountuseExecutedOutputCountcartesi_getPendingExecutableOutputCountgetPendingExecutableOutputCountusePendingExecutableOutputCountcartesi_getNodeInfogetNodeInfouseNodeInfogetNodeInforeturns the chain id, the semantic node version and the node's default block tag in a single call. It replacesgetChainIdandgetNodeVersion, which the node deprecated and which are now marked@deprecatedhere too — they still work.defaultBlockis 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, onlistEpochs,listInputs,listOutputsandlistReports.listEpochstakes a list of statuses (status?: EpochStatus | NonEmptyArray<EpochStatus>).listOutputstakes a list of output types (outputType?: OutputType | NonEmptyArray<OutputType>) and a newexecuted?: booleanfilter.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/rpcand re-exported by@cartesi/client:status: []andoutputType: []are compile errors rather than failed requests. Note this is stricter than a plain array in both directions — it also rejects anEpochStatus[]-typed variable, so callers building lists dynamically should type them asNonEmptyArray<EpochStatus>.Input completion changes
These two landed on
next/2.0alongside — but not as part of — #793. Now that #793 has merged there is a single node API, and leaving these out would mean shipping a client that promises statuses the node cannot return and drops a field it does return.InputStatuslost its resource-limit members. The node collapsedOUTPUTS_LIMIT_EXCEEDED,REPORTS_LIMIT_EXCEEDED,CYCLE_LIMIT_EXCEEDED,TIME_LIMIT_EXCEEDEDandPAYLOAD_LENGTH_LIMIT_EXCEEDEDinto the remaining outcomes, so the union is nowNONE | ACCEPTED | REJECTED | EXCEPTION | MACHINE_HALTED. Code switching on a removed member no longer compiles.InputgainedexceptionData: Hex | null(exception_dataon the wire) — the raw guest-provided CMIO exception payload, non-null only whenstatusisEXCEPTION, with an empty payload encoded as0x. The bytes are passed through undecoded, the same treatmentrawDatagets.waitForInputwithrejectErrorslisted four of the removed statuses; it now aborts onEXCEPTION,MACHINE_HALTEDandREJECTED, which is every terminal status other thanACCEPTED. That also closes a pre-existing gap: the old list omittedREPORTS_LIMIT_EXCEEDED, so an input failing that way slipped through the guard.Synchronization patterns
These are the node's documented patterns, mirrored in the JSDoc and docs pages of all three packages:
fromto 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.getExecutedOutputCount(monotone) and, when it changes, re-query the bounded executable-output working set withexecuted: falseandoutputType: ["Voucher", "DelegateCallVoucher"], then diff that pending set against the previous result to identify the executions.getPendingExecutableOutputCountis a gauge and must not be used for change detection.No resume cursor over the
executedfilter 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_getMatchAdvancedwas renamed tocartesi_getMatchAdvance, following the node. The action is nowgetMatchAdvance, the hook isuseMatchAdvance(withmatchAdvanceOptions/matchAdvanceQueryKey), andGetMatchAdvancedParams/GetMatchAdvancedReturnTypeare nowGetMatchAdvanceParams/GetMatchAdvanceReturnType. No back-compat aliases were kept — these packages are on2.0.0-alphaprereleases and the node made the same break. The entity typeMatchAdvancedkeeps its name, matching the node'sMatchAdvancedGetResultschema.-31002(was-32002) and resource not found is now-31001(was-32001).InputStatusshrank, as described above.Error codes and batch limits
@cartesi/rpcnow exports the node's codes aserrorCodes, 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) anddefaultListLimit(50).Two budgets apply to a batch beyond its entry count:
-31003; the budget then closes, so every later entry gets-31003too, even one that would still have fit.limitof every list entry, counting an omitted or zero limit asdefaultListLimitand capping each entry atmaxBatchListWork. A total abovemaxBatchListWorkrejects the whole batch with a single-31004and dispatches nothing. Being raised before dispatch,-31004is a batch-level error and is not attributed to any one method.Neither budget meters the
COUNTqueries behindpaginationor offset traversal, so a deepoffsetover a broad filter can still make the database scan and discard rows before the requested page.offsetitself is bounded to the signed 64-bit range — far aboveNumber.MAX_SAFE_INTEGER, so only a deliberately out-of-range value is rejected.Notes
json-rpc-2.0client already batches — so they are documented rather than implemented.{ data: UnsignedInteger }, which the separate return types here already matched. No wire-shape change.statusandoutput_typelists with invalid params, soNonEmptyArray<T>continues to match node behavior.prev_randaoand vouchervalueare nowUnsignedInteger256in the spec. Both were already 256-bit-safe here —prev_randaoisHexon the wire converted withhexToBigInt, andvalueis aHexNumber.chainIdinNodeInfois anumber, matching what the existinggetChainIdaction returns.listOutputsmaps output types to selectors through the head of the list separately, becauseArray.prototype.mapwould widen the tuple back toHex[]. That keeps non-emptiness proven rather than asserted."invalid request"split into"Invalid Request","Invalid request ID","Unsupported JSON-RPC version","Parse error"). Nothing here matches on message text —@cartesi/rpcexports codes — so this is not tracked.@cartesi/reacthooks (useApplication,useCommitments,useTournaments,useWithdrawals) were already failingbiome checkon the base branch for import formatting; this branch lets biome fix them sopnpm lintpasses.Testing
pnpm lintandpnpm check-typesclean across the workspace.@cartesi/client(12),@cartesi/react(122),@cartesi/codec(70) and@cartesi/rollup(24) suites pass. Coverage added for the newnodeInfoConverter, the renamed match-advance query keys, the stringification of the newfrom/tobigints in every listing query key, and anEXCEPTIONinput carrying a non-nullexceptionData.__tests__/params.test-d.tstype suite, which required enabling vitest type testing in@cartesi/client— CI runspnpm testbut notsc --noEmitover test files, so without it a regression would go unnoticed. Verified non-vacuous: reverting the type toEpochStatus[]makes the suite fail, includingUnused '@ts-expect-error' directive. It earned its keep on theexception_datachange too, failing the build on a now-incompleteInputfixture that a value-only run would have accepted.@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
majoris included.