Skip to content

feat(l1): schedule Amsterdam on Sepolia - #7287

Merged
ilitteri merged 2 commits into
mainfrom
feat/schedule-amsterdam-sepolia
Sep 18, 2026
Merged

ilitteri merged 2 commits into
mainfrom
feat/schedule-amsterdam-sepolia

Conversation

@ilitteri

@ilitteri ilitteri commented Sep 18, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

Glamsterdam (Gloas on the consensus layer, Amsterdam on the execution layer) has a date on Sepolia: epoch 353024, timestamp 1791294816, 2026-10-06 13:53:36 UTC. Decided in ethereum/pm#2205 (merged 2026-09-15) and recorded in the EIP-7773 activation table by ethereum/EIPs#12355 (merged 2026-09-17). The client configuration is eth-clients/sepolia#126, still open at the time of writing but reflecting the merged decision.

Description

  • amsterdamTime: 1791294816 added to the Sepolia preset, after the Osaka and BPO times, exactly as Schedule Sepolia Glamsterdam activation eth-clients/sepolia#126 does in metadata/genesis.json. 1655733600 + 353024 * 32 * 12 = 1791294816.
  • No blob-schedule change. Upstream leaves it unchanged, Amsterdam inherits the BPO2 parameters, and the preset carries no Amsterdam blob entry, the same shape as the Plataberget preset.
  • The EIP-2124 fork ID changes with the new scheduled fork: the Sepolia fork-ID test rows after BPO2 now advertise next = 1791294816, and a head at or past Amsterdam gets fork hash 0x6c1d9423 (CRC32 continued from BPO2's 0x268956b6 over the big-endian timestamp; the same method reproduces 0x268956b6 from BPO1's hash). The usual just-before/at pair was added for the new fork.
  • A test pins the activation timestamp on the parsed preset so it cannot drift silently. The Sepolia genesis-hash test is unaffected, since the chain config is not part of the genesis header.
  • The forks roadmap claimed Amsterdam timestamps were already wired into the Sepolia and Hoodi presets; neither was true. It now states the Sepolia schedule and that Hoodi and mainnet are still TBD upstream, which pm#2205 confirms.

Hoodi is not scheduled here because pm#2205 leaves its date TBD.

How to Test

cargo test -p ethrex-config

Nine preset tests pass; cargo test -p ethrex-common --lib fork_id passes 8/8, including test_sepolia_amsterdam_activation and the unchanged test_sepolia_genesis_block_hash.

Checklist

  • Updated STORE_SCHEMA_VERSION (crates/storage/lib.rs) if the PR includes breaking changes to the Store requiring a re-sync. (Not needed: no schema change.)

Glamsterdam (Gloas + Amsterdam) activates on Sepolia at epoch 353024,
timestamp 1791294816, 2026-10-06 13:53:36 UTC. The date was decided in
ethereum/pm#2205 and recorded in EIP-7773 by ethereum/EIPs#12355; the
client configuration is eth-clients/sepolia#126, which sets
`amsterdamTime` in the Geth-style genesis alongside the existing Osaka
and BPO times. 1655733600 + 353024 * 32 * 12 = 1791294816.

The blob schedule is unchanged, as upstream: Amsterdam inherits the BPO2
parameters, and the preset carries no Amsterdam blob entry, the same
shape as the Plataberget preset.

A test pins the activation timestamp so it cannot drift silently. The
forks roadmap is corrected: it claimed Amsterdam timestamps were already
wired into the Sepolia and Hoodi presets, and Hoodi's date is still TBD
upstream.
@ilitteri
ilitteri requested a review from a team as a code owner September 18, 2026 15:48
@ilitteri ilitteri added the L1 Ethereum client label Sep 18, 2026
@github-actions

github-actions Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

⚠️ Known Issues — intentionally skipped tests

Source: docs/known_issues.md

rpc-compat log-bearing cases excluded

Where: KNOWN_EXCLUDED_TESTS in .github/scripts/check-hive-results.sh counts out
eight hive rpc-compat cases — the four eth_getLogs cases, eth_getBlockReceipts/get-block-receipts-latest,
and three eth_getTransactionReceipt cases. They are exactly the cases whose recorded
response contains at least one log object; every case with an empty log array still runs.
Note this leaves eth_getLogs with no rpc-compat coverage at all, since all four of its
cases are in the set.

