Repository navigation
Conversation
solidsnakedev
left a comment
There was a problem hiding this comment.
Thanks, the refusal is right, and the bound is exact.
Two changes before merge:
- The new
Hash.symbolstringifies the raw variant, so aBufferkey hash and aUint8Arraywith the same bytes now hash differently.Equal.equalscompares hashes first (effectEqual.ts:47), soEqual.equals(makeScriptPubKey(bytes), makeScriptPubKey(Buffer.from(bytes)))istrueon main andfalsehere, and a script decoded from aBufferno longer equals the same script decoded from hex. A structural hash fixes both:Hash.array(Array.from(keyHash))as inAssetName.ts:66,Hash.hashfor the slot andrequired, combined with the tag. requiredis anint64(conway.cddl:402), and the ledger allows a negative one (Allegra/Scripts.hs:174-175). Please also refuse a value below-Number.MAX_SAFE_INTEGER, with a test.
Smaller: throwing the module's NativeScriptError instead of a plain Error lets callers catch it by tag.
…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. `required` is an int64 and the ledger accepts a negative one, so the lower bound is reachable the same way the upper one is, and is refused with it. A script read off the chain may carry any uint64, so this is reachable on decode and not only when authoring one. The refusal is the module's `NativeScriptError`, so callers can catch it by tag. `Hash.symbol` hashes the variant structurally instead of 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. Structurally means a key hash hashes from its bytes rather than from its container, so a `Buffer` and a `Uint8Array` over the same bytes still hash alike and `Equal.equals`, which compares hashes first, still holds for them. `fromJSON`, the inverse that found this, is left for its own change.
96a7a23 to
a10ca13
Compare
|
Both changes are in, and the smaller one too. Rebased onto
Confirmed before fixing it, because it is worth being exact about which side was wrong: The hash is now structural, in a
Done — the bound is now
Done, with a test asserting the class rather than the message. Gate, after a clean
|
One of the four fixes asked for in the closing comment on
#619 — smallest fix plus its test, nothing else.
The defect
The cardano-cli JSON form carries
slotandrequiredas JSON numbers, so a CDDL uint64 aboveNumber.MAX_SAFE_INTEGERhas no exact representation in it.Number(script.slot)returned adifferent 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.symbolstops going throughtoJSON, which would now throw for exactly these scripts: aHashSetholding 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, andHash.symbolofftoJSON.packages/evolution/test/NativeScripts.JSON.test.ts— at the bound, above it, and the two scriptsthat used to hash equal.
Deliberately left out:
fromJSONand itsNativeScriptJSONmodule, as asked.Verification
All six CI tasks run locally off
ci.ymlagainst 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.