Skip to content

Viewer: re-run a transaction's scripts in the browser (Script Lab) - #208

Open
satran004 wants to merge 1 commit into
viewer/julc-foundationfrom
viewer/script-runs
Open

satran004 wants to merge 1 commit into
viewer/julc-foundationfrom
viewer/script-runs

Conversation

@satran004

Copy link
Copy Markdown
Member

Stacked on #206 (Script Lab foundation), which is stacked on #204. Part of #207: PR 2 of the Script Lab series.

What users get

A transaction's Scripts tab gets a Re-run in your browser button. It re-executes every script of the transaction with julc, using the cost model and protocol version of the epoch it ran in, and compares the result with the budget declared on chain.

Each script card shows:

  • a verdict:
    • Passed / Failed / Out of budget
    • Reproduced exactly, when CPU and memory match the declared ex-units to the unit
    • Reproduced · declared with a 20% margin, when the declared budget is this run scaled uniformly (the builder's safety margin)
  • julc's CPU and memory against the declared budget
  • traces, the error and the last builtins called (on failure)
  • What the validator saw: the exact ScriptContext, as a decoded tree, JSON or CBOR
  • notes on anything that may differ from the ledger, e.g. "the viewer added the other 2 redeemers in the context"

The panel also shows a summary (e.g. "3 reproduced exactly"). For transactions that failed phase 2 on chain, it says so up front.

Like decoding, nothing loads until the user clicks, or opts in with the shared "Run Script Lab automatically" setting.

How it works

  • replay/build.ts (pure, unit-tested on recorded Mainnet fixtures) rebuilds a julc MockTransaction per redeemer from Yaci Store data:

    • inputs and reference inputs in ledger order
    • values and mint sorted by policy and asset name
    • withdrawals and votes in ledger credential order
    • inline and hashed datums, required signers
    • validity range: slot → POSIX time from Shelley constants for Mainnet, preprod and preview, and /genesis for devnets
  • Inputs: the epoch's cost_models_raw and tx limits.

  • Purpose names are normalised (spend/spending, proposing, …).

  • Runs it can't rebuild are explained: Byron addresses, proposal scripts, unsupported certificate kinds.

  • replay/fix-context.ts works around julc 0.1.0-pre18 context gaps, all now in WASM API asks from Yaci Viewer Script Lab: full redeemer set, tx-CBOR evaluation, profiling julc#244:

    1. Multi-asset values not in ledger order → re-sorted where the ledger puts values. Datums are untouched.
    2. Only the evaluated script's redeemer in txInfoRedeemers → every run's own entry is collected and the complete map is put back, in ledger order. This fixes withdraw-zero validators.
    3. An input datum given with its hash is dropped → it is handed over inline (V2/V3) or without the hash (V1), and the on-chain hash is restored. Witnessed datums are added to txInfoData.
    4. V1 withdrawals and datums encoded as maps instead of lists of pairs → converted.

    Corrected contexts are re-run with vm.evaluate, and every result says what was corrected.

  • cbor.ts: a Plutus-data encoder (Plutus-library style), round-trip tested.

  • replay/load.ts fetches only on click:

    • epoch parameters, falling back to the latest with a note
    • genesis
    • datums by hash
    • script bodies the store left out
    • certificates and votes only when a script runs for one (some stores don't allow those endpoints from the browser)

Results on Mainnet (playground store, headless Chrome)

Sample Runs Reproduced exactly With builder margin Other passes Failed Couldn't run
40 recent transactions (2026) 108 80 5 23 0 0
10 transactions from block 9,000,000 (2023, Plutus V1, protocol 8) 17 0 0 8 9 0

The earlier spike, before the workarounds, had 3 of 16 recent runs failing.

Known limits

  • Plutus V1 history: julc 0.1.0-pre18's V1 contexts still differ from the ledger in places. V1/V2 translation fixes are on julc main.
  • Proposal (guardrail) scripts: planned with the governance work (PR 6).
  • Certificates: only stake registration, deregistration and delegation are rebuilt, so other certificate kinds can't be replayed yet.
  • Devnet: tested on a local devnet too, but its only script transaction runs a proposal script, which shows the "not supported yet" message.

Tests

  • npm run check: 0 errors, 0 warnings.
  • vitest: 47 passing. New:
    • the transaction rebuild on 3 recorded Mainnet transactions (withdraw-zero V2, V3, mint)
    • slot conversion
    • ledger ordering of withdrawals and votes
    • skip reasons and purpose names
    • context fixes
    • CBOR encoding
  • Playwright script-lab.spec.ts: both tests pass against a production build in Chrome. The new test re-runs a transaction and opens the ScriptContext.
  • 19 devnet smoke tests pass.

🤖 Generated with Claude Code

The Scripts tab of a transaction can now re-run every script with julc: the transaction is rebuilt
from Yaci Store data and each redeemer runs with the cost model and protocol version of its epoch.
Results show julc's budget next to the declared one ("Reproduced exactly", or reproduced with the
builder's margin), traces, the failure and last builtins, and the exact ScriptContext.

- replay/build.ts: MockTransaction per redeemer in ledger order (inputs, values, mint, withdrawals,
  votes), slot -> POSIX time (Shelley constants for public networks, /genesis for devnets),
  epoch cost models and tx limits; explains runs it can't rebuild (Byron addresses, proposals,
  unsupported certificates) and adds notes on known gaps.
- replay/fix-context.ts: workarounds until julc builds ledger-exact contexts (julc#244): asset
  values in ledger order, the complete redeemer map (withdraw-zero validators), datums given by
  hash, and V1 list shapes. Corrected contexts are run again with the VM; each result says what
  changed.
- cbor.ts: Plutus data encoder (Plutus-library style), round-trip tested.
- load.ts: fetches the rest only on click; certificates and votes only when a script needs them;
  falls back to the latest parameters when an epoch's are missing.

Mainnet checks: 40 recent transactions, 108 runs, all passed (80 exact, 5 with builder margin).
2023 Plutus V1 history: 8 of 17 runs pass; julc's V1 fixes after pre18 should improve this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copy link
Copy Markdown

Initial automated review · Aster

Hi @satran004, thanks for the PR! 🙏 This is an automatic first check by an AI reviewer. It does not replace maintainer review and may be wrong.

Reviewed commit: 9f45fd9624ba499295d8cfec37e1ebe420e4beff

Issues found:

  • applications/viewer/src/lib/julc/ScriptRuns.svelte:48 — Opening another transaction through search while the Scripts tab is active reuses results keyed only by purpose/index, so its cards can show the previous transaction's verdict, budget and ScriptContext. Please reset/key this state by transaction hash and ignore stale in-flight results.
  • applications/viewer/src/lib/julc/replay/load.ts:47 — A transaction can contain key-authorized votes or certificates without vote/cert redeemers; these guards silently omit them from the rebuilt context, changing the result of scripts that inspect them. Please load those collections independently of redeemer purposes, or flag the replay as incomplete.
  • applications/viewer/src/lib/julc/replay/build.ts:207 — The Blockfrost delegation endpoint returns a bech32 pool1… ID, but julc's certificate builder decodes poolId as hex, so supported stake-delegation replays fail before evaluation. Please decode the pool ID to its hex key hash.
  • applications/viewer/src/lib/julc/replay/build.ts:272 — A global datum lookup can find a datum witnessed by an earlier transaction; adding it for a hash-only output inserts an entry that was absent from this transaction's txInfoData, which can change validation results. Please use the transaction's actual datum witnesses rather than infer witness membership from lookup success.

Not tested: Static review only; I did not run svelte-check, Vitest, Playwright, or browser/devnet replays. No CI checks were reported for this head at review time.

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.

2 participants