Why: ethrex populates blockTimestamp on log objects, as geth, besu, nethermind, reth
and erigon all do. hive's rpc-compat compares responses byte-exactly (jsondiff.FullMatch;
the lenient checkJSONStructure path applies only to cases upstream marks speconly), and
the corpus is pinned to execution-apis d08382ae (2025-02-10), whose recordings predate the
field — it entered the schema in execution-apis#639 and the fixtures in #846 (2026-07-22).
So the extra key cannot match, and this is a property of the pin rather than of the response.

The pin cannot move, and this is not temporary. The pin sits one commit before
execution-apis#627, which moved the test chain to a pre-merge genesis: the current corpus has
~36 proof-of-work blocks before its terminal total difficulty. ethrex does not support
pre-merge chains and will not, so importing that chain.rlp fails at block 1 —
validate_block_header has no pre-London base-fee path. Every revision carrying
blockTimestamp in its fixtures also carries that chain, so there is no revision that
satisfies both. Nor can the corpus be patched locally: rpc-compat's Dockerfile clones
ethereum/execution-apis by hard-coded URL, so the branch buildarg cannot point at a fork.

Coverage: the field itself is pinned by
block_timestamp_is_on_the_log_and_not_on_the_receipt in
crates/networking/rpc/types/receipt.rs, which asserts it is present on each log and absent
from the receipt level.

Removal: delete the entries if ethrex ever gains pre-merge chain import, or if upstream
marks these cases speconly so they are type-checked instead of compared byte-for-byte.


The stateless schema id does not identify the encoding

Where: STATELESS_INPUT_SCHEMA_ID in crates/common/types/stateless_ssz.rs.

Upstream keeps the stateless input schema id at 0x1501
(fork_index 0x15 << 8 | revision 0x01) across incompatible body changes. Three
encodings have now shipped under it: tests-zkevm@v0.6.2, then #3248 + #3278,
then #3356, which moved state, codes and public_keys from SszList to
ProgressiveList. ethrex speaks the last one.

The consequence is that the 2-byte prefix cannot be used to detect a stale or
mismatched bundle. A wrong-dialect input is accepted by the id check and then
fails later — in SSZ decode, or on a root that does not match — rather than being
rejected up front for what it is. only_amsterdam_schema_id_decodes therefore
proves less than its name suggests.

Worth raising upstream: a revision field that does not move across a body change
provides no version negotiation at all.


ZisK guest program hash changes with the unsync_cell gate

Where: crates/common/types/block.rs, transaction.rs.

The gate on the single-threaded unsync_cell::OnceCell moved from
all(feature = "eip-8025", target_arch = "riscv64") to
all(feature = "zisk", target_arch = "riscv64") when the eip-8025 feature was removed.

The guest ELFs were previously built --features "<zkvm>-build-elf,ci", which never enabled
eip-8025, so they compiled the atomic once_cell variant. bin/zisk/Cargo.toml does enable
ethrex-common/zisk, so the ZisK guest now compiles the unsafe impl Sync cell instead.
That changes the ELF bytes and therefore the program hash and verification key.

This is intended (the guest is single-threaded, so the unsync cell is sound and cheaper), but it
is a VK change rather than a no-op refactor, and the diffstat presents it as a file rename
(eip8025_cell.rs → unsync_cell.rs). Anyone pinning a ZisK VK across this change must
re-register it. The stateless-validator crate now forwards ethrex-common/zisk from its own
zisk feature so the two ZisK guests do not disagree on the cell type.


Release signing key is an unprotected repository secret

Where: .github/workflows/tag_release.yaml.

MINISIGN_SECRET_KEY is a plain repository secret. There is no environment: on
finalize-release or dry-run-release-assets, and gh api repos/lambdaclass/ethrex/rulesets
shows only branch-targeted rulesets, so the github.ref_type == 'tag' condition is a workflow
check rather than an enforced boundary: anyone who can push a tag can reach the signing key.

