Skip to content

feat(core-cst): evaluate with a reusable Scalus TxEvaluator - #860

Merged
lisicky merged 1 commit into
MeshJS:mainfrom
nau:pr-a/scalus-1.4-tx-evaluator
Nov 1, 2026
Merged

lisicky merged 1 commit into
MeshJS:mainfrom
nau:pr-a/scalus-1.4-tx-evaluator

Conversation

@nau

@nau nau commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • OfflineEvaluatorScalus now uses one Scalus TxEvaluator with its own ScriptCache (64 entries, kept across rebuilds) instead of calling evalPlutusScripts on every evaluateTx.
  • The evaluator is built on first use and rebuilt only when slotConfig or costModels change (compared by value, so in-place edits count too). The script cache survives rebuilds.
  • UTxOs go in as the [input, output] CBOR pairs that TransactionUnspentOutput.toCbor() already gives, so the hand-built CBOR map is gone.
  • The public behaviour does not change: same constructor, same results, same tag mapping, same error on an unknown tag, same fetcher resolution of inputs, collateral and reference inputs. Scalus still loads through a native dynamic import(), so the CJS build keeps working. Where a runtime cannot import() an ES module (Jest without --experimental-vm-modules), the error now says so, and a later call tries again.
  • One difference: hex of odd length now fails with a TypeError. Before, Buffer.from(..., "hex") silently dropped the last digit. Hex with invalid characters still fails earlier, in cardano-sdk, as before.

Why

MeshTxBuilder calls the evaluator on every coin-selection round. With a reusable evaluator each script is hashed and decoded once. On 55,001 requests recorded from Midgard's test suites, TxEvaluator with a ScriptCache takes 0.98x the time of Aiken WASM (Lucid's evaluator), with identical execution units, and the cache alone saves about 17–25%.

Tests

  • offline-evaluator-scalus.test.ts: the pinned budget is unchanged (this also checks the UTxO pair encoding, including a reference-script UTxO). New tests check that two calls build one TxEvaluator and leave one script in the cache, that doubled V2 cost models double the budget and restoring them restores it, and that a moved slotConfig.zeroTime takes effect – all while one ScriptCache is kept.
  • On current main (Scalus 1.4.1): mesh-core-cst 180 + 3 Scalus tests, test:package (ESM and CJS) 2/2, mesh-scalus-emulator 24, mesh-transaction 249/249 (35 suites) pass.

Switch OfflineEvaluatorScalus from a per-call evalPlutusScripts to one
Scalus TxEvaluator with its own ScriptCache. The evaluator is built on
first use and rebuilt only when slotConfig or costModels change; the
script cache survives rebuilds. UTxOs are passed as the [input, output]
pairs TransactionUnspentOutput already encodes, so the hand-built CBOR
map goes. A runtime that cannot import() Scalus (Jest without
--experimental-vm-modules) gets an error that says so.

MeshTxBuilder evaluates on every coin-selection round, so reuse pays off:
on recorded Midgard requests, TxEvaluator with a ScriptCache takes 0.98x
the time of Aiken WASM, and the cache alone saves about 17-25%.
@nau
nau force-pushed the pr-a/scalus-1.4-tx-evaluator branch from f5f2aff to 6ebe5c2 Compare October 30, 2026 10:45
@nau

nau commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

Rebased on current main. b42a31d already bumps Scalus to 1.4.1 and fixes the governance tests the same way this PR did, so I dropped that commit. This PR is now only the OfflineEvaluatorScalus change: one reusable TxEvaluator with a script cache. On main + this commit, mesh-core-cst (180 + 3), mesh-scalus-emulator (24) and mesh-transaction (249/249) pass.

@lisicky lisicky left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! The reusable TxEvaluator + ScriptCache is what the default evaluator in #866 builds on. Merging.

@lisicky
lisicky merged commit 3b41af8 into MeshJS:main Nov 1, 2026
1 check passed
lisicky added a commit that referenced this pull request Nov 1, 2026
Resolves the conflicts with #860 (reusable Scalus TxEvaluator, which this
branch carried as a copy) and with the Scalus 1.4.1 test fixes on main:

- offline-evaluator-scalus.ts and its test keep this branch's version,
  which already holds #860's content plus the default-evaluator work
  (#862, #866).
- offline-evaluator-scalus-cases.test.ts keeps its Scalus expectations.
  Main's edits were to the CSL evaluator test it was copied from, so that
  test (mesh-core-csl/test/offline-providers/evaluator.test.ts) is
  restored from main rather than staying deleted.
- script-tx-fail / script-tx-fetcher tests import MeshTxBuilder from
  @meshsdk/transaction, as on main.
@nau
nau deleted the pr-a/scalus-1.4-tx-evaluator branch November 2, 2026 17:21
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.

2 participants