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.
477 lines
28 KiB
Markdown
477 lines
28 KiB
Markdown
# AERE Parallel Execution: Block-STM Executor and On-Chain Hint Registry
|
|
|
|
Technical specification. Chain 2800 (AERE Network mainnet).
|
|
|
|
Grounding: `parallel-executor/` (Rust), `rollup-sequencer/src/blockstm/` (TypeScript),
|
|
`contracts/contracts/parallel/AereBlockSTMRegistry.sol`,
|
|
`contracts/contracts/parallel/AereRollupValidity.sol`,
|
|
`contracts/deployments/block-stm-registry.json`, and
|
|
`sdk-js/src/addresses.ts`.
|
|
|
|
---
|
|
|
|
## 1. Executive summary and honest scope
|
|
|
|
AERE's parallel-execution work has three distinct pieces at three different levels of maturity.
|
|
Stating them plainly up front, because the boundary between "shipped" and "roadmap" is the
|
|
whole point of this document:
|
|
|
|
1. **A real, self-verifying Block-STM parallel executor (shipped, benchmarked).**
|
|
`aere-block-stm` is a from-scratch Rust implementation of the Block-STM
|
|
optimistic-concurrency algorithm (Gelashvili et al., arXiv:2203.06871, 2022, the same
|
|
design behind Aptos and the family Sui and Monad build on). It executes a batch of
|
|
transactions across many CPU cores and commits a single keccak256 state root. Every run
|
|
also executes the batch sequentially and refuses to emit a root unless the two results
|
|
match, so a concurrency bug cannot silently produce a bad commitment. Correctness is proven
|
|
over 6000 randomized adversarial comparisons with zero mismatches, and measured speedup on a
|
|
16-core box is roughly 8.6x to 9.3x on low and medium-conflict batches.
|
|
|
|
2. **An on-chain advisory registry (shipped, live).**
|
|
`AereBlockSTMRegistry` at `0x98E2C3e615841919d173D8FF642514c5902E8A28` is an opt-in registry
|
|
where a contract publishes the storage-slot read/write hints for its own function selectors.
|
|
It is advisory metadata for a scheduler, holds no funds, changes no execution semantics, and
|
|
has no admin over anyone else.
|
|
|
|
3. **Moving parallelism into base consensus (roadmap, not built).**
|
|
AERE's Layer-1 base layer runs Hyperledger Besu and executes transactions **sequentially**.
|
|
Nothing here changes that. Making Besu execute in parallel is a fork of a Java
|
|
execution client, a multi-month effort, and is explicitly out of scope for what exists today.
|
|
The registry is metadata for that eventual fork; the concrete parallel path that runs today
|
|
lives in the **rollup layer**, off-chain in the sequencer.
|
|
|
|
The honest one-line framing, taken verbatim from the executor README, is: "Real Block-STM
|
|
parallel executor, wired into the AERE rollup sequencer; the L1 base layer stays
|
|
Besu-sequential."
|
|
|
|
Everything in Section 2 through Section 5 is code that exists and runs. Section 6 (base-consensus
|
|
promotion) and the fraud-proof / full-EVM items in Section 7 are roadmap and are labeled as such.
|
|
|
|
---
|
|
|
|
## 2. The parallel executor (`aere-block-stm`)
|
|
|
|
The executor is a standalone Rust crate under `parallel-executor/` with **zero external
|
|
dependencies**: the scheduler, multi-version memory, PRNG and keccak256 are all built on `std`.
|
|
The build is fully offline and reproducible.
|
|
|
|
### 2.1 State and transaction model
|
|
|
|
The state model is intentionally EVM-shaped but minimal (`aere-research/parallel-executor/src/types.rs`):
|
|
|
|
- `Key::Balance(account)`: the native-token balance of an account.
|
|
- `Key::Storage(contract, slot)`: a single key/value contract storage slot.
|
|
|
|
Values are `u128`; an absent key reads as `0`. A transaction version is `(txn_index,
|
|
incarnation)`, where `incarnation` counts how many times a transaction has been re-executed
|
|
after an abort.
|
|
|
|
The VM understands four transaction kinds (`TxKind`), each chosen because its control flow or its
|
|
written *values* depend on what it reads, so a stale read is silently wrong unless caught:
|
|
|
|
- **Transfer** `{from, to, amount}`: move `amount` if `from` can afford it. Control flow depends
|
|
on reading the sender balance.
|
|
- **Sweep** `{from, to}`: move the entire balance of `from`. The written values depend directly
|
|
on the read balance, a strong serializability probe.
|
|
- **Increment** `{contract, slot}`: `storage[slot] += 1`. When many transactions hit the same
|
|
slot this is the classic all-conflict counter: the sequential result is `start + count`, and a
|
|
correct parallel executor must reproduce exactly that despite reordering.
|
|
- **AmmSwap** `{contract, x_slot, y_slot, dx}`: a constant-product swap against a two-slot pool,
|
|
modelling a hot DeFi pool that conflicts across concurrent swaps.
|
|
|
|
Each `Txn` also carries a `gas` field, a simulated per-transaction CPU cost measured in
|
|
keccak rounds. It does **not** affect the resulting state (correctness is independent of gas); it
|
|
exists so benchmarks charge each transaction a realistic amount of interpreter-like work instead
|
|
of measuring only scheduling overhead. This is discussed honestly in Section 4.
|
|
|
|
### 2.2 One transaction semantics, two drivers
|
|
|
|
The single most important design decision is in `aere-research/parallel-executor/src/vm.rs`: there is exactly **one**
|
|
implementation of what a transaction does, `execute_txn`, and it runs against an abstract
|
|
`VmView` trait with two methods, `read(key)` and `write(key, value)`. All arithmetic is
|
|
saturating so both paths behave identically and never panic on overflow.
|
|
|
|
- The **sequential oracle** (`aere-research/parallel-executor/src/sequential.rs`) drives `execute_txn` with a view backed
|
|
directly by a live `HashMap` state, applying transactions in strict index order. This is the
|
|
definition of the correct answer.
|
|
- The **parallel executor** (`aere-research/parallel-executor/src/parallel.rs`) drives the same `execute_txn` with a view backed
|
|
by multi-version memory that records the read set and can signal an abort.
|
|
|
|
Because both paths share the exact same semantics function, the parallel result can differ from
|
|
the sequential result **only** if the concurrency control is wrong. That is precisely the
|
|
property the correctness harness (Section 3) exercises.
|
|
|
|
### 2.3 Multi-version memory (MVMemory)
|
|
|
|
`aere-research/parallel-executor/src/mvmemory.rs` keeps, for every `Key`, an ordered `BTreeMap<txn_index, cell>`, where a cell is
|
|
either a concrete `Value(incarnation, value)` written by a transaction, or an `Estimate`
|
|
placeholder (a marker that a lower-indexed transaction previously wrote here but is currently
|
|
being re-executed, so its value is not trustworthy).
|
|
|
|
A read by transaction `i` for key `k` returns the entry of the **highest** transaction `j < i`
|
|
that wrote `k` (`versions.range(..txn_idx).next_back()`). That is what makes speculative parallel
|
|
execution serial-equivalent: transaction `i` always observes the writes of all lower-indexed
|
|
transactions that have run, and nothing from higher ones. If the highest lower entry is an
|
|
`Estimate`, the read returns `Blocked(j)` and the reader must abort and park on `j`.
|
|
|
|
Storage is sharded across 256 independent mutexes keyed by an FNV-1a hash of the `Key`, so
|
|
non-conflicting transactions touch disjoint locks and run without contention. Hot keys (the
|
|
shared counter, the AMM pool) serialize on one shard, which is the honest source of the
|
|
high-conflict slowdown, not an implementation defect.
|
|
|
|
Three operations matter:
|
|
|
|
- `apply_write_set` installs a completed incarnation's writes, deletes stale entries the previous
|
|
incarnation wrote but this one did not, and returns whether the *set* of written keys changed
|
|
(Block-STM calls this "wrote a new path" and uses it to trigger suffix revalidation).
|
|
- `mark_estimates` converts an aborted transaction's writes into `Estimate` placeholders the
|
|
instant it is validation-aborted, so any concurrent higher transaction that reads one of those
|
|
keys blocks on it instead of consuming a soon-to-be-wrong value.
|
|
- `snapshot_final` materializes the committed state once the block is fully executed and
|
|
validated: base overlaid with, for each key, the value written by the highest transaction index
|
|
that wrote a concrete value.
|
|
|
|
### 2.4 The collaborative scheduler
|
|
|
|
`aere-research/parallel-executor/src/scheduler.rs` implements the Block-STM collaborative scheduler (Algorithm 3 of the paper). It
|
|
hands worker threads two kinds of task:
|
|
|
|
- **Execution** tasks: run incarnation `k` of transaction `i`.
|
|
- **Validation** tasks: re-check that an already-executed transaction's recorded read set is
|
|
still valid against current MVMemory.
|
|
|
|
Two atomic cursors, `execution_idx` and `validation_idx`, drive it. Validation of a lower index
|
|
always takes priority over execution of a higher one. When a transaction aborts (validation
|
|
fails) or writes a new path, the relevant cursor is *decreased* so the affected range is
|
|
revisited, and a `decrease_cnt` counter is bumped. The block is done only when both cursors have
|
|
passed the end, no task is in flight, and no decrease happened during the check.
|
|
|
|
Dependencies are handled **without condvars**: when execution of `i` reads an `Estimate` from
|
|
`j`, `i` is parked on `j`'s dependency list and its task dropped; when `j` finishes it re-arms `i`
|
|
(back to `ReadyToExecute`) and decreases `execution_idx` so a worker re-picks it. `add_dependency`
|
|
holds the blocking transaction's status lock across the whole check-then-park critical section, so
|
|
`j` cannot transition to `Executed` and drain its dependency list between the check and the push
|
|
(which would lose the wakeup). `try_validation_abort` uses a compare-and-set on status so only one
|
|
validator can abort a given incarnation.
|
|
|
|
The `aere-research/parallel-executor/src/parallel.rs` driver spawns `num_threads` workers, each looping `next_task` -> run ->
|
|
feed result back -> repeat, until the scheduler reports `Done`. It tracks aggregate stats:
|
|
`total_executions` (>= `num_txns`; the excess is re-executions), `total_validations`, and
|
|
`total_aborts`.
|
|
|
|
### 2.5 keccak256 state root
|
|
|
|
`aere-research/parallel-executor/src/keccak.rs` is a from-scratch keccak256 (standard Keccak-f[1600], rate 1088 bits, original
|
|
Keccak `0x01 .. 0x80` padding, i.e. keccak256 not SHA3-256), verified in tests against the known
|
|
vectors for `""` and `"abc"`. `state_root` folds a materialized state into one 32-byte root by
|
|
sorting non-zero entries into a canonical order (balances tagged `0x00`, storage tagged `0x01`,
|
|
big-endian fields) and hashing. The canonical sort makes the root deterministic and independent of
|
|
hashmap iteration order, which is exactly what a rollup state commitment requires, and it is
|
|
EVM-compatible with zero external crates.
|
|
|
|
---
|
|
|
|
## 3. Correctness guarantee (proven, not asserted)
|
|
|
|
The whole point of Block-STM is that the parallel result must equal sequential execution. The
|
|
harness (`aere-block-stm harness`, in `src/main.rs`) proves it empirically.
|
|
|
|
It runs **6 workload profiles x 200 randomized batches x {1,2,4,8,16} threads = 6000
|
|
comparisons** (1200 distinct randomized batches, each compared at five thread counts) and asserts
|
|
the Block-STM committed state equals the sequential oracle for every single case. The profiles
|
|
include deliberately adversarial fully-conflicting cases: `all-hot` (400 transactions, 200 hot
|
|
accounts, conflict probability 1.0) and `brutal-single-counter` (300 transactions on 64 accounts,
|
|
one contract, one slot, conflict probability 0.9). Reported result:
|
|
|
|
```
|
|
total (batch x threads) comparisons: 6000
|
|
mismatches : 0
|
|
RESULT: PASS -- parallel Block-STM == sequential on ALL cases
|
|
```
|
|
|
|
Workloads are generated by a seedable SplitMix64 PRNG (`aere-research/parallel-executor/src/workload.rs`) with no external RNG
|
|
crate, so any failing case can be replayed exactly. The default batch mix is 60% transfers, 15%
|
|
sweeps, 15% shared-counter increments, and 10% AMM swaps.
|
|
|
|
`cargo test --release` adds targeted unit checks:
|
|
|
|
- `shared_counter_is_serialized`: 500 transactions all incrementing one slot yield exactly 500 at
|
|
1, 2, 4, 8, and 16 threads (naive parallelism would lose updates).
|
|
- `parallel_equals_sequential_random`: 40 seeds x 4 thread counts.
|
|
- `keccak_known_answer`: keccak256 of `""` and `"abc"` match the standard vectors.
|
|
|
|
---
|
|
|
|
## 4. Measured speedup (honest numbers)
|
|
|
|
Measured on the AERE infra box: 16 physical cores, Linux 6.8, Rust 1.96. 20,000 transactions per
|
|
batch, each carrying a simulated EVM execution cost of `gas = 80` keccak-rounds. Speedup is versus
|
|
the single-threaded sequential oracle, median of 7 runs. Reproduce with
|
|
`cargo run --release -- bench`.
|
|
|
|
| Workload | 2 cores | 4 cores | 8 cores | 16 cores | abort % @16 |
|
|
|---|---|---|---|---|---|
|
|
| Low-conflict (~2% hot-touch) | 1.78x | 3.22x | 5.71x | **8.59x** | 0.3% |
|
|
| Medium-conflict (~15%) | 1.87x | 3.54x | 6.24x | **9.31x** | 1.9% |
|
|
| High-conflict (single hot counter, 15% of txns) | 1.70x | 3.04x | 4.87x | **4.62x** | 24% |
|
|
| Pathological (every tx hits ONE slot) | 0.85x | 0.85x | 0.82x | **0.73x** | 19% |
|
|
|
|
The "8 to 10x" headline is the low and medium-conflict range (8.59x and 9.31x at 16 cores). The
|
|
honest reading, including the cases that do not look good, is stated in the README and repeated
|
|
here because it is a credibility asset:
|
|
|
|
- Low and medium-conflict batches scale nearly linearly.
|
|
- The high-conflict batch still reaches roughly 4.6x because only about 15% of its transactions
|
|
touch the single hot slot; the rest are independent transfers.
|
|
- The **pathological** batch (every transaction increments the same slot) has zero available
|
|
parallelism. Block-STM correctly serializes it and is actually *slower* than sequential (0.73x)
|
|
because it pays for aborted speculation. This is the expected worst case: no correct parallel
|
|
executor can beat sequential when there is nothing to parallelize.
|
|
- There is also a floor case: if transactions do near-zero compute (`gas = 0`), concurrency-control
|
|
overhead dominates and the parallel executor is slower than sequential. Real EVM transactions are
|
|
compute-heavy (opcode interpretation, keccak, ecrecover), which is the regime Block-STM targets,
|
|
which is why the benchmark charges a realistic per-transaction cost. Run `bench 0` to see the
|
|
floor and `bench 200` for heavier transactions.
|
|
|
|
These figures are single-machine microbenchmarks of the executor. They are not a network
|
|
throughput claim, not a TPS figure, and say nothing about AERE L1, whose base layer remains
|
|
Besu-sequential.
|
|
|
|
---
|
|
|
|
## 5. Integration into the rollup sequencer
|
|
|
|
The concrete place this executor runs today is AERE's rollup layer, off-chain in a sequencer.
|
|
|
|
### 5.1 The wrapper
|
|
|
|
`rollup-sequencer/src/blockstm/BlockSTMExecutor.ts` exposes:
|
|
|
|
```
|
|
executeBatch(base: Map<StateKey, bigint>, txns: RollupTx[], opts?) : BlockSTMResult
|
|
```
|
|
|
|
It has no npm dependencies (only Node's built-in `child_process`). It serializes the prior L2
|
|
state slice and the ordered batch into the executor's line protocol and shells out to the
|
|
`aere-block-stm execute` subcommand, which runs the batch across cores, computes the new state,
|
|
and returns a keccak256 state root as JSON. The `execute` path runs the batch **both** in parallel
|
|
and sequentially and sets `parallelEqualsSequential`; the binary exits non-zero and the wrapper
|
|
throws if they diverge, so a bad root can never reach the chain. `BlockSTMResult` carries
|
|
`{ stateRoot, numTxns, threads, executions, validations, aborts, parallelEqualsSequential, state }`.
|
|
|
|
The `execute` stdin wire protocol (`src/main.rs`) is one record per line: `THREADS n`, `GAS n`,
|
|
`BASE <key> <value>` (key is `B:<acct>` or `S:<contract>:<slot>`), then `TX TRANSFER|SWEEP|INC|AMM
|
|
...`. Output is a single JSON object with the committed root and self-check.
|
|
|
|
### 5.2 The on-chain commitment flow
|
|
|
|
The rollup layer is AERE's Rollup-as-a-Service stack. The canonical factory is
|
|
`AereRaaSFactoryV2` at `0xB7F8c754AC3155197d76f01857172bBd5a5F39Ab` (bond token
|
|
WAERE `0x7e84d7d66d5da4cfE46Da67CDEeB05B323e1f5e8`, sink
|
|
`AereSink 0x69581B86A48161b067Ff4E01544780625B231676`), which deploys a fixed
|
|
`AereRollupSettlementV2` instance per registered rollup. That per-rollup settlement contract, not
|
|
a single global address, is where a sequencer proposes roots. Its call is
|
|
`proposeStateRoot(uint256 epoch, bytes32 root, bytes32 l2BlockHash)`, callable only by the
|
|
rollup's `sequencer`, with `epoch == latestEpoch + 1`, followed by an optimistic challenge window.
|
|
|
|
**Who judges that challenge, which this spec previously did not say.** The window is real and the
|
|
challenge is bonded, but the arbiter is the defendant. In
|
|
`aere-contracts/contracts/raas/AereRollupSettlementV2.sol`, `resolveChallenge(uint256,bool)`
|
|
begins with `if (msg.sender != sequencer) revert NotSequencer();`, so the party who decides whether
|
|
a challenge succeeds is the same party whose root is being challenged. Resolving with
|
|
`accepted = false` defends the root and **slashes the challenger's bond** to the sink. A challenger
|
|
who is right can therefore be ruled against by the accused and lose the bond for being right. The
|
|
only path that does not run through the sequencer is `resolveChallengeExpired`, which applies when
|
|
the sequencer simply ignores a challenge past the defense grace period.
|
|
|
|
This document was already correct further down when it lists an on-chain fraud-proof verifier as
|
|
roadmap. What it was missing is the sentence that says who judges until then, and that omission
|
|
made an optimistic-with-a-real-arbiter reading available where none is warranted. **The security of
|
|
a rollup settled through this contract rests on the sequencer's honesty, not on a proof**, and a
|
|
rollup deployed by `AereRaaSFactoryV2` must not be described as trust-minimised on the strength of
|
|
this challenge window. The same warning is carried in the contract source itself.
|
|
|
|
The flow is therefore:
|
|
|
|
```
|
|
batch of L2 txns -> BlockSTMExecutor.executeBatch() -> { stateRoot, ... }
|
|
|
|
|
v
|
|
settlement.proposeStateRoot(epoch, stateRoot, l2BlockHash)
|
|
```
|
|
|
|
Because the executor guarantees the parallel result equals sequential execution, the committed
|
|
root is deterministic and reproducible, which is what makes it safe as an optimistic-rollup
|
|
commitment: a Phase-2 fraud proof would re-derive it by re-running the same deterministic
|
|
executor over the disputed batch. See `rollup-sequencer/src/blockstm/example.ts` for an
|
|
end-to-end run.
|
|
|
|
### 5.3 Integration status (honest)
|
|
|
|
- Executor: real Block-STM, correctness-proven, benchmarked. Shipped.
|
|
- Integration: the `execute` JSON boundary is live and tested; the TypeScript wrapper drives it and
|
|
returns a root ready for `proposeStateRoot`. Shipped as the batch-execution core.
|
|
- **Not yet built:** the wiring from a live L2 mempool into `executeBatch` (this module is the
|
|
batch-execution core the full sequencer loop plugs into, not a running production sequencer), and
|
|
an on-chain optimistic fraud-proof verifier (settlement is optimistic Phase 1 today). These are
|
|
roadmap.
|
|
|
|
---
|
|
|
|
## 6. The on-chain hint registry: `AereBlockSTMRegistry`
|
|
|
|
### 6.1 Purpose
|
|
|
|
For Block-STM to schedule efficiently it benefits from **hints** about which storage slots a
|
|
transaction is likely to read or write; a good hint reduces the abort rate. Solidity does not
|
|
expose this metadata. `AereBlockSTMRegistry` (`contracts/contracts/parallel/AereBlockSTMRegistry.sol`)
|
|
is an opt-in registry where a contract publishes its likely read/write set at the function-selector
|
|
grain, so an eventual scheduler can consult it. It is **advisory only**: hints cannot change
|
|
execution semantics, and a scheduler always re-validates the actual read/write set after execution.
|
|
A wrong hint costs at most one extra abort; it can never make a transaction succeed when it should
|
|
fail.
|
|
|
|
### 6.2 Data model and API
|
|
|
|
- `SlotHint { bytes32 slotPrefix; Mode mode; }` where `Mode` is `READ`, `WRITE`, or `READWRITE`.
|
|
- `HintSet { address publisher; SlotHint[] hints; uint64 publishedAt; }`, stored per
|
|
`(target, selector)` key `keccak256(abi.encodePacked(target, selector))`.
|
|
|
|
Functions:
|
|
|
|
- `publish(address target, bytes4 selector, SlotHint[] hints)`: publish or replace the hint set.
|
|
It caps hints at 64 (`TooManyHints` above that) and **replaces** rather than appends.
|
|
- `clear(address target, bytes4 selector)`: clear the set; publisher only.
|
|
- `hintsFor(target, selector) -> (publisher, hints, publishedAt)`: the view a scheduler reads.
|
|
- `publisherOf(target, selector) -> address`.
|
|
|
|
### 6.3 Access control (audit fix HIGH #27)
|
|
|
|
The first publisher for a `(target, selector)` must be the target itself **or** the target's
|
|
`Ownable` owner, checked best-effort via a `staticcall` to `owner()` (`_tryOwner`). This closes a
|
|
front-run squatting vector: without it, an attacker could publish poisoned hints for a victim
|
|
contract's selector before the real owner did. After the first publisher claims a key, only that
|
|
publisher can update or clear it (`NotPublisher` otherwise). There is no admin override and no
|
|
Foundation gate: the contract author knows its own access pattern best. The registry test
|
|
(`contracts/test/block-stm-registry.test.js`) exercises the claim rule, the replace-not-append
|
|
behavior, the 64-hint cap, and publisher-only clear.
|
|
|
|
### 6.4 Deployment facts (live)
|
|
|
|
- Address: `AereBlockSTMRegistry 0x98E2C3e615841919d173D8FF642514c5902E8A28` (roadmap item #33).
|
|
- Deploy tx: `0x5646445f5a6c8a3d9d06db7a6becd95f6227608b64291319fd19d7d928beee72`, block 8877969.
|
|
- Deployed from an operational deployment account (moving to governance); the account hex is operational detail and is not published here. Code size 1753 bytes. Deployed 2026-07-10.
|
|
- Read-verified at deploy: `hintsFor(unpublished)` returns `(0x0, [], 0)` and
|
|
`publisherOf(unpublished)` returns the zero address.
|
|
- No owner, no admin, holds no funds.
|
|
|
|
### 6.5 What the registry does NOT do (honest scope)
|
|
|
|
The AERE L1 (Besu) executes sequentially today. The registry is metadata for the eventual
|
|
Block-STM Besu fork; it does **not** make L1 parallel, and publishing hints has no effect on how
|
|
any transaction executes on mainnet right now. Its `hintsFor(target, selector)` view is
|
|
intentionally shaped to be the interface a future consensus precompile (planned at `0x103` in the
|
|
Phase-2 Besu fork) would read. That precompile and fork do not exist. The contract is deliberately
|
|
inert-but-ready: real, correct metadata storage today, waiting for a consumer that is roadmap.
|
|
|
|
---
|
|
|
|
## 7. Related on-chain anchor: `AereRollupValidity` (validity proofs of the same executor)
|
|
|
|
There is a second, stronger settlement path already anchored on-chain for the exact same executor.
|
|
`AereRollupValidity` at `0x38772063572DF94E90351e44ccbBEefD5F497fbd` verifies **SP1 zkVM Groth16
|
|
validity proofs** that AERE's deterministic rollup executor transitioned a prior state root to a
|
|
new one by applying a specific batch. Its `PROGRAM_VKEY` binds the SP1 verification key of the
|
|
guest ELF that ports `execute_txn`, keccak256 and state-root folding **verbatim** from
|
|
`parallel-executor/src/{vm,keccak}.rs`, so the proven computation is byte-identical to what the
|
|
production `aere-block-stm` binary self-checks and what `BlockSTMExecutor` commits. Public values
|
|
are exactly 160 bytes: `abi.encode(chainId, prevRoot, postRoot, batchHash, numTxns)`. Submission is
|
|
permissionless; an epoch is final the instant its proof verifies (no challenge window), gated by a
|
|
`prevRoot == latestRoot` continuity check. It routes through the SP1 gateway
|
|
`SP1VerifierGateway 0x9ca479C8c52C0EbB4599319a36a5a017BCC70628`.
|
|
|
|
Per the SDK registry, epoch 0 has already been recorded from a real proof
|
|
(`submitEpoch` `0xd4f8d858...12a4b0`), advancing `latestRoot` to `0x256fa277...25e3ac` with
|
|
`epochCount = 1`, under an immutable vkey `0x00c39737...84ad` (these three values are cited in the
|
|
abbreviated form they appear in `sdk-js/src/addresses.ts`).
|
|
|
|
**Honest scope, stated in the contract itself:** this proves the state transition of AERE's
|
|
*current* rollup executor, whose VM implements a bounded set of transaction kinds (Transfer,
|
|
Sweep, Increment, AmmSwap) over a balance/storage map. It is a real validity proof of *that*
|
|
executor. It is **not** a proof of arbitrary EVM bytecode. The path to a full validity rollup is
|
|
replacing the executor's VM with a real EVM (revm) inside the zkVM, a separate multi-quarter
|
|
effort. No claim built on this contract should imply it proves a full EVM.
|
|
|
|
---
|
|
|
|
## 8. Roadmap: moving parallelism into base consensus
|
|
|
|
What exists today is a proven off-chain executor plus a live on-chain hint registry. Promoting
|
|
Block-STM into AERE's base consensus is the roadmap, and it needs work that is not done:
|
|
|
|
1. **The Besu execution-client fork (the hard blocker).** AERE L1 is Hyperledger Besu, a Java
|
|
client that executes block transactions sequentially. Running Block-STM at L1 requires forking
|
|
Besu's transaction-processing pipeline to execute speculatively with multi-version memory,
|
|
validation, and abort/retry, then reconcile with QBFT block production. This is a multi-month
|
|
Java engineering effort and is not mainnet-active. A first prototype now exists and is
|
|
benchmarked: a parallel state-root **commit** was added to the forked Besu client's Bonsai
|
|
world-state (`aerenew/parallel/`, `parallel_commit.patch`), self-checked to produce a commit
|
|
root **bit-identical to the sequential-commit root** across independent-transfer, commit-heavy
|
|
SSTORE, deletion, and mixed workloads. The honest finding is a boundary, not a win: the commit
|
|
phase is allocation and memory-bandwidth bound, so adding commit worker threads (widths 2 to 16)
|
|
is *slower* than a single worker, not faster. The improvement that does hold is a single-threaded
|
|
commit rewrite that is roughly **2x cheaper than the stock parallel-trie commit** (for example,
|
|
on medium tries about 316.98 ms stock versus 142.38 ms at width 1); end-to-end, Block-STM
|
|
execution plus the width-1 commit gives about 1.27x to 1.42x on commit-heavy load versus stock
|
|
sequential exec plus sequential commit, and the real execution-side speedup remains the ~8.6x to
|
|
9.3x of Section 4. A network throughput win is gated on real execution-heavy load. This is a
|
|
research/benchmark control surface (a process-global flag), not a mainnet-active feature; until
|
|
the full pipeline lands, the registry's `0x103` precompile consumer does not exist and hints have
|
|
no runtime effect on L1.
|
|
|
|
2. **Fraud proofs for the optimistic rollup path.** The per-rollup `AereRollupSettlementV2`
|
|
settlement is optimistic Phase 1: propose plus challenge window, no on-chain fraud-proof
|
|
verifier yet. The deterministic executor makes a fraud proof *constructible* (re-run the same
|
|
binary over the disputed batch), but the on-chain verifier is not built.
|
|
|
|
3. **Full-EVM validity.** `AereRollupValidity` proves the bounded four-kind VM, not arbitrary EVM.
|
|
A full validity rollup needs a real EVM inside the zkVM.
|
|
|
|
4. **Production sequencer loop.** The live-mempool -> `executeBatch` -> `proposeStateRoot` loop is
|
|
not wired end-to-end; today the module is the batch-execution core, not a running sequencer.
|
|
|
|
---
|
|
|
|
## 9. Honest limitations summary
|
|
|
|
- The AERE L1 mainnet executes **sequentially** on Besu. No parallel execution runs at L1 today,
|
|
and the hint registry, while live, has no L1 consumer yet.
|
|
- The parallel executor's VM is a **bounded four-kind model** (Transfer, Sweep, Increment,
|
|
AmmSwap) over a balance/storage map, not a full EVM. Its correctness proofs and validity proofs
|
|
are proofs of *that* executor.
|
|
- The measured speedup figures are **single-machine microbenchmarks** (16 cores, gas=80), not a
|
|
network throughput or TPS claim.
|
|
- The rollup settlement path is optimistic Phase 1 with **no on-chain fraud proof** yet; the
|
|
validity-proof anchor covers only the bounded VM.
|
|
- Broader chain caveats apply and are not hidden: AERE runs seven validators under one operator, a
|
|
single client, and has had no external audit; usage is thin. The self-verifying executor and the
|
|
advisory registry are real and proven, but they sit on that foundation.
|
|
|
|
---
|
|
|
|
## 10. Address reference (verbatim, chain 2800)
|
|
|
|
| Contract / entity | Address |
|
|
|---|---|
|
|
| AereBlockSTMRegistry | `0x98E2C3e615841919d173D8FF642514c5902E8A28` |
|
|
| AereRollupValidity | `0x38772063572DF94E90351e44ccbBEefD5F497fbd` |
|
|
| AereRaaSFactoryV2 | `0xB7F8c754AC3155197d76f01857172bBd5a5F39Ab` |
|
|
| AereSink | `0x69581B86A48161b067Ff4E01544780625B231676` |
|
|
| WAERE (RaaS bond token) | `0x7e84d7d66d5da4cfE46Da67CDEeB05B323e1f5e8` |
|
|
| SP1VerifierGateway | `0x9ca479C8c52C0EbB4599319a36a5a017BCC70628` |
|
|
| Foundation (owner of Ownable contracts) | `0x0243A4f47D44b40b65D33f20329dE20D00c6f3C3` |
|
|
| Deployer (registry / validity) | an operational deployment account, moving to governance; hex not published |
|
|
|
|
`AereRollupSettlementV2` instances are deployed per rollup by `AereRaaSFactoryV2`, so no single
|
|
global settlement address exists; the sequencer commits to the per-rollup instance's
|
|
`proposeStateRoot`.
|