This is a repository-settings change, not a code change, so it is recorded here rather than
fixed in the tree. Recommended:

  1. Move MINISIGN_SECRET_KEY / MINISIGN_PASSWORD into a GitHub Environment with required
    reviewers, and add environment: to the two jobs that sign.
  2. Add a ruleset targeting refs/tags/v* restricting who may create release tags.

Until then, the compromise of that key is silent and durable: signatures would still verify
against the committed .github/minisign.pub.

@github-actions

Copy link
Copy Markdown

🤖 Kimi Code Review

I'll review this PR which adds Amsterdam fork activation time for Sepolia testnet.

Review

Overall Assessment

This is a straightforward configuration update adding the Amsterdam hardfork activation timestamp for Sepolia. The implementation appears correct, but I have a few observations.

Specific Findings

1. Genesis JSON Configuration — Correct

cmd/ethrex/networks/sepolia/genesis.json:23

The amsterdamTime: 1760427360 value is correctly placed in the config object alongside other fork timestamps. The value 1791294816 matches the documented calculation (1655733600 + 353024 * 32 * 12).

2. Test Verification — Good Practice

crates/common/config/networks.rs:213-223

The test correctly verifies the genesis configuration loads properly. The extensive comment with cross-references to consensus decisions (ethereum/pm#2205, EIP-7773, eth-clients/sepolia#126) is excellent for auditability.

3. Documentation Update — Minor Inconsistency

docs/roadmaps/forks-roadmap.md:111-114

The documentation states:

"Amsterdam is scheduled on Sepolia (amsterdamTime 1791294816...)"

However, the earlier paragraph still says:

"Amsterdam timestamps are wired into the holesky, sepolia and hoodi genesis files"

This is now incorrect — only Sepolia has the timestamp wired. Holesky and Hoodi are explicitly noted as "TBD upstream." Suggest updating line 110 to match the new reality:

defined for the BPOs and Hegotá. Amsterdam timestamps are wired into the Sepolia
genesis file under `cmd/ethrex/networks/`. Hoodi, Holesky and mainnet dates are
still TBD upstream, so their presets carry no `amsterdamTime` yet.

4. Missing: Holesky Configuration?

No file shown for cmd/ethrex/networks/holesky/genesis.json. The PR description and docs note this is intentional ("TBD upstream"), but verify that:

  • The Holesky genesis JSON doesn't accidentally contain a stale/placeholder amsterdamTime
  • The ChainConfig struct in crates/common/types/genesis.rs already has the amsterdam_time field (implied by test compiling, but not shown in diff)

5. Test Coverage — Suggestion

The test only verifies Sepolia. Consider adding a negative test for networks without Amsterdam activation:

#[test]
fn test_hoodi_no_amsterdam_yet() {
    let genesis = Network::PublicNetwork(PublicNetwork::Hoodi)
        .get_genesis()
        .unwrap();
    assert_eq!(genesis.config.amsterdam_time, None);
}

This prevents accidental premature activation on other networks.

Security Consideration

Hardfork timestamps are consensus-critical. The cross-referenced sources check out:

  • 1655733600 = Sepolia genesis timestamp
  • 353024 * 32 slots/epoch * 12s/slot = 135,561,216 seconds
  • Sum: 1,791,294,816 ✓

Timestamp corresponds to 2026-10-06 13:53:36 UTC as documented. No discrepancy found.

Conclusion

The PR is correct and safe to merge with minor documentation fix (Point 3). The test addition (Point 5) is optional but recommended for robustness.


Automated review by Kimi (Moonshot AI) · kimi-k2.6 · custom prompt

@github-actions

Copy link
Copy Markdown

🤖 Claude Code Review

All verified — the PR is accurate and consistent with existing conventions. Ready to write the review.

Review: feat(l1): schedule Amsterdam on Sepolia (PR #7287)

This is a small, well-scoped data/config change that schedules the Amsterdam (Glamsterdam) fork on Sepolia. I verified the surrounding infrastructure and cross-checked the claims in the PR description; everything holds up.

Correctness

  • Timestamp math is correct. 1655733600 + 353024 * 32 * 12 = 1791294816, matching both the genesis JSON value and the value asserted in the new test.
  • amsterdamTime is already wired plumbing, not a new field — it's parsed in crates/common/genesis_utils.rs:35, consumed by ChainConfig::get_fork/get_fork_blob_schedule in crates/common/types/genesis.rs, and exercised elsewhere (block_execution_witness.rs). This PR only supplies a value for one network, so there's no risk of unexercised code paths.
  • Fork-resolution ordering is safe with only amsterdamTime set and no bpo3..bpo5/hegotaTime/lstarTime: get_fork checks from the latest fork backward, so the absence of later fields correctly falls through to Amsterdam. This mirrors the existing Plataberget preset shape, as the PR description claims.
  • Blob schedule correctly left unchanged. Per EIP-7892, named forks inherit the highest activated BPO entry rather than carrying their own blob params, so omitting an amsterdam blob-schedule entry is consistent with how Osaka/BPO forks are already handled, and with the Plataberget preset.
  • Roadmap correction is accurate. Holesky doesn't even have a genesis file under cmd/ethrex/networks/, and Hoodi's genesis has no amsterdamTime — so the old roadmap claim that Amsterdam was "already wired into the holesky, sepolia and hoodi presets" was indeed false, and the fix is warranted.

Test coverage

  • The new test_sepolia_amsterdam_activation pins the value via genesis.config.amsterdam_time, which will catch silent drift if the genesis JSON is edited later. Good, targeted regression test.

Minor / nit

  • None substantive. The change is minimal, self-contained, and doesn't touch any consensus-critical execution logic — it only supplies a scheduling parameter that's already fully supported by existing code.

Overall: No correctness, security, or performance concerns. This is a clean, low-risk config/data update with an appropriate regression test and an accurate documentation fix. Approve.


Automated review by Claude (Anthropic) · sonnet · custom prompt

@github-actions

Copy link
Copy Markdown

🤖 Codex Code Review

No correctness, security, or performance findings in this patch.

cmd/ethrex/networks/sepolia/genesis.json:23 adds amsterdamTime on a path the client already supports via ChainConfig::amsterdam_time and ChainConfig::get_fork() in crates/common/types/genesis.rs. The added regression test at crates/common/config/networks.rs:214 is the right coverage for the change and should catch accidental removal or rename of the field during genesis deserialization.

Minor doc nit: docs/roadmaps/forks-roadmap.md:109 says the fork enum “ends at Amsterdam”, but the current enum continues through Hegota and LStar in crates/common/types/genesis.rs:318. If this section is meant to describe the live codebase, that wording is now stale.

I could not run cargo test in this sandbox because Cargo/Rustup could not write to its home/cache directories under /home/runner, so this review is based on static inspection only.


Automated review by OpenAI Codex · gpt-5.4 · custom prompt

@github-actions

github-actions Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Lines of code report

Total lines added: 25
Total lines removed: 0
Total lines changed: 25

Detailed view
+-----------------------------------------+-------+------+
| File                                    | Lines | Diff |
+-----------------------------------------+-------+------+
| ethrex/crates/common/config/networks.rs | 255   | +7   |
+-----------------------------------------+-------+------+
| ethrex/crates/common/types/fork_id.rs   | 555   | +18  |
+-----------------------------------------+-------+------+

@github-project-automation github-project-automation Bot moved this to In Review in ethrex_l1 Sep 18, 2026
Setting `amsterdamTime` changes the EIP-2124 fork ID on Sepolia: the
post-BPO2 rows now advertise 1791294816 as the next fork, and a head at or
past Amsterdam gets fork hash 0x6c1d9423 (CRC32 continued from 0x268956b6
over the big-endian timestamp) with no next fork. Adds the usual
just-before/at pair for the new fork, matching the other rows.
@ilitteri
ilitteri added this pull request to the merge queue Sep 18, 2026
Merged via the queue into main with commit 5b611f1 Sep 18, 2026
60 of 63 checks passed
@ilitteri
ilitteri deleted the feat/schedule-amsterdam-sepolia branch September 18, 2026 17:36
@github-project-automation github-project-automation Bot moved this from In Review to Done in ethrex_l1 Sep 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

L1 Ethereum client

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants