148 lines
6.5 KiB
Markdown
148 lines
6.5 KiB
Markdown
# AIP-18: EIP-2935 on Chain 2800: Deviation from the Written Activation Schedule
|
|
|
|
## Preamble
|
|
|
|
| Field | Value |
|
|
| --- | --- |
|
|
| AIP | 18 |
|
|
| Title | EIP-2935 on Chain 2800: Deviation from the Written Activation Schedule |
|
|
| Author | Aere Network Foundation |
|
|
| Type | Standards Track |
|
|
| Category | Core |
|
|
| Status | Final |
|
|
| Created | 2026-07-20 |
|
|
| Requires | 7 |
|
|
| Supersedes | None |
|
|
| Superseded-By | None |
|
|
| Ratification | Foundation-ratified (pre-decentralization) |
|
|
|
|
## Abstract
|
|
|
|
Chain 2800 lists EIP-2935 under its Pectra ruleset, but the history-storage
|
|
system contract was not populated and the write path did not run until the
|
|
AerePQC fork at block **9,189,161**. Any client or integrator that assumed
|
|
"Pectra is active, therefore EIP-2935 serves history" was wrong for every block
|
|
between the Pectra ruleset taking effect and block 9,189,161. This AIP records
|
|
that deviation explicitly so it is discoverable, and states exactly what is true
|
|
before and after that block. It is a retro-filed record and backfills history.
|
|
|
|
## Motivation
|
|
|
|
A deviation from a written standard that is not written down is a trap. It does
|
|
not cause a problem on the day it is created; it causes one months later, when
|
|
somebody reads the standard, checks that the fork is active, and writes code
|
|
against a guarantee the chain was not providing.
|
|
|
|
The deviation was found and confirmed by direct measurement while building the
|
|
EIP compatibility matrix, not by reading our own configuration, which is exactly
|
|
the failure mode this record exists to prevent for the next person.
|
|
|
|
## Specification
|
|
|
|
EIP-2935 as written specifies a history-storage system contract at
|
|
`0x0000F90827F1C53a10cb7A02335B175320002935`, a ring buffer serving the last
|
|
`HISTORY_SERVE_WINDOW = 8191` block hashes, written by a consensus system call at
|
|
the start of each block, activated at the fork that adopts it.
|
|
|
|
On chain 2800:
|
|
|
|
- **Address:** `0x0000F90827F1C53a10cb7A02335B175320002935` (canonical, unchanged).
|
|
- **Window:** 8191 blocks (`0x1fff`), unchanged from the written EIP.
|
|
- **Runtime:** 83 bytes, byte-for-byte the canonical EIP-2935 runtime
|
|
(**measured**). Disassembly confirms the two jump targets: the `JUMPDEST` at
|
|
`0x42` (revert path) and the `JUMPDEST` at `0x46` (the `SSTORE` path taken when
|
|
`caller == SYSTEM_ADDRESS`).
|
|
- **Deviation:** the contract was **not populated at the Pectra ruleset**. It was
|
|
populated, and the consensus write path began running, at the AerePQC milestone
|
|
block **9,189,161** (Besu `futureEipsTime = 1783820272`), the same fork
|
|
documented in AIP-7.
|
|
|
|
Therefore, normatively:
|
|
|
|
- For `number < 9,189,161`: a call to the history address returns empty, because
|
|
the address was an empty account. EIP-2935 MUST NOT be relied on.
|
|
- For `number >= 9,189,161`: the contract serves the window
|
|
`[number - 8191, number - 1]`. A call passes the 32-byte block number as
|
|
calldata; a query outside the served window reverts.
|
|
|
|
At the 500 ms target block period, 8191 blocks is roughly **68 minutes** of
|
|
trustless lookback, against roughly 128 seconds for the 256-block `BLOCKHASH`
|
|
window.
|
|
|
|
## Rationale
|
|
|
|
The deviation was not a design choice made in advance; it is the honest
|
|
description of what happened. Pectra parity was configured before the EIP-2935
|
|
write path existed in the Aere Besu fork, so the ruleset listed an EIP whose
|
|
system contract nothing was writing to. When the write path shipped, it was
|
|
bundled into the AerePQC fork rather than given its own activation, because the
|
|
fork was already scheduled and a second coordinated activation would have added
|
|
rollout risk for no benefit (the same bundling rationale as AIP-7).
|
|
|
|
**Alternatives rejected.** Silently correcting the compatibility documentation to
|
|
say EIP-2935 was live from Pectra: false. Backfilling the ring buffer at
|
|
activation: impossible without rewriting state, and the fail-empty behavior of an
|
|
unpopulated contract is the safe outcome anyway.
|
|
|
|
## Backwards Compatibility
|
|
|
|
This is the whole subject of the AIP. Concretely: a contract deployed before
|
|
block 9,189,161 that called the history address received empty return data, and
|
|
if it treated empty as "hash zero" it computed a wrong answer rather than
|
|
reverting. Any such contract should be re-checked. From block 9,189,161 the same
|
|
call returns real history, so a contract whose behavior depended on the empty
|
|
return changes behavior at that block.
|
|
|
|
Note the asymmetry that makes this safe at the consensus layer: the transition is
|
|
from an empty account to a populated one, so no historical block re-executes
|
|
differently on an upgraded binary.
|
|
|
|
## Security Considerations
|
|
|
|
The window is 8191 blocks and queries outside it revert. A consumer that assumes
|
|
a longer lookback fails closed, which is correct, but a consumer that assumes any
|
|
lookback before block 9,189,161 silently receives nothing, which is not. That
|
|
asymmetry is the reason this record exists.
|
|
|
|
The trustless-lookback guarantee is only as strong as the chain itself: on chain
|
|
2800 that is a seven-validator, single-operator QBFT chain (AIP-9). EIP-2935
|
|
removes a trust assumption on an oracle; it does not remove the trust assumption
|
|
on the validator set.
|
|
|
|
## Reference Implementation and On-Chain Deployment
|
|
|
|
Chain ID 2800, activation block 9,189,161, contract
|
|
`0x0000F90827F1C53a10cb7A02335B175320002935`, runtime 83 bytes.
|
|
|
|
Verify it yourself against `https://rpc.aere.network`:
|
|
|
|
1. `eth_getCode` at the history address returns the canonical 83-byte runtime.
|
|
2. `eth_call` the address with the 32-byte block number of `head - 100` returns
|
|
that block's hash, byte-identical to `eth_getBlockByNumber`. This is the
|
|
stronger check: the ring buffer is not merely populated, it is serving correct
|
|
history.
|
|
|
|
Related: AIP-7 (the fork that activated it),
|
|
`aerenew/docs/AERE-EIP-COMPATIBILITY-MATRIX.md` (deviation 7),
|
|
`aerenew/docs/AERE-PROTOCOL-SPECIFICATION.md`.
|
|
|
|
## Errata
|
|
|
|
None.
|
|
|
|
## Post-Acceptance Outcome Record
|
|
|
|
**2026-07-20.** Both verification paths above were run against the live chain and
|
|
both pass (**measured**). The functional check, returning the correct hash for
|
|
`head - 100`, is recorded as the canonical proof rather than the bytecode check,
|
|
because matching bytes prove deployment while a correct answer proves operation.
|
|
|
|
An adjacent claim remains open and is flagged rather than assumed: whether the
|
|
EIP-6110 deposit system contract is populated on mainnet 2800 has **not** been
|
|
checked directly. Given that EIP-2935's contract was listed as active while
|
|
unpopulated, that claim must be measured, not inferred from the ruleset.
|
|
|
|
## Copyright
|
|
|
|
Released to the public domain (CC0). No rights reserved.
|