aere-research/aips/AIP-3.md
Aere Network 6cb0140fae Republished from a clean root: the compiled artifact is gone from history, and the local line of work joins the sanitized public line
The public history carried kat/__pycache__/mlkem768_reference.cpython-314.pyc,
a compiled Python artifact embedding the operator's absolute local path. Text
secret scanners do not read compiled binaries, which is exactly how it slipped
through, and removing it from the tip would have left it reachable through the
old root commits. So this repository is republished from a single clean root.

This root also carries, from the previously unpublished line of work:
- corrected LICENSE year, LICENSING.md, VERIFY-POLICY.md, and
  CITATIONS-UNRESOLVED.md remeasured 2026-08-11 (101 paths, README aligned)
- O-018: run_consensus_verification.py ran 19 of 29 models and reported PASS;
  it now runs all 29, and computemarket_smt.py gains resolveByTimeout /
  reclaimUnsettled cases plus a negative control
- O-006: the word 'audited' removed from next to Bouncy Castle, twice, after a
  concurrent edit resurrected it
- O-014: prior art named and dated - Algorand's native falcon_verify shipped
  about ten months before AERE's precompiles; the primacy claim is withdrawn
  where it was implied
- bench/ scripts parametrized so they actually run for an outsider (the
  earlier textual sanitization left $STAGING unexpanded inside Python strings)
- AIP-2/AIP-3 errata with measured figures, spec remeasurements at 2026-08-01,
  and the spec-zk-stack retractions (owner is an operational key, not the
  Foundation; 'maximally sound' withdrawn; aggregator V1 deprecated)
The redacted bench-host environment files from the sanitized line are kept
exactly as published; the unredacted local variants are not carried.
2026-08-15 13:52:14 +03:00

221 lines
9.4 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 current seven validators 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.