Skip to content

feat: add era reader/writer - #149

Merged
wemeetagain merged 13 commits into
mainfrom
cayman/era
Jan 6, 2026
Merged

feat: add era reader/writer#149
wemeetagain merged 13 commits into
mainfrom
cayman/era

Conversation

@wemeetagain

@wemeetagain wemeetagain commented Dec 30, 2025

Copy link
Copy Markdown
Member
  • add era module (mostly transliterated from @lodestar/era)
    • Reader/Writer implementations
  • add era downloader script (currently controlled via an options module)
    • zbuild run download_era_files
  • add era integration tests, skipped if era files aren't present (download_era_files hasn't been run)
    • validate known good era file
    • round trip read+write

My hope is that era support can be leveraged for simple testing / benchmarking / etc of the stfn without the need for a full node or a lot of additional infra.

PS: zbuild needed to be rebuilt to fix a bug with list options.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @wemeetagain, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the project's capability to interact with historical Ethereum Beacon Chain data by introducing a robust system for reading, writing, and managing 'era' files. This new functionality provides a streamlined approach to accessing historical beacon states and blocks, which is crucial for simplifying testing, benchmarking, and analysis of the state transition function without the need for a full node or extensive additional infrastructure.

Highlights

  • New Era Module: Introduced a new era module, which includes Reader and Writer implementations for handling Ethereum Beacon Chain 'era' files. This module is largely a transliteration from the @lodestar/era project.
  • Era File Downloader: Added a new script, scripts/download_era_files.zig, along with corresponding build options, to facilitate downloading era files. This script can be run via zbuild run download_era_files and is configurable for base URL, specific files, and output directory.
  • Era Integration Tests: Implemented integration tests for the era functionality. These tests validate known good era files and perform round-trip read-and-write operations to ensure data integrity. The tests are designed to be skipped if the necessary era files are not present (i.e., if the download script hasn't been run).
  • Serialization/Deserialization Enhancements: Added deserialize and serialize methods to the SignedBeaconBlock and BeaconStateAllForks unions in src/state_transition/types, enabling these critical data structures to be converted to and from byte arrays, which is essential for era file operations.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new era module for reading and writing era files, which is a significant and well-structured feature. The implementation is mostly solid, with good structure and tests. I've found a few issues related to potential errors, style guide adherence, and code simplification. My main suggestions are to use std.io.copy for file downloading to improve efficiency and maintainability, fix a potential crash in the era writer when handling era 0, and address a type-casting issue in the era reader. I've also pointed out a function that exceeds the length limit from the style guide.

Comment thread src/era/Writer.zig Outdated
Comment thread src/era/era.zig Outdated
Comment thread scripts/download_era_files.zig Outdated
Comment thread src/era/Reader.zig
Comment thread src/era/Reader.zig Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds comprehensive support for Ethereum consensus layer ERA file format (e2store), enabling reading and writing of historical beacon chain data for testing and benchmarking purposes without requiring a full node. The implementation is primarily transliterated from Lodestar's TypeScript implementation.

  • Implements Reader and Writer for ERA files with full validation support
  • Adds downloader script for fetching ERA files from nimbus.team
  • Updates snappy dependency to support both raw and framed compression modes

Reviewed changes

Copilot reviewed 17 out of 18 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
zbuild.zon Updates snappy dependency and adds download_era_options configuration with base URL and file list
build.zig.zon Updates snappy package hash for new commit
build.zig Adds era module, download_era_files executable, and integrates era testing infrastructure
src/era/root.zig Module entry point exposing e2s, era, Reader, and Writer components
src/era/era.zig Core ERA file utilities including filename parsing, group indices, and validation functions
src/era/e2s.zig E2Store format implementation with entry reading/writing and SlotIndex serialization
src/era/Reader.zig ERA file reader with methods for reading compressed/serialized blocks and states
src/era/Writer.zig ERA file writer with state machine for sequential block/state writing
src/state_transition/types/beacon_state.zig Adds deserialize and serialize methods to BeaconStateAllForks for all fork variants
src/state_transition/types/beacon_block.zig Adds deserialize, deinit, and serialize methods to SignedBeaconBlock, changes pointers from const to mutable
src/config/root.zig Exports mainnet_genesis_validators_root constant
src/config/chain/networks/mainnet.zig Adds mainnet_genesis_validators_root constant and sets FULU_FORK_EPOCH to 411392
scripts/download_era_files.zig HTTP downloader script for fetching ERA files with existence checks and streaming writes
test/int/era/root.zig Integration tests validating ERA file reading and round-trip write operations
test/int/root.zig Imports era integration tests
test/spec/test_case.zig Updates snappy import to use .raw namespace
test/spec/ssz/test_case.zig Updates snappy import to use .raw namespace
.gitignore Adds *.era pattern to exclude downloaded ERA files

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/era/Writer.zig
Comment thread src/era/era.zig
Comment thread src/era/era.zig Outdated
Comment thread src/era/e2s.zig
Comment thread src/era/era.zig
Comment thread src/era/Reader.zig Outdated
Comment thread src/era/Writer.zig
Comment thread src/era/e2s.zig
Comment thread scripts/download_era_files.zig
Comment thread src/era/Reader.zig Outdated
@wemeetagain
wemeetagain requested a review from a team as a code owner January 2, 2026 16:42
Comment thread src/era/Writer.zig
Comment thread src/era/Writer.zig
Comment thread src/era/Writer.zig
try reader.validate(allocator);
}

