220 lines
9.5 KiB
Markdown
220 lines
9.5 KiB
Markdown
# AIP-3: Sub-Second Block Period (500 ms QBFT)
|
|
|
|
## Preamble
|
|
|
|
| Field | Value |
|
|
| --- | --- |
|
|
| AIP | 3 |
|
|
| Title | Sub-Second Block Period (500 ms QBFT) |
|
|
| Author | AERE Foundation |
|
|
| Type | Standards Track |
|
|
| Category | Core |
|
|
| Status | Final |
|
|
| Created | 2026-07-11 |
|
|
| Requires | None |
|
|
| Supersedes | None |
|
|
| Superseded-By | None |
|
|
| Ratification | Foundation-ratified (pre-decentralization) |
|
|
|
|
## Abstract
|
|
|
|
This AIP documents the mid-chain transition of AERE's block period from one
|
|
second to 500 milliseconds, performed as a QBFT configuration transition rather
|
|
than a chain restart, so that all history, state, and validator keys were
|
|
preserved. It is a retro-filed record of a change that is already live on chain
|
|
2800.
|
|
|
|
## Motivation
|
|
|
|
AERE targets settlement-grade latency. A one-second block period puts a hard
|
|
floor of about one second on inclusion latency and worst-case finality. Halving
|
|
the block period to 500 ms roughly halves both, which materially improves the
|
|
feel of interactive flows (swaps, payments, wallet confirmations) without any
|
|
change to the EVM or to application code.
|
|
|
|
The change had to be done without re-genesising the chain. AERE had already been
|
|
forced through one full re-genesis (genesis-v2 on 2026-05-07), and losing history
|
|
again was not acceptable. QBFT supports timed configuration transitions, so the
|
|
block period could be reduced at a scheduled block with continuity of state and
|
|
validator identity.
|
|
|
|
## Specification
|
|
|
|
### Mechanism
|
|
|
|
Hyperledger Besu QBFT reads the initial block period from `config.qbft` and reads
|
|
scheduled overrides from a **separate** `transitions` object at the config root.
|
|
The transition key is `xblockperiodmilliseconds` (note: milliseconds, and note the
|
|
`x` prefix, which marks the option experimental in Besu). The correct, and easily
|
|
mis-typed, form is:
|
|
|
|
<!-- QBFT-TRANSITION-CANONICAL path=config.transitions.qbft key=xblockperiodmilliseconds block=2137652 value=500 -->
|
|
|
|
```json
|
|
{
|
|
"config": {
|
|
"qbft": {
|
|
"blockperiodseconds": 1,
|
|
"epochlength": 30000,
|
|
"requesttimeoutseconds": 4
|
|
},
|
|
"transitions": {
|
|
"qbft": [
|
|
{ "block": 2137652, "xblockperiodmilliseconds": 500 }
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
`transitions` is a sibling of `qbft`, not a child of it. Besu reads `transitions`
|
|
from the config root (`JsonGenesisConfigOptions.java:47`) and then the sub key
|
|
`qbft` (`TransitionsConfigOptions.getQbftForks()`). A `transitions` object nested
|
|
inside `config.qbft` is never read, parses without any error or warning, and is
|
|
silently inert.
|
|
|
|
### Activation
|
|
|
|
The 500 ms period is in force from block 2,137,652 on chain 2800. Before that
|
|
block the network produced one-second blocks; from that block onward it produces
|
|
500 ms blocks, with the cadence settling into a steady alternating pattern by
|
|
block 2,137,662. State, account balances, contract code, and the validator set
|
|
were unchanged across the transition.
|
|
|
|
Block 2,137,652 is the boundary because it is the first block on chain 2800 whose
|
|
timestamp equals its parent's. That is impossible while a one second minimum
|
|
period is in force, and it is the reason the block number is not a free choice: a
|
|
node configured to transition later than 2,137,652 applies
|
|
`TimestampMoreRecentThanParent` to block 2,137,652
|
|
(`QbftBlockHeaderValidationRulesetFactory.java:80-83`), rejects it, and stops
|
|
syncing. Full evidence in `aerenew/docs/TRANZITIA-QBFT-SETTLED-2026-07-20.md`.
|
|
|
|
### Operational note for fresh nodes
|
|
|
|
A node synced from genesis against this config applies the transition
|
|
automatically. A brand-new isolated chain started from a config like this needs
|
|
`--sync-min-peers=1` to begin producing, which is an operational detail of
|
|
bootstrapping, not part of the consensus rule.
|
|
|
|
## Rationale
|
|
|
|
A configuration transition was chosen over a re-genesis because it preserves the
|
|
chain's entire history and, critically, the validator keys and account state.
|
|
Re-genesis was rejected: it destroys history and forces every integrator to
|
|
re-point. QBFT's timed transition is purpose-built for exactly this kind of
|
|
parameter change and avoids a client fork.
|
|
|
|
500 ms was chosen as a conservative first step below one second. It roughly halves
|
|
latency while staying comfortably within what a small, low-latency,
|
|
Foundation-operated validator set can sustain. Going lower (for example 250 ms or
|
|
100 ms) is possible in principle but was deliberately not attempted here, because
|
|
tighter periods increase the rate of missed-proposal rounds and stress
|
|
peer-to-peer timing, and there is no need to push that limit with the current
|
|
validator topology.
|
|
|
|
## Backwards Compatibility
|
|
|
|
None at the application layer. Block time is not part of the EVM; contracts do not
|
|
observe it directly. Note the second-order effect: any code that assumed a
|
|
one-second block period to convert block counts to wall-clock time (for example a
|
|
naive per-block reward constant) is now wrong by 2x. AERE hit exactly this: the
|
|
original staking contract computed rewards against a hardcoded blocks-per-year
|
|
constant and under-paid once blocks sped up. That was fixed in AereStakingV2
|
|
(`0x1D95eF6D17aeAB732dF914Ba2d018c270BC155FC`) by moving reward accrual to
|
|
timestamps, which is block-time-immune. New code MUST use `block.timestamp`, not
|
|
block height, for wall-clock math.
|
|
|
|
## Security Considerations
|
|
|
|
Reducing the block period narrows the timing margin for each consensus round. With the seven validators of the time (ten since 2026-09-11) under a single operator this is low-risk because
|
|
network latency between the nodes is small and predictable, and QBFT finalizes
|
|
within the round among a small set. The honest caveats:
|
|
|
|
- **Small, single-operator validator set.** Sub-second finality here is a property
|
|
of a seven-node, one-operator topology, not of a large decentralized set. It
|
|
should not be read as a claim about behavior under a geographically dispersed,
|
|
independently operated validator set. Reassessing the block period will be part
|
|
of decentralizing the validator set.
|
|
- **No consensus-layer change beyond the parameter.** This is a timing parameter,
|
|
not a new consensus algorithm. It does not alter QBFT's fault tolerance
|
|
assumptions.
|
|
|
|
## Reference Implementation and On-Chain Deployment
|
|
|
|
This is a chain-configuration change, so there is no contract address. The
|
|
authoritative artifacts are the Besu QBFT genesis/config carrying the
|
|
`xblockperiodmilliseconds: 500` transition at block 2,137,652 (see Erratum 1),
|
|
and the chain history itself: block intervals before 2,137,652 are 1000 ms and
|
|
after are approximately 500 ms, verifiable via `eth_getBlockByNumber` timestamp
|
|
deltas on `https://rpc.aere.network`. Chain ID is 2800.
|
|
|
|
## Errata
|
|
|
|
**Erratum 1, 2026-07-20. The Mechanism JSON example was self-contradictory, and
|
|
the activation block was wrong.**
|
|
|
|
As originally published, the prose in Mechanism correctly described a `transitions`
|
|
block, but the JSON example nested `transitions` **inside** `qbft`, which is a form
|
|
Besu never reads. The example was:
|
|
|
|
```json
|
|
{
|
|
"_note": "WRONG-FORM, historical record of the original defect. Do not copy.",
|
|
"config": {
|
|
"qbft": {
|
|
"blockperiodseconds": 1,
|
|
"transitions": { "qbft": [ { "block": 2138451, "xblockperiodmilliseconds": 500 } ] }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
That fence is retained above only as the historical record of the defect. It is
|
|
marked WRONG-FORM so the regression test skips it. It must not be copied.
|
|
|
|
Two things were corrected in the body:
|
|
|
|
1. **Path.** `transitions` moved from inside `config.qbft` to the config root, as
|
|
a sibling of `qbft`. Settled from the Besu 26.4.0 source
|
|
(`JsonGenesisConfigOptions.java:47`, `TransitionsConfigOptions.getQbftForks()`).
|
|
2. **Activation block.** `2,138,451` corrected to `2,137,652`. The original figure
|
|
was not measured. Live block timestamps show the one second cadence ending at
|
|
block 2,137,651, and block 2,137,652 carries the same timestamp as its parent,
|
|
which a one second period forbids. The `2,138,451` figure is roughly 800 blocks
|
|
too late and would halt a from-genesis sync at 2,137,652.
|
|
|
|
The key name `xblockperiodmilliseconds` was correct as originally published and is
|
|
unchanged. The 500 ms value is unchanged. Nothing about the deployed network
|
|
changed; only this document's description of it was wrong.
|
|
|
|
Evidence and Besu source citations: `aerenew/docs/TRANZITIA-QBFT-SETTLED-2026-07-20.md`.
|
|
|
|
## Post-Acceptance Outcome Record
|
|
|
|
*Appended 2026-07-20 under AIP-1 section 5. Nothing above this heading was
|
|
edited.*
|
|
|
|
**Measured block interval: 516.4 ms. Configured target: 500 ms.**
|
|
|
|
The transition worked: history, state and validator keys were preserved, and
|
|
intervals before block 2,137,652 (see Erratum 1) are 1000 ms while intervals after
|
|
are approximately 500 ms, as the sections above describe. But the realized mean
|
|
interval is **516.4 ms (measured)**, roughly 3.3% above the 500 ms target, not
|
|
500 ms exactly.
|
|
|
|
This is expected behavior rather than a defect: `xblockperiodmilliseconds` sets a
|
|
minimum period, and QBFT adds real proposal, gossip and commit latency on top of
|
|
it. A configured target and a measured cadence are different quantities.
|
|
|
|
**The obligation this creates.** Aere documents state the target as a
|
|
configuration value and the interval as a measured value, and never present 500 ms
|
|
as a measured result. Any derived figure that depends on block cadence, including
|
|
the EIP-2935 lookback duration quoted in AIP-7 and AIP-18 as "roughly 68 minutes",
|
|
is computed from the target and is therefore an approximation that runs about 3%
|
|
optimistic; at the measured 516.4 ms cadence, 8191 blocks is approximately 70.5
|
|
minutes.
|
|
|
|
## Copyright
|
|
|
|
Released to the public domain (CC0). No rights reserved.
|