Skip to content

v5.8.0

Choose a tag to compare

@github-actions github-actions released this 20 Oct 09:09
· 42 commits to main since this release
320e452

Nuthatch 5.8.0 is the cold audit of 5.7.2 put right: the 107 verified defects and the follow-ups found while
fixing them, across six sprints (#2110). Most of it is correctness of stored state, what one tenant can
do to another, and what an untrusted caller can reach or leak. There is no storage migration and no
nest's NID or registry hash changes, but several defaults are stricter, and the ones that need an
operator's attention before upgrading are listed at the end.

Balances and exposure after a restart

/balances and /exposure lost all but the last 10,000-row step of a large batch, and a restart
rebuilds them as one batch, so any nest with more than about 5,000 transfers to rebuild served wrong
totals after its last restart (#2268). They now integrate every step, as authored entities already
did. Restart nests that serve either route once they run 5.8.0.

The chain we stored is the chain

  • A window is committed only against a chain it has verified: every kept row above the finality depth
    is checked against its block, an unanswered reorg check stops the window rather than passing it,
    and a window with no checkpoint is refused (#2146, #2147, #2149, #2152, #2154).
  • A nest quarantined during a shared-cursor reorg is checked against its own checkpoints before it
    rejoins, a rollback never goes below the nest's origin, and a --seal-direct backfill leaves a
    checkpoint behind it (#2165, #2174, #2175). An interrupted seal-direct prepare no longer re-indexes
    history it already sealed (#2242).
  • RPC failures are classified once: permanent ones (credentials, pruned history, a block over the
    provider's cap) stop only the nest they belong to, and transient ones are retried (#2151, #2155,
    #2161, #2162).
  • Decode refuses rather than panics on an out-of-range narrow integer, factory rules on overloaded
    events resolve, and a factory child's history no longer depends on how it was fetched (#2148,
    #2150, #2153, #2158, #2159).

Derived state survives a reorg and a crash

  • What an entity is fed live, seeded with on restart and retracted on reorg is one selection of the
    stored rows; WETH-shaped transfers now retract (#2164, #2166, #2168, #2170).
  • A crash during a fold, a lost or corrupt segment, or a torn offchain snapshot can no longer leave a
    row in neither the sealed nor the hot layer (#2169, #2172, #2179, #2266).
  • Entity state, per-nest cache and velocity buckets are priced against the per-cursor budget (#2167,
    #2173, #2176). /ready reports a nest whose sealing has stopped (#2262).

One tenant cannot touch another

  • Reclaim no longer deletes segments a kept dataset still names; offline prune --yes refuses while a
    runtime holds the directory, through a new runtime.lock (#2128, #2133, #2249).
  • A move and every other path that installs a nest serve its recorded SQL surface, and an open mount
    serves within its author's queries.toml ceiling (#2129, #2135).
  • A mount named like a runtime route, or a tenant equal to an alias, is refused up front. A NID given
    to the admin API is lower-cased, so one dataset can no longer gain two directories; an upper-case
    NID written in mounts.toml is refused at load, since on Linux it names a different directory
    (#2130, #2137, #2256).
  • A live mount catches up beside the cursor rather than holding it back, and outside the lifecycle
    lock (#2131, #2134).

Keys stay on the box, and no caller sinks the process

  • Every URL that reaches a log, a metric label or a served error carries scheme and host only; that
    covers the Etherscan key, keyed RPC and IPFS gateways, the publish target and Postgres passwords
    (#2156, #2206, #2207, #2208, #2284). pack keygen writes its secret owner-only, by default under
    ~/.nuthatch (#2197).
  • pack verify checks against a key the operator supplies with --pubkey (#2186). Nest names,
    aliases and catalogue entries are held to [A-Za-z0-9_-] so a bundle or a cloned nest cannot reach
    outside its tree (#2184, #2185).
  • Whole-store reads, sorts and response bodies are bounded; /balances?limit=1 at a million holders
    went from 236 ms to 2.2 ms (#2209 to #2214). The SQL memo never serves a clock-dependent answer or
    one from before a resume (#2203, #2204).

Address history

The deposit sweep records only what it read (#2111, #2112, #2118, #2272); one dead endpoint, account
or chain stops only itself (#2113, #2116, #2123); reorgs and requests no longer scale with the watched
set (#2117, #2275); and /api answers as Etherscan does, with L1FeesPaid on Optimism and Base and
getblocknobytime on Polygon (#2114, #2119, #2120, #2127). The nuthatchDeposits feed can return
"sweptThrough": null on a full page.

The CLI

init refuses to overwrite an existing nest and refuses flags that do not apply, nuthatch dev on a
runtime directory honours --ipfs and --state-rpc, and a pasted quickstart no longer answers the
head-count prompt with its next line (#2183, #2187, #2190, #2191, #2235).

Compatibility and upgrade

Replace the binary and restart. A 5.7.2 store is used as it is. Before upgrading:

  • The admin token now applies on localhost. A runtime with NUTHATCH_ADMIN_TOKEN set requires it
    on every bind, and a token-less localhost runtime answers only requests addressed to loopback, so
    one behind a proxy that forwards a public Host answers 401 on /_admin until a token is set (#2132,
    #2136).
  • Names outside [A-Za-z0-9_-] refuse to load. Check aliases and template names in deployed
    nests (#2184).
  • An upper-case NID in mounts.toml refuses to load. Lower-case it; the dataset directory under
    data/ is already lower-case unless it was mounted that way by hand (#2137).
  • pack verify needs --pubkey (#2186).
  • An open mount with an author ceiling now serves within it (#2135).