Conversation
The session captures start_block once, at the head that follows the
global setup. `_reset_chain_between_tests` rewinds to that block after
every test, which keeps the anchor correct for the next fill.
`--no-reset-between-tests` skips the rewind, but nothing advances the
anchor in its place. The first test moves the head, and every later test
still chains its first block from the stale anchor. The client then
rejects the parent ("parentHash is not current head"), or, on a long run
against a non-archive client, reports "historical state ... is not
available" once that block's state is pruned.
Read the head before each test and re-anchor on it. Consumers are not
affected: they route pre-run setup by directory (`pre_run/*.json`,
applied once per session), not by a fixture's `start_block_hash`.
skylenet
added a commit
to ethpandaops/benchmarkoor-tests
that referenced
this pull request
Aug 27, 2026
Use skylenet/execution-specs fix/no-reset-reanchor-start-block. The branch adds the start_block re-anchor for --no-reset-between-tests on top of feat-deploy-script-oom-fix. See jochem-brouwer/execution-specs#6.
`hash` built the whole fixture as one JSON string and then again as UTF-8 bytes, on top of the `json_dict` copy it already holds. That is three full-size copies alive at once, right after a fill has finished. Feed the encoder's chunks into the digest instead. `iterencode` emits the identical character stream, so the hash value does not change; 406 randomised documents (unicode, escapes, floats, deep nesting) hash the same both ways.
A stateful benchmark fill produces one `FixtureEngineNewPayload` per block. `make_stateful_fixture` held all of them, and `json_dict` then made a full `model_dump` copy on top -- hex strings, so larger than the models. A 41k-block fill reached 46 GiB and the kernel killed it partway through the copy. `PayloadBuffer` keeps the first 512 payloads in memory, which is every ordinary fill, and behaves exactly as the list it replaces: the fixture field is populated and nothing touches the disk. Past that it moves to a temp file holding one payload per line of canonical JSON -- the exact form `BaseFixture.hash` digests -- and the fixture field is left empty. `hash` and the new `write_json` then stream that text back in at the right place, one payload at a time. The hash is byte-identical either way, so a fixture does not change identity because of how it was built. Measured on a 1 GB fixture document: peak RSS 2957 MiB buffered vs 79 MiB spilled, same hash.
2 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
--no-reset-between-testskeeps the chain moving between fills, but thesession anchor never moves with it.
_session_pre_runcapturesstart_blockonce, fromlatest, after theglobal setup:
That is the only production write to
client_backend.start_block. Everytest then chains its first block from it, in
make_stateful_fixture.Normally the invariant holds because
_reset_chain_between_testsrewindsthe chain back to that block after each test. Under
--no-reset-between-teststhe rewind is skipped and nothing takes itsplace, so the anchor goes stale as soon as the first test builds a block.
The nonce side of the flag was already adapted —
worker_keyreads atlatestunder the flag, with a comment explaining the inversion. Theanchor side was missed.
Symptoms
Two failures with the same root cause. Which one appears depends on where
the client's state-history window sits:
worker_key->get_accounthistorical state ... is not availablebuild_block(first block of a later test)parentHash is not current headSeen while filling
tests/benchmark/stateful/bloatnet/test_setup_contracts.pyon ajochemnet snapshot. Both
code_sizeparametrizations run in one session;the first passes and advances the chain about 7,700 blocks, and the
second dies on the anchor it never updated.
Fix
Read the head before each test and re-anchor on it, so every test starts
from what the previous test actually left behind. That is the chain the
accumulating mode is built around.
Consumer impact
None. Consumers route pre-run setup by directory (
pre_run/*.json,applied once per session), not by matching a fixture's
start_block_hash. Each test's fixture now records the anchor it trulychains from, which is more accurate than every test claiming the session
anchor while depending on its predecessors.
Testing
ruff checkandruff format --checkpass in repo context.pytest --collect-onlyovertests/benchmark/stateful/bloatnetcollects 382 tests, unchanged from the base commit.