test "write an era file from an existing era file" {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

after zig build run:download_era_files I found it takes > ~70s in my environment to run test:int
maybe drop a comment to instruct people to move downloaded files to another folder to save time

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Or could we have this test be entirely independent of downloading, either by just using a known good era.Reader (preferred) or committing an era file? Seems not great to have to have extra instructions, it's more ideal to be able to zig build test after fetching the repo.

We can do the same for the validation test by writing a known good era file into a tmp dir and then validating it, so we don't have to rely on downloading for the tests, which makes us do stuff like SkipZigTest in the case of errors external to our implementation (download failure, etc.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I found it takes > ~70s in my environment to run test:int

Maybe time to just add another test specifically for slow tests


Seems not great to have to have extra instructions, it's more ideal to be able to zig build test after fetching the repo.

I think we already have precedent to requiring extra instructions for some tests (download and write spec tests).
The problem here is similar. The validation rules are quite strict, and "actually useful" test data is big.

The benefit though, is that these test files are "actually useful" in that they are actually representative of our intended workload.

I think this cost (run an extra script to download a few files) can be offset by leaning in the other direction -- reusing these era files for as many other tasks as possible. For example, it should be straightforward to refactor #6 and #121 (ssz and stfn microbenchmarks) to use the very same era files. Also it should be straightforward to add a script that loads an era file and replays the state transition -- for the purpose of running perf or collecting prometheus metrics from it.

Imo these era files can be like a poor-man's deterministic testing framework. In lieu of the ability to generate test data, or until we have that ability, these era files are the next best thing.

@twoeths twoeths left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

looks good to me after comparing to ChainSafe/lodestar#8035
the tests work well in my environment
I dropped some minor comments

Comment thread src/era/Writer.zig Outdated
try reader.validate(allocator);
}

test "write an era file from an existing era file" {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Or could we have this test be entirely independent of downloading, either by just using a known good era.Reader (preferred) or committing an era file? Seems not great to have to have extra instructions, it's more ideal to be able to zig build test after fetching the repo.

We can do the same for the validation test by writing a known good era file into a tmp dir and then validating it, so we don't have to rely on downloading for the tests, which makes us do stuff like SkipZigTest in the case of errors external to our implementation (download failure, etc.)

Comment thread src/era/e2s.zig Outdated
twoeths
twoeths previously approved these changes Jan 6, 2026
@wemeetagain
wemeetagain merged commit b92bc98 into main Jan 6, 2026
8 checks passed
@wemeetagain
wemeetagain deleted the cayman/era branch August 17, 2026 19:48
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.

4 participants