Skip to content

fix: update pnpm lockfile and dispatch epoch_boundary sanity runner#1

Closed
lodekeeper wants to merge 2 commits into
brech1:feat/nightly-workflowfrom
lodekeeper:fix/pr9221-lockfile
Closed

fix: update pnpm lockfile and dispatch epoch_boundary sanity runner#1
lodekeeper wants to merge 2 commits into
brech1:feat/nightly-workflowfrom
lodekeeper:fix/pr9221-lockfile

Conversation

@lodekeeper
Copy link
Copy Markdown

Opening this against your feat/nightly-workflow branch so you don't need to patch it yourself (per @nflaig's ask on ChainSafe#9221).

Two changes:

  1. pnpm-lock.yaml — the upstream Build job on feat: support nightly spec tests ChainSafe/lodestar#9221 was failing with ERR_PNPM_OUTDATED_LOCKFILE. dotenv@^16.4.5 was added to packages/beacon-node/package.json but the lockfile wasn't regenerated. Three-line addition in the beacon-node importer section.

  2. test/spec/presets/sanity.test.ts — when I ran pnpm test:spec:minimal against freshly-downloaded nightly artifacts, the gloas epoch_boundary/pyspec_tests suite (new in consensus-specs Schedule capella on sepolia ChainSafe/lodestar#5127) threw Unknown sanity test epoch_boundary from the dispatcher. The fixture format is identical to blocks (pre.ssz_snappy + post.ssz_snappy + blocks_N.ssz_snappy + meta.blocks_count), so routing it through the existing sanityBlocks runner is sufficient.

Verification

  • pnpm install --frozen-lockfile --prefer-offline succeeds from the updated lockfile.
  • Nightly artifact download end-to-end (unstable branch -> pretest -> extract 3 .tar.gz into spec-tests-nightly) — OK.
  • pnpm test:spec:minimal result with both fixes applied:
    • Test Files: 1 failed | 13 passed
    • Tests: 5 failed | 56128 passed | 95 skipped
    • All 5 failures are in gloas/sanity/epoch_boundary/pyspec_tests (epoch_boundary_full_parent_* + switch_to_compounding_across_epoch_boundary) with Block parent root ... does not match state latest block at processBlockHeader.ts:34. These are pre-existing Lodestar state-transition gaps surfaced by the new gloas tests (exactly what the nightly workflow is designed to catch), not regressions introduced by this PR — needs separate investigation once nightly CI is landed.

Commits

  • b4c68811cb — chore: update pnpm-lock.yaml for dotenv devDependency
  • f84920bd23 — test: add epoch_boundary sanity runner case for nightly spec tests

🤖 Generated with AI assistance

dotenv@^16.4.5 was added to packages/beacon-node/package.json in the
nightly-spec-tests support work but pnpm-lock.yaml wasn't regenerated,
causing `pnpm install --frozen-lockfile` to fail in CI with
ERR_PNPM_OUTDATED_LOCKFILE.

🤖 Generated with AI assistance
Upstream consensus-specs ChainSafe#5127 adds epoch_boundary sanity tests for
Gloas (and post-Gloas `heze`). The case format is identical to blocks
(pre / post / blocks_N / meta.blocks_count), so route it through the
existing sanityBlocks runner.

Surfaced by pnpm test:spec:minimal against nightly artifacts downloaded
via the new nightly workflow in ChainSafe#9221.

🤖 Generated with AI assistance
case "slots":
return sanitySlots(fork, testName, testSuite);
case "blocks":
case "epoch_boundary":
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brech1 I think this is because of the epoch boundary tests I added, maybe these should be under blocks?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nflaig — I dug into this, and the routing epoch_boundary vs blocks isn't actually the issue. The fixture layout is identical (pre / post / blocks_N.ssz_snappy / meta.blocks_count), so whether Lodestar dispatches via case "epoch_boundary": or moves the tests under the blocks/ directory, the consumer-side replay is the same.

The real cause of the 5 failures is in the test generator itself: set_parent_block_full(spec, state) is called between signed_block_1 = state_transition_and_sign_block(...) and block_2 = _build_..., i.e. after yield "pre", state. That mutation touches state.latest_block_hash (+ state.latest_execution_payload_bid.block_hash), which changes hash_tree_root(state), which in turn ends up written into state.latest_block_header.state_root by the very next process_slot. Python computes block_2.parent_root = hash_tree_root(state.latest_block_header) using that mutated state root. But the fixture has no way to re-apply that mutation on replay — no envelope file, no second state, nothing. So consumers hit processBlockHeader.ts:34 with a parent-root mismatch.

Evidence for this interpretation:

  • All 3 passing test_epoch_boundary_empty_parent_* only call set_parent_block_full before yield "pre", so the mutation is baked into the pre-state and fully captured.
  • All 5 failing tests (test_epoch_boundary_full_parent_* + test_switch_to_compounding_across_epoch_boundary + test_epoch_boundary_full_parent_all_requests_gap_5_epochs) call it a second time between blocks 1 and 2, which is the one that can't be serialized.

Fix direction is in consensus-specs, not Lodestar. Either (a) teach the fixture format to carry an execution_payload_envelopes_N.ssz_snappy and teach the sanity runner to deliver it between blocks, or (b) restructure the tests so the FULL-parent path is exercised by actually processing a real envelope through spec.process_execution_payload instead of a test helper that mutates state out-of-band. Option (b) is smaller.

Happy to open a PR against consensus-specs once you confirm the direction.

@lodekeeper lodekeeper closed this Apr 24, 2026
@lodekeeper lodekeeper deleted the fix/pr9221-lockfile branch April 24, 2026 07:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants