Skip to content

perf: reduce fetcher and evaluator calls in MeshTxBuilder - #849

Open
lisicky wants to merge 1 commit into
mainfrom
feat/tx-builder-fetch-efficiency
Open

lisicky wants to merge 1 commit into
mainfrom
feat/tx-builder-fetch-efficiency

Conversation

@lisicky

@lisicky lisicky commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

What

Cuts the provider calls MeshTxBuilder.complete() makes, and fixes two builds that could not complete at all.

Contents

mesh-transaction (MeshTxBuilder):

  • evaluateRedeemers skips evaluateTx and the serialization before it when nothing is witnessed by a Plutus script. Before, it ran once per coin-selection cost estimate on every transaction, including plain ADA sends.
  • Input and reference-script info is looked up first in what the builder already holds: selectUtxosFrom UTxOs, inputForEvaluation UTxOs and chainTx outputs. fetchUTxOs is called only for hashes still unknown.
  • Concurrent lookups of one hash share one request. A failed or empty response is no longer remembered, so a later complete() retries it instead of failing with "Couldn't find value information".
  • fetchCostModels runs alongside the UTxO fetches instead of before them.
  • Native (simple) script reference sources are now fetched and completed, including their scriptSize. Before, simpleScriptTxInReference without a hash and size crashed with TypeError: Cannot read properties of undefined (reading 'find'). Native-script inputs given by reference only are now completed too.
  • A reference script's hash is derived from scriptRef when the fetcher does not return scriptHash (e.g. ScalusEmulator).
  • clone() shares the fetched UTxO cache instead of deep-copying it for every coin-selection callback.

mesh-core-cst (OfflineEvaluatorScalus) and mesh-core-csl (OfflineEvaluator):

  • Fetched outputs are reused across evaluateTx calls, since tx outputs never change, and distinct hashes are fetched in parallel. The builder calls the evaluator once per coin-selection round, so each round used to refetch every input, collateral and reference input.
  • The cache is capped at 1000 tx hashes per evaluator. Empty or failed responses, and hashes missing a needed output, are dropped so they are refetched.
  • OfflineEvaluator no longer appends resolved UTxOs to the caller's additionalUtxos array.

Provider calls, before → after

Measured with ScalusEmulator behind a call-recording proxy (provider-calls.test.ts):

Scenario Before After
ADA send, evaluator set evaluateTx ×1 (×1+k with extra selection rounds) 0
Spend of a chainTx output given as hash/index fetchUTxOs for an unsubmitted hash, then "Couldn't find value information" 0 fetches, builds and submits
Native script by reference without hash/size crash 1 fetch per hash, builds and submits
Two script-spend builds with one OfflineEvaluatorScalus fetchUTxOs ×4 ×2
OfflineEvaluator, same tx evaluated twice fetchUTxOs ×10 ×5

No public API changes. The protected getUTxOInfo / queryAllTxInfo keep their signatures.

Validation

npm run build:mesh
cd packages/mesh-transaction && NODE_OPTIONS=--experimental-vm-modules npx jest
cd packages/mesh-core-cst && npm test
cd packages/mesh-scalus-emulator && npm test
cd packages/mesh-core-csl && npx jest test/offline-providers/evaluator.test.ts
  • mesh-transaction: 156 tests pass, including the new provider-calls.test.ts. script-tx-fetcher and script-tx-fail fail to load under --experimental-vm-modules on main too, because they import dist through require. Both pass without the flag.
  • mesh-core-cst (179 tests) and mesh-scalus-emulator (24 tests) pass.
  • In mesh-core-csl/test/offline-providers/evaluator.test.ts the new fetch assertions pass. Four budget assertions in that file already fail on main: expected steps differ after the cost-model update (e.g. 164980381 vs 164973765).

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