Repository navigation
v5.8.0
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-directbackfill 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)./readyreports a nest whose sealing has stopped (#2262).
One tenant cannot touch another
- Reclaim no longer deletes segments a kept dataset still names; offline
prune --yesrefuses while a
runtime holds the directory, through a newruntime.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'squeries.tomlceiling (#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 inmounts.tomlis 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 keygenwrites its secret owner-only, by default under
~/.nuthatch(#2197). pack verifychecks 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=1at 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_TOKENset 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 publicHostanswers 401 on/_adminuntil 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.tomlrefuses to load. Lower-case it; the dataset directory under
data/is already lower-case unless it was mounted that way by hand (#2137). pack verifyneeds--pubkey(#2186).- An open mount with an author ceiling now serves within it (#2135).