fix(js): preserve cost-model key order for Plutus builds#6
Open
matiwinnetou wants to merge 1 commit into
Open
Conversation
DevKit/Blockfrost-style providers return Plutus cost models as a map keyed by
numeric indices ("000"."165"). JS object iteration hoists canonical
integer-string keys ("100") ahead of zero-padded ones ("000"), so
JSON.stringify emitted them out of order; CCL rebuilds the per-language cost
array in document order, so the scrambled order produced a wrong
script-integrity hash and the node rejected Plutus txs with
PPViewHashesDontMatch. (Go's json.Marshal sorts keys; Python preserves provider
order — both unaffected.)
normalizeCostModels() converts any numerically-keyed language to CCL's ordered
cost_models_raw array form (List<Long>, consumed in order ahead of the
order-sensitive named map), which serializes order-stably. Named-operation cost
models are left as-is. The Plutus-mint DevKit round-trip now submits with the
devnet's real fetched cost models (dropping the earlier workaround), and offline
unit tests cover the conversion.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Summary
Fixes a real JS-wrapper correctness bug, found while adding the JS Plutus-mint DevKit test in #5: passing provider-fetched cost models into a Plutus
build()produced a transaction the node rejects withConwayUtxowFailure (PPViewHashesDontMatch …).Root cause
Yaci DevKit / Blockfrost-style backends return Plutus cost models as a map keyed by numeric indices, e.g.
{"PlutusV2": {"000": 100788, …, "165": 10}}. JavaScript object semantics iterate canonical integer-string keys ("100") in ascending order before zero-padded ones ("000"), soJSON.stringifyemits them out of order. CCL rebuilds each language's cost array in document order, so the scrambled order yields a wrong script-integrity (cost-model) hash → the node rejects the tx.This is JS-specific:
json.Marshalsorts keys lexicographically, which for zero-padded keys equals numeric order.jsonpreserves the provider's order.Fix
normalizeCostModels()inwrappers/js/src/index.js, applied inquicktx.build(): any numerically-keyed language is converted to CCL's orderedcost_models_rawarray form (aList<Long>that CCL consumes directly in list order, ahead of the order-sensitive named map). Arrays serialize order-stably, so the cost-model order is now canonical regardless of JS key hoisting. Named-operation cost models (which JS does not reorder) are left as acost_modelsmap untouched, and params without cost models pass through unchanged.Verification
normalizeCostModelsunit tests (numeric → orderedcost_models_raw, named-op left as-is, no-cost-models pass-through). Full JS offline suite green locally (71 pass).quicktx.integration.test.jsnow submits with the devnet's real fetched cost models — the earlier workaround (dropping cost models to use the lib's built-in set) is removed, so this test now genuinely exercises the fix end-to-end.Closes the
P1cost-model-ordering item inTODO.md§3. The §2c provider helpers should pass params through an equivalent normalization.