Skip to content

feat(minibf): add /scripts/{script_hash}/redeemers endpoint - #1199

Draft
slowbackspace wants to merge 4 commits into
mainfrom
feat/minibf-scripts-redeemers
Draft

feat(minibf): add /scripts/{script_hash}/redeemers endpoint#1199
slowbackspace wants to merge 4 commits into
mainfrom
feat/minibf-scripts-redeemers

Conversation

@slowbackspace

@slowbackspace slowbackspace commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Closes #1077.

What

  • New endpoint: GET /scripts/{script_hash}/redeemers with count/page/order pagination and the Blockfrost 404/empty-page semantics.
  • Candidate blocks come from a new index-time script_redeemers dimension, streamed through blocks_by_script_redeemers_stream in dolos-cardano. The endpoint scans that dimension alone — see the dimension section below for why query-time derivation cannot work.
  • Redeemer-to-script matching lives in a shared redeemer_script_hash function. It now covers spend, mint, cert, and reward. As a side effect, /txs/{tx_hash}/redeemers now fills script_hash for cert and reward redeemers (it returned an empty string before).
  • Phase-2-failed txs are skipped: db-sync stores no redeemers for them, so Blockfrost lists none. A failed tx also consumes only its collateral, so its spend redeemers point at inputs the resolver never prepared.
  • Docs: one row added to the MiniBF endpoint table.

Verification

  • Unit tests resolve every purpose against a hand-built Conway tx, including the vote/propose None cases and key-credential negatives.
  • Route tests follow the standard matrix: happy path, pagination 400s, 404s, faulty-store 500.
  • Official blockfrost-tests suite against a synced preview node: the strict golden fixture for this endpoint (112 rows, exact db-sync fees) passes, plus all pagination-error fixtures and the txs/:tx/redeemers regression tests.
  • New upstream fixtures covering cert and reward purposes on both endpoints (test: cover cert and reward redeemer purposes on all networks blockfrost/blockfrost-tests#105) pass against this branch and against live Blockfrost on preview.
  • Descending order equals reversed ascending order over the script's full history.

The script_redeemers dimension

Deriving candidates at query time cannot be complete: an execution through a reference script carries no script bytes, and governance redeemers (vote, propose) leave no side effect that any dimension tags. So the endpoint is backed by an index-time dimension, following the precedent of #974 (ACCOUNT_WITHDRAWALS) and #976 (POOL_CERTS):

  • index_block resolves each redeemer to its script — a shared matcher in pallas_extras, covering all six purposes including vote (the voter's credential) and propose (the proposal's policy script) — and tags the executed script under script_redeemers.
  • The endpoint scans that dimension alone. The tag is block-level, so the handler still matches each redeemer to pick rows.
  • Tags are a superset by design: phase-2-failed txs and governance purposes are tagged. The Blockfrost rules (no redeemers for failed txs; no vote/propose in the schema) stay query-time filters, so output matches deployed Blockfrost exactly.
  • Storage cost measured on preview: ~1.7 entries per block at current traffic, ≈16 B payload each — single-digit percent of the index store, nothing on archive or state.
  • The stele goldens re-pin deliberately: the canonical indexes layer carries one record per dimension, so its diffId and the inscription digest change.

Operational note (release-note material): a store synced before this change serves only post-upgrade history on /scripts/{script_hash}/redeemers. Full history needs a store synced from scratch, or a snapshot cut from one — the same transition model as #974/#976.

Known limits / follow-ups

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ffe2f3a2-124f-4bfc-bbc6-6b13b7df2df9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@slowbackspace
slowbackspace force-pushed the feat/minibf-scripts-redeemers branch 3 times, most recently from e78f74c to 559b91b Compare August 13, 2026 13:19
Scan the union of the archive dimensions a script can leave traces in
(script bytes, payment credential, policy, stake credential), then match
each redeemer to its script per tx. This finds executions through
reference scripts, which carry no script bytes in the tx.

The redeemer-to-script matching now also covers cert and reward
purposes, so /txs/{tx_hash}/redeemers reports script_hash for those
too.
… scan

- blocks_by_tag_stream now delegates to blocks_by_tags_stream: one copy
  of the chunked cursor logic remains
- the scripts handler reuses log_and_500 instead of hand-rolled
  tracing + 500 closures
- the RedeemerTag-to-purpose policy (including the vote/propose gap)
  lives in mapping.rs, once per generated enum
- by_hash_redeemers keeps HTTP concerns; scan_script_redeemers owns the
  scan loop, with prices_for_epoch as the memoized pparams lookup

No behavior change: route tests and the official Blockfrost fixtures
pass unchanged.
The scripts redeemers scan derives candidates from side-effect
dimensions, and governance redeemers leave no side effect any dimension
tags. Resolve the redeemer-to-script matching once, at index time, and
tag each executed script under a new script_redeemers dimension.

- the matcher moves to pallas_extras with a generic error type and
  gains vote and propose arms (voter credential, proposal policy
  script); the endpoints keep their Blockfrost-parity output, so the
  new purposes surface only as tags for now
- index_block tags every resolvable execution, phase-2-failed txs
  included: tags are candidates, the Blockfrost rule stays a query-time
  filter
- the scripts redeemers union gains the new dimension as its first key;
  stores synced before this commit lack the tags, and the union keeps
  those complete
- redb3 (deprecated backend) gets the table and arms so the dimension
  works there too
- the stele goldens re-pin: the canonical indexes layer carries one
  record per dimension, so its diffId, record count and inscription
  digest change deliberately
The union of side-effect dimensions existed to keep old stores complete
while the script_redeemers dimension was new. Precedent says the
transition story is a resync (#974, #976 shipped their dimensions the
same way), so drop the union: the endpoint scans the exact dimension
and nothing else. This removes the noise cases entirely — deposits into
a script address and transfers of a policy's assets no longer produce
candidate blocks.

With the union gone, nothing needs a multi-tag scan anymore. Remove
blocks_by_tags_stream and restore blocks_by_tag_stream to its original
single-tag form.

A store synced before the dimension serves only post-upgrade history on
this endpoint; full history needs a store synced from scratch or a
snapshot cut from one.

Also rewraps a goldens doc comment that failed the nightly fmt gate.
@slowbackspace
slowbackspace force-pushed the feat/minibf-scripts-redeemers branch from 559b91b to 14602cc Compare August 13, 2026 13:24
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.

minibf: add /scripts/<script>/redeemers

1 participant