aere-research/aips/AIP-18.md

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.