Merge pull request #343 from blockfrost/feat/scripts-script-hash-utxos
feat: add /scripts/:script_hash/utxos endpoint
feat: add /scripts/:script_hash/utxos endpoint
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
- Import `Amount` as a type-only import (used only as a type). - Type `reference_script_hash` as non-null: the query inner-joins `script` and filters on its hash, so the column is always present. - Simplify the `amount` array construction using the `...(row.amount ?? [])` pattern already used by /accounts/:stake_address/utxos. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Lists the UTXOs that hold a given script as a reference script (CIP-33), so a script hash can be resolved directly to its deployment UTXOs for use as reference inputs (CIP-31) — without knowing/enumerating the holding address. - paged route GET /scripts/:script_hash/utxos - query uses consumed_by_tx_id IS NULL for spentness - response mirrors /addresses/:address/utxos, minus the deprecated tx_index - requires @blockfrost/openapi 0.1.90 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
perf: push pagination before joins in drep-votes and delegations SQL
Wrap the driving-table filter + ORDER BY + LIMIT/OFFSET in a CTE so
Postgres materializes the page first, then joins to tx / block /
gov_action_proposal / pool_hash only for the page we return — not
for every matching row.
Two endpoints applied (paged + unpaged variants each):
GET /governance/dreps/:drep_id/votes
Original plan: seq-scan voting_procedure (25k rows on mainnet),
hash-join to drep_hash → 130 rows for a busy DRep, 4 nested-loop
joins fire on all 130, sort + top-N 100. ~65ms warm.
New plan: filter voting_procedure to the drep's 130 rows, sort
+ limit to 100, then 3 nested-loop joins fire only on 100. ~30ms warm.
Live end-to-end: ~140ms → ~50ms (~2.9x).
GET /accounts/:stake_address/delegations
Original plan: stake_address → delegation index scan returns 1282
rows for a heavily-delegated account, 3 joins (tx + block + pool_hash)
fire on all 1282, then sort + top-N 100. ~60ms warm SQL.
New plan: filter + sort + limit delegations to 100 (via d.tx_id
ordering directly from the delegation row), then 3 joins fire on
100. ~2ms warm SQL. 27x speedup at the DB layer.
No response shape changes. Same fields, same ordering semantics, same
edge cases.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
- Import `Amount` as a type-only import (used only as a type). - Type `reference_script_hash` as non-null: the query inner-joins `script` and filters on its hash, so the column is always present. - Simplify the `amount` array construction using the `...(row.amount ?? [])` pattern already used by /accounts/:stake_address/utxos. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Lists the UTXOs that hold a given script as a reference script (CIP-33), so a script hash can be resolved directly to its deployment UTXOs for use as reference inputs (CIP-31) — without knowing/enumerating the holding address. - paged route GET /scripts/:script_hash/utxos - query uses consumed_by_tx_id IS NULL for spentness - response mirrors /addresses/:address/utxos, minus the deprecated tx_index - requires @blockfrost/openapi 0.1.90 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
perf(docker): layered Nix image + slim the fallback Dockerfile
Per review: use the flake CLI (`nix build .#blockfrost-backend-ryo`) rather than classic `nix-build -A`, so the Dockerfile no longer depends on default.nix (slated for removal). Experimental features are enabled inline since the nixos/nix base image doesn't enable them by default. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
The Dockerfile ran `nix-build` twice — once for the `result` symlink and again with `--no-out-link` just to resolve the path for a second symlink. Build once with `-o result` and run from `result/bin/...` directly. Add a `.dockerignore` so `COPY . /app` no longer pulls `.git`, `node_modules`, `dist`, `result` and coverage into the image layer (smaller context, fewer cache busts). The in-image `nix-build` already filters these via `lib.cleanSource`, but the COPY layer carried them. Note: this is the manual/fallback build path; the image actually published by CI is the Nix `dockerTools` image (see flake.nix), which is addressed separately in this PR. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Switch the published image from `dockerTools.buildImage` to `dockerTools.buildLayeredImage`. `buildImage` packs the entire runtime closure into a single ~382 MiB layer, so every release re-pushes and every pull re-fetches the whole image even when only a few node_modules store paths changed. `buildLayeredImage` splits the closure into many content-addressed layers, enabling cross-version dedup — a patch release then transfers only the changed layers instead of the full closure. Same image contents (node + pm2 + app dist + node_modules + configs); all consumers (`nix build .#dockerImage`, `nix flake check`) are unaffected. Also declare `ExposedPorts = 3000/tcp` so the image carries the port metadata the Dockerfile already documented. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
chore: update deps and prepare 6.6.1 release
Security-focused dependency upgrades: - @fastify/http-proxy 11.5.0 (pulls @fastify/reply-from 12.6.2) - vitest / @vitest/coverage-v8 4.1.9 - @blockfrost/blockfrost-utils 3.0.0 (drops pm2, removing the transitive vm2 package from the tree entirely) - additional yarn-audit-flagged bumps: fastify 5.8.5, axios 1.18.0, @sentry/node 10.58.0, @blockfrost/blockfrost-js 6.1.1, ajv 8.20.0, path-to-regexp 8.4.2 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Lists the UTXOs that hold a given script as a reference script (CIP-33), so a script hash can be resolved directly to its deployment UTXOs for use as reference inputs (CIP-31) — without knowing/enumerating the holding address. - paged route GET /scripts/:script_hash/utxos - query uses consumed_by_tx_id IS NULL for spentness - response mirrors /addresses/:address/utxos, minus the deprecated tx_index - requires @blockfrost/openapi 0.1.90 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>