Skip to content

fix(native-scripts): refuse a JSON slot above 2^53-1 rather than truncate it - #711

Open
jorbuedo wants to merge 1 commit into
IntersectMBO:mainfrom
jorbuedo:slice/native-scripts-json-slot
Open

jorbuedo wants to merge 1 commit into
IntersectMBO:mainfrom
jorbuedo:slice/native-scripts-json-slot

Conversation

@jorbuedo

@jorbuedo jorbuedo commented Oct 22, 2026 •

Copy link
Copy Markdown

One of the four fixes asked for in the closing comment on
#619 — smallest fix plus its test, nothing else.

NativeScripts.toJSON rounds a slot above 2^53 without saying so. A refusal is enough here; fromJSON can be its own PR.

The defect

The cardano-cli JSON form carries slot and required as JSON numbers, so a CDDL uint64 above
Number.MAX_SAFE_INTEGER has no exact representation in it. Number(script.slot) returned a
different slot and reported nothing.

A script read off the chain may carry any uint64, so this is reachable on decode, not only when
authoring one.

One consequence worth naming

Hash.symbol stops going through toJSON, which would now throw for exactly these scripts: a
HashSet holding one would fail. It hashes the variant directly instead — and before the refusal,
two scripts differing only above the bound hashed equal.

Contents

  • packages/evolution/src/NativeScripts.ts — the range refusal, and Hash.symbol off toJSON.
  • packages/evolution/test/NativeScripts.JSON.test.ts — at the bound, above it, and the two scripts
    that used to hash equal.
  • A patch changeset.

Deliberately left out: fromJSON and its NativeScriptJSON module, as asked.

Verification

All six CI tasks run locally off ci.yml against this base (lint, type-check, test, build,
check:dts, docgen): green. packages/evolution: 1918 passed, 75 skipped, 0 failed. The new test file fails on this base without the source change, so it does exercise it.
devnet's suite needs Docker and was not run here.

…cate it

The cardano-cli JSON form carries `slot` and `required` as JSON numbers, so a
CDDL uint64 above `Number.MAX_SAFE_INTEGER` has no exact representation in it.
`Number(script.slot)` returned a different slot and reported nothing.

A script read off the chain may carry any uint64, so this is reachable on decode
and not only when authoring one.

`Hash.symbol` stops going through `toJSON`, which would now throw for exactly
these scripts: a `HashSet` holding one would fail, and before the refusal two
scripts differing only above the bound hashed equal.

`fromJSON`, the inverse that found this, is left for its own change.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant