Repository navigation
v5.3.0
Nuthatch 5.3.0 proves which blocks a validator proposed (RFC-0063 plan C), whoever received their
fees, so rotki can book a validator's produced blocks and MEV from a nest alone. It also fixes a 5.2.0
defect that stopped rotki reading history from a nest with a start_block. Nothing outside an
[address_history] nest changes, and there is no storage migration.
Proven proposers per validator (Ethereum mainnet)
- The proof is the chain's own. Block N+1's
parent_beacon_block_root(EIP-4788) commits to the
beacon header that produced block N, whoseproposer_indexnames the proposer. Every row of a span
is checked before any is filtered by validator, so a tampered row fails the span instead of hiding a
proposal. Every span hangs from the block the nest's own RPC calls finalized, read by that tag. - Coverage: slot 12,777,208 (block 23,551,570) onward. A range starting earlier is refused with
"proposals are proven from block 23551570". Proofs do not followstart_blockorend_block;
end_blockbounds only what is served. - Where the proofs come from: catalogue files beside the block partitions on the mirror (published
for blocks 23,551,570 to 26,159,999), and for the blocks above them, built here from the RPC and a
beacon node whenbeacon_url(orNUTHATCH_BEACON_URL) names one. Without one, those blocks stay
incomplete. - API:
validators = [...], orPOST /api/watchwith{"validator": N};
account/nuthatchValidatorBlocks&validator=N&startblock&endblock&page&offset, complete or refused,
withsupportedFromandverifiedThrough. Rows carry the block reward (verified from the block's
receipts, orrewardStatus: unavailableand retried, never zero), the relays' MEV, and the builder's
payment from the block's traces. nuthatch partitions --proposers --beacon-url URL --beacon-cache DIRbuilds the catalogue for a
mirror from its block partitions, verifying every header as a nest does.
Fixes
- A range before
start_blocknames where history starts (fixes 5.2.0). Every account action
refused a range starting beforestart_block, including rotki's usualstartblock=0and a request
with no start, as "not indexed at block 0", which rotki could not act on. It now says "history starts
at block N", and rotki asks again from there. - A covered answer above the finalized head is served on one hash check instead of waiting for the
cursor. Measured with the cursor busy backfilling another account: every request timed out at 20 s
before; 0.08 to 0.53 s after. logs/getLogsfetches a page's receipts and timestamps together, 16 at a time, and answers
within the request deadline or refuses.- A request above what is covered is served inside a long backfill. The cursor serves such
requests between its windows, and a window could cover 50,000 blocks: on mainnet, tip requests for
one account while the nest backfilled a busy wallet waited 10.9 to 16.0 s each. Backfill windows now
start at 128 blocks and are paced to a quarter of the request deadline, and the bridge to the
finalized block serves waiting requests between its chunks. The same measurement: 0.05 to 2.6 s,
except a first request right after startup, which can still wait for the first windows. request_deadlinedefaults to 8 s, down from 20 s, and is one ceiling per request from its
arrival: the hash check, the queue, a window the cursor is part way through, a trace and a cover all
count against it. A fully covered range is served if its final read completes within that ceiling;
otherwise the request is refused. A gap the cursor cannot cover in time at its measured pace is
refused at once with how far history is covered. The pace is measured per layer (discovery, block
bodies, produced blocks), the layers' times add up, and owed relay re-asks count as blocks.- Recent timestamp lookups search near the chain head first. rotki's usual timestamp just
behind the tip is bracketed within eight blocks, avoiding a search from genesis that could exhaust
the four-second search budget. The answer still passes the same neighbour and ancestry checks. - An open mirror is read as far as it has published. A
[address_history.mirror]without
to_blockfollows the mirror's newest partition; coverage it cannot verify is taken back first.
Compatibility and upgrade
Replace the binary and restart. A 5.2.0 store is used as it is. Validator watches start empty.