Dated corrections (2026-10-27): a validator, not every node, refuses an anchor below the threshold (a node started from this package lowers the count to one seal; SPEC 6.4); the startup guard refuses above the quorum and only warns below it; anchors carry at least one seal in the warm-up and three or more after; the follower's rewrite bound is 33 from stage R; run-node.sh comment and verify-live-precompiles.mjs brought to the same form
This commit is contained in:
parent
a537b7c9d1
commit
6ece1f2a6c
10
README.md
10
README.md
@ -17,8 +17,10 @@ consensus post-quantum, and nothing in the precompile patches touches consensus.
|
||||
Consensus on chain 2800 is **hybrid post-quantum in a precise and limited sense**, by a separate
|
||||
mechanism: the QBFT header anchor in `anchor/` and `patches/0003`. Since 2026-08-14 every
|
||||
32nd block (an anchor block; every 128th from block 17,225,968 to block 20,746,736, see below) must carry, under its block hash, a certificate of valid post-quantum
|
||||
validator seals, and a node does not finalize an anchor block without it: at least three Falcon-512
|
||||
seals at first (f+1 of nine), six of nine, as many as the 2f+1 quorum, from block 14,961,456 (August 21,
|
||||
validator seals, and a validator does not finalize an anchor block without it (a node started from this package with
|
||||
`run-node.sh` lowers that count to one seal, at the cost stated in `SPEC.md` section 6.4; corrected 2026-10-27: this said
|
||||
"a node"): at least three Falcon-512
|
||||
seals at first (f+1 of nine), six of nine, as many as the QBFT quorum of nine (corrected 2026-10-27: this said the 2f+1 quorum, which at nine validators is five), from block 14,961,456 (August 21,
|
||||
2026), and **seven of ten per scheme, as many as the 2f+1 quorum of the ten validators, since block 20,715,632** (2026-09-29, AIP-22 stage 1; below block 24,148,752 the seals proved those validators signed the block, not that it was decided, per the AIP-22 erratum of 2026-10-01, and from that block a certificate that carries the quorum of one round proves the decision); since block 17,047,600 (2026-09-04) the certificate is
|
||||
**hybrid**, Falcon-512 AND SLH-DSA-SHA2-128s seals. From block 17,225,968 (schedule set on all nine
|
||||
validators on 2026-09-05) the anchor fell on every 128th block instead of every 32nd, with both
|
||||
@ -105,7 +107,7 @@ Both patches target upstream commit `d2032017bb3b8cb215a97303980a1e4a643f7180`,
|
||||
| `patches/0010-aere-pq-round-bound-commit-seal.patch` | the fleet distribution of 2026-10-14: AIP-22 stage R, the round-bound post-quantum commit seal and the v3 anchor certificate, inert below the height `aere.pq.commitRoundBlock`, which is block 24,148,752 on chain 2800, in force there since 2026-10-24 (announced on 2026-10-22; not yet set at 2026-10-14), and 6,157,024 on testnet 28001 since 2026-10-14 | the tree after 0009 |
|
||||
|
||||
`run-node.sh` applies 0001 and 0003 to 0010, in that order; 0002 is for the testnet only. A node
|
||||
built without 0008 stops at block 20,836,227. (Note added 2026-10-09: 0009 is not needed to follow
|
||||
built without 0008 follows the chain up to block 20,836,227 and refuses block 20,836,228. (Note added 2026-10-09: 0009 is not needed to follow
|
||||
the chain today; it keeps the recipe equal to what the fleet runs, see `RUN-A-NODE.md`. Note added
|
||||
2026-10-14: the same holds for 0010 while `aere.pq.commitRoundBlock` is unset on chain 2800, which
|
||||
`run-node.sh` does not set; when the founder sets that height, a node without 0010 stops at the block
|
||||
@ -317,4 +319,4 @@ able to trust without checking.
|
||||
well: every validator refuses a commit without a valid seal, and nine of the ten refuse any consensus message without
|
||||
one; the tenth, which runs the second client, applies the rule to proposal, prepare and round-change messages from
|
||||
AIP-22 stage 4, whose height is not yet set on chain 2800. On the testnet the second client's validator enforces
|
||||
commits since block 1,314,403 and all four types since block 3,117,000 (SPEC section 2.6).)
|
||||
commits since block 1,314,403 and all four types since block 3,117,000 (SPEC section 2.6).) (*Added 2026-10-27:* stage 4 is in force on chain 2800 since block 24,300,000, reached on 2026-10-25; from it the second client judges all four message types by their seals.)
|
||||
|
||||
@ -36,8 +36,9 @@ is not required to follow the chain.
|
||||
```
|
||||
|
||||
You still need a bootnode enode for discovery (see the bootnodes section below for how to get one
|
||||
today). Everything except peer discovery works without it; if you omit `--bootnode` the script says
|
||||
so plainly and stops with instructions rather than starting a node that can never find a peer.
|
||||
today). Everything except peer discovery works without it; if you omit `--bootnode`, `run-node.sh` uses
|
||||
the published bootnode and says so, and `--bootnode` uses another (corrected 2026-10-27: until this date
|
||||
this sentence said the script stops with instructions, which it did until 2026-09-11).
|
||||
|
||||
Everything the one command does is also written out by hand below, unchanged, for anyone who wants to
|
||||
audit each step rather than run it.
|
||||
@ -152,7 +153,7 @@ shipped code in favour of the anchor rules and changed no enforcement, so that s
|
||||
The anchor ships in this repository both as source, under `anchor/`, and as
|
||||
`patches/0003-aere-pq-anchor.patch`. A node built without it has not been shown to import
|
||||
headers past block 13,014,000: the second client needed an explicit change to accept the sixth
|
||||
element, and no floor-only build has been observed following the chain past that height. Apply `0001` and `0003` to `0010` together and treat a build missing any of them as unable to follow the current chain (from 2026-09-22 `0006` and `0007` are part of the recipe; a build without `0008` stops at block 20,836,227 and one without `0010` at block 24,148,751; see the sections on them below).
|
||||
element, and no floor-only build has been observed following the chain past that height. Apply `0001` and `0003` to `0010` together and treat a build missing any of them as unable to follow the current chain (from 2026-09-22 `0006` and `0007` are part of the recipe; a build without `0008` follows the chain up to block 20,836,227 and refuses block 20,836,228, and one without `0010` follows it up to block 24,148,751 and refuses block 24,148,752; see the sections on them below).
|
||||
|
||||
## Patch 0005 exists because the import proof was actually attempted
|
||||
|
||||
@ -230,7 +231,7 @@ distribution.
|
||||
|
||||
## Patch 0008: AIP-22 stages 1 to 3 (2026-10-01)
|
||||
|
||||
**A node built from patches 0001 and 0003 to 0007 stops at block 20,836,227.** From block
|
||||
**A node built from patches 0001 and 0003 to 0007 follows the chain up to block 20,836,227 and refuses block 20,836,228.** From block
|
||||
20,836,228 (AIP-22 stage 3, 2026-09-30) the header of every chain-2800 block names the validators by
|
||||
post-quantum ids from the registry v3 epoch, and such a node refuses the block with
|
||||
`Invalid block header: Incorrect validators`. Measured: a follower built from patches 0001 and 0003
|
||||
@ -268,7 +269,7 @@ rule that refused it.
|
||||
|
||||
Since 2026-10-05 the Besu nodes of chain 2800 run a distribution built from the tree of patch 0008
|
||||
plus two changes; `patches/0009-aere-pq-seal-judge-snap-cap.patch` brings the recipe to that exact
|
||||
tree. **A node built from patches 0001 and 0003 to 0008 followed the chain up to block 24,148,751** and stops at block 24,148,752 (AIP-22 stage R), for lack of patch 0010 (below); neither change of 0009 alters what a node accepts below the AIP-22 stage 4 height (`aere.pq.finalityBlock`), which is block 24,300,000 on chain 2800 (armed 2026-10-21, in force since 2026-10-25); `run-node.sh` sets it since 2026-10-21; the four message-seal
|
||||
tree. **A node built from patches 0001 and 0003 to 0008 followed the chain up to block 24,148,751** and refuses block 24,148,752 (AIP-22 stage R), for lack of patch 0010 (below); neither change of 0009 alters what a node accepts below the AIP-22 stage 4 height (`aere.pq.finalityBlock`), which is block 24,300,000 on chain 2800 (armed 2026-10-21, in force since 2026-10-25); `run-node.sh` sets it since 2026-10-21; the four message-seal
|
||||
layers it requires at startup (AERE-PQC-FIN-02) were already set in the follower options. The two changes:
|
||||
|
||||
- the heard-seal store and commit messages that arrive before the proposal: from the stage 4 height
|
||||
@ -300,8 +301,7 @@ inert below its height.** Its height is the per-node property `aere.pq.commitRou
|
||||
(`H_r`), an anchor height; **on chain 2800 it is block 24,148,752** (announced on 2026-10-22, reached on 2026-10-24;
|
||||
`run-node.sh` and every validator carry it since 2026-10-21). Below it, a node built from patches 0001
|
||||
and 0003 to 0010 makes, at every height, exactly the decisions of a node built from 0001 and 0003 to
|
||||
0009, so **a node built from 0001 and 0003 to 0009 follows the chain up to block 24,148,751 and stops
|
||||
there** (derived from the code, see below). On the public testnet 28001 the stage is active: `H_r` = 6,157,024,
|
||||
0009, so **a node built from 0001 and 0003 to 0009 follows the chain up to block 24,148,751 and refuses block 24,148,752** (derived from the code, see below). On the public testnet 28001 the stage is active: `H_r` = 6,157,024,
|
||||
crossed on 2026-10-14 (14:02Z) with all five validators proposing and no refusal; on chain 2800 it is active since block 24,148,752, crossed on 2026-10-24.
|
||||
|
||||
What the stage changes, from `H_r` on (specified in `SPEC.md`, sections 2.3, 2.6, 2.7, 3.3, 3.4 and 8
|
||||
@ -321,7 +321,7 @@ A node that does not carry patch 0010 at that height refuses the first v3 anchor
|
||||
because its decoder does not know certificate version 3: it stops at block `H_r - 1` and accepts
|
||||
nothing wrong (derived from the code; not yet observed on chain 2800). A node built from this
|
||||
recipe before 2026-10-21 needs only the property, which `run-node.sh` carries. After `H_r`
|
||||
there is no way back to the round-free form on that chain. (Note added 2026-10-26: stage R is in force on chain 2800 since block 24,148,752, crossed on 2026-10-24; from it the validators accept an anchor only with a v3 certificate, and the 20 most recent anchors read with the public verifier on 2026-10-26 carry one; that a node without patch 0010 stops at block 24,148,751 is still derived from the code, not observed on chain 2800.)
|
||||
there is no way back to the round-free form on that chain. (Note added 2026-10-26: stage R is in force on chain 2800 since block 24,148,752, crossed on 2026-10-24; from it the validators accept an anchor only with a v3 certificate, and the 20 most recent anchors read with the public verifier on 2026-10-26 carry one; that a node without patch 0010 follows the chain up to block 24,148,751 and refuses block 24,148,752 is still derived from the code, not observed on chain 2800.)
|
||||
|
||||
Measured 2026-10-12 (the patch generator, in the operator repository) and re-measured 2026-10-14 on
|
||||
the patch files of this package: patches 0001 and 0003 to 0010 applied with plain `git apply` on a
|
||||
@ -383,8 +383,8 @@ band that worked here was roughly 2.4 GB early and 3.4 GB past nine million bloc
|
||||
The Aere fork reads its per-node configuration from JVM system properties passed through the
|
||||
`BESU_OPTS` environment variable, not from the genesis file. `run-node.sh` sets these for you; this
|
||||
is what it sets, and what a manual operator must export before the `besu` command below, or the node
|
||||
will refuse the first anchor at block 13,014,000. Five of them are the ones without which a node stops
|
||||
at block 17,047,600 (the first hybrid, v2 certificate) or at the first anchor after 17,225,968 (the
|
||||
will refuse the first anchor at block 13,014,000. Five of them are the ones without which a node refuses
|
||||
block 17,047,600 (the first hybrid, v2 certificate) or the first anchor after 17,225,968 (the
|
||||
interval change): `anchorV2Block`, `schemeSchedule`, `hybridRegistry` (the SLH-DSA-SHA2-128s public
|
||||
keys, `registries/hibrid-10.properties` since 2026-09-10; `hibrid-1.properties` before), `anchorIntervalSchedule`, and the two dated steps in
|
||||
`anchorMinSeals` (see `anchor/README.md`, scope item 3).
|
||||
@ -446,7 +446,7 @@ export BESU_OPTS="\
|
||||
A node syncing from block 0 starts into the GENESIS validator set, which is small (three
|
||||
validators). The startup threshold guard (`PqAnchorThresholdGuard`) refuses an effective seal threshold above `N - f` of that set (`AERE-PQC-THRESHOLD-01`; 3 at N=3), since inside the fault model no more seals can exist, and from `H_r` it also refuses one above the set's QBFT quorum (`AERE-PQC-THRESHOLD-02`; 2 at N=3); a threshold at or above the quorum below `H_r` only gets a WARN. The published schedule reaches K=6 (block 14,961,456) and K=7 (block 20,715,632), above both bounds at N=3, so without `aere.pq.anchor.minSealsCeiling` a from-genesis node refuses to start. The ceiling lowers the EFFECTIVE threshold to 1, which the guard accepts against the genesis set, WITHOUT editing the published schedule, exactly as that guard's own message instructs (`--Xaere-pq-anchor-min-seals-max`). (Corrected 2026-10-26: until this date this paragraph said the guard refuses a threshold at or above the quorum and gave the value 1 as `quorum(3) - 1`; that was the guard of 2026-08-02, and since 2026-08-20 the code refuses only above `N - f`, as above.)
|
||||
|
||||
It weakens one check of this follower, and section 6.4 of `SPEC.md` states the cost: against an adversary holding every classical validator key and no post-quantum key the follower keeps the rewrite bound of a validator, because one seal the adversary cannot make is enough, but ONE leaked or misused validator post-quantum key makes this follower's rewrite depth unbounded, where a validator at K=7 needs seven such keys; and from block 24,148,752 (AIP-22 stage R) the bound of this follower is 33 blocks where a validator's is 32. What is not weakened: every anchor must still carry a valid validator Falcon seal that verifies against the registry, and its digest must still bind the certificate under the block hash. (Corrected 2026-10-26: until this date this paragraph said the ceiling does not weaken the post-quantum binding a follower checks and that the seal-count floor is not a history-verification property; both said less than the cost above.) Real anchor blocks carry far more than one seal, so all import cleanly: measured 2026-09-12 by our own second implementation walking the live chain, the certificates carried 14, 16, 18 or 20 seals in total, which is seven to ten per half since the certificate became hybrid on 2026-09-04, at block 17,047,600 (corrected 2026-10-26: the date was given as 2026-09-03, the day of the testnet). A validator, which starts into the full set and proposes, does not set this, and a follower should restart without it once synced (below).
|
||||
It weakens one check of this follower, and section 6.4 of `SPEC.md` states the cost: against an adversary holding every classical validator key and no post-quantum key the follower kept the rewrite bound of a validator below block 24,148,752, because one seal the adversary cannot make is enough, and from that block (AIP-22 stage R) its bound is 33 blocks where a validator's is 32, because below the quorum of one round the anchors it accepts do not prove that their parent was decided; but ONE leaked or misused validator post-quantum key makes this follower's rewrite depth unbounded, where a validator at K=7 needs seven such keys. What is not weakened: every anchor must still carry a valid validator Falcon seal that verifies against the registry, and its digest must still bind the certificate under the block hash. (Corrected 2026-10-26: until this date this paragraph said the ceiling does not weaken the post-quantum binding a follower checks and that the seal-count floor is not a history-verification property; both said less than the cost above.) Real anchor blocks carry at least one valid seal, so all import at this floor of one: anchors with one or two seals occur from block 13,014,000 until the emergency ceiling was lifted on 2026-08-14 (83 of the 625 anchors of the warm-up, blocks 13,014,000 to 13,033,999, and later ones such as block 13,283,120; measured 2026-10-26), three or more after that, and, measured 2026-09-12 by our own second implementation walking the live chain, the certificates carried 14, 16, 18 or 20 seals in total, which is seven to ten per half since the certificate became hybrid on 2026-09-04, at block 17,047,600 (corrected 2026-10-26: the date was given as 2026-09-03, the day of the testnet; corrected 2026-10-27: this sentence said that real anchor blocks carry far more than one seal, which the anchors before 2026-08-14 do not). A validator, which starts into the full set and proposes, does not set this, and a follower should restart without it once synced (below).
|
||||
|
||||
**What you will see in the log, and why it is not an incident.** With this ceiling set, the node
|
||||
prints a red startup banner (`AERE-PQC-EMG-BANNER-01`, "starting with 1 POST-QUANTUM SAFETY
|
||||
@ -464,7 +464,7 @@ impossible to forget, so it shouts on every use rather than once at startup. On
|
||||
it is loud - measured on our own import run, 2,786 such lines in three megabytes of log. It is not a chain fault and not a failed verification. A node started with `run-node.sh` also prints, once at startup, a WARN with `AERE-PQC-ROUND-05`: from `H_r` the effective threshold 1 is below the quorum of the set it starts into, so the anchors it accepts there do not by themselves prove that their parent was decided; that is the cost described above, not a fault (derived from the code; added 2026-10-26).
|
||||
|
||||
What WOULD be a fault, and what you should watch for instead: an anchor **refused**. Those read
|
||||
`IneligibleSeal`, `SealCountBelowThreshold`, or `AnchorDigestMismatch` and stop the import. Once the node is synced to the head, restart it without `aere.pq.anchor.minSealsCeiling`: that removes the cost described in "Why the seal-threshold ceiling" (one leaked validator post-quantum key would otherwise be enough to rewrite this node's history past an anchor), and the shouting stops because the control is no longer lowered. The restart needs the node past block 18,083,404, where the set became ten: below that block, with the stage R height in the configuration, the guard would refuse K=7, above the quorum of the nine-validator set of that time (`AERE-PQC-THRESHOLD-02`). (Corrected 2026-10-26: until this date this paragraph said the restart works once the node is past block 13,034,000; derived from the code, not measured.)
|
||||
`IneligibleSeal`, `SealCountBelowThreshold`, or `AnchorDigestMismatch` and stop the import. Once the node is synced to the head, restart it without `aere.pq.anchor.minSealsCeiling`: that removes the cost described in "Why the seal-threshold ceiling" (one leaked validator post-quantum key would otherwise be enough to rewrite this node's history past an anchor), and the shouting stops because the control is no longer lowered. The restart needs the node past block 18,083,404, where the set became ten: below that block, with the stage R height in the configuration, the guard would refuse K=7, above the quorum of the nine-validator set of that time (`AERE-PQC-THRESHOLD-02`). (Corrected 2026-10-26: until this date this paragraph said the restart works once the node is past block 13,034,000; derived from the code, not measured.) `run-node.sh` always passes that property, and an empty `AERE_ANCHOR_MIN_SEALS_CEILING` keeps its default of 1, so with the script the restart is `AERE_ANCHOR_MIN_SEALS_CEILING=7 ./run-node.sh` with your other options: a ceiling at or above every step of the schedule (the highest is 7) lowers the threshold at no height, so the per-block `AERE-PQC-EMG-CEILING-01` lines stop, while the startup banner still names the ceiling. Without the script, start the node with the same `BESU_OPTS` minus that property. (Added 2026-10-27; derived from the code, `PqAnchorConfig.emergencyCeilingLowersAt` and `AerePqEmergencyOptions`, not measured with the published package.)
|
||||
|
||||
This is the configuration of a node that FOLLOWS the chain. *Corrected 2026-10-20:* until this date
|
||||
the paragraph said that a follower leaves out `aere.falcon.attach*`, `aere.falcon.validatorCount` and
|
||||
|
||||
10
SPEC.md
10
SPEC.md
@ -517,7 +517,7 @@ that also carries a valid Falcon seal [MEASURED 2026-09-05, 400 consecutive anch
|
||||
`anchor/consensus/common/.../PqAnchorV2.java`, `PqSchemeSchedule.java`; the public verifier
|
||||
`tools/verify-anchor.mjs`). The enforced minimum number of valid seals is a height
|
||||
schedule: 0 from 13,014,000 (warm-up), 3 from 13,034,000 (f+1 of the nine validators of that time; enforced on the fleet since
|
||||
2026-08-14), 6 from block 14,961,456 (of nine then, as many as the 2f+1 quorum at that size, and below the ten-validator quorum of seven from 2026-09-11), and **7 from block 20,715,632** (AIP-22 stage 1, as many as the 2f+1 quorum of the ten validators, the same count QBFT itself requires; below block 24,148,752 the seals proved those validators signed the block, not that it was decided, per the AIP-22 erratum of 2026-10-01, and from that block a certificate that carries the quorum of one round proves the decision) (source: `anchor/README.md`, "Scope boundary"; `RUN-A-NODE.md`, the anchor section).
|
||||
2026-08-14), 6 from block 14,961,456 (of nine then, as many as the QBFT quorum at that size (corrected 2026-10-27: this said the 2f+1 quorum, which at nine validators is five), and below the ten-validator quorum of seven from 2026-09-11), and **7 from block 20,715,632** (AIP-22 stage 1, as many as the 2f+1 quorum of the ten validators, the same count QBFT itself requires; below block 24,148,752 the seals proved those validators signed the block, not that it was decided, per the AIP-22 erratum of 2026-10-01, and from that block a certificate that carries the quorum of one round proves the decision) (source: `anchor/README.md`, "Scope boundary"; `RUN-A-NODE.md`, the anchor section).
|
||||
|
||||
The defensible sentence, and the only form this document endorses: *every anchor block (every
|
||||
32nd block; every 128th from 17,225,968 to 20,746,736) does not
|
||||
@ -699,8 +699,10 @@ Semantics of each parameter (source: `PqAnchorConfig.java`):
|
||||
cap: a proposer includes every eligible seal it heard in time, so real anchor headers carry more
|
||||
than K (measured seal counts at K=3, N=7: 42 blocks with 4 seals, 36 with 5, 5 with 6; a
|
||||
Falcon-512 seal is 666 bytes) (source: `PqAnchorConfig.java`, `PROPERTY_MAX_SEALS` javadoc,
|
||||
measurement dated 2026-08-07). Real anchor blocks carry three to nine seals (source:
|
||||
`RUN-A-NODE.md`). *Note added 2026-10-20:* the cap in the block above is the archive node's own value
|
||||
measurement dated 2026-08-07). Real anchor blocks carry at least one valid seal: one or two on anchors from block
|
||||
13,014,000 until the emergency ceiling was lifted on 2026-08-14, three or more after that, and at least seven
|
||||
per scheme since block 20,715,632 (source: `RUN-A-NODE.md`; *corrected 2026-10-27:* this sentence said three to
|
||||
nine, which neither the anchors of the warm-up and of the emergency ceiling nor the ten-seal anchors of today fit). *Note added 2026-10-20:* the cap in the block above is the archive node's own value
|
||||
(nine); the validators run ten (the validator kit, `validator/README.md`). The cap only limits what a
|
||||
PROPOSER writes, so on a follower it is inert.
|
||||
- `aere.pq.anchor.disable`: local emergency de-arm; both rules off on this node; per-block disarm
|
||||
@ -1173,7 +1175,7 @@ the ceiling at 1, the follower's seal-COUNT requirement is 1 at every height, no
|
||||
NOT weakened: every anchor must still carry a digest that binds its certificate under the block
|
||||
hash, indices must still be strictly increasing, every carried seal is still Falcon-verified
|
||||
against the height-correct registry, and eligibility in the parent's validator set is still
|
||||
enforced. Real anchor blocks carry far more than one seal (3 to 9 when this section was written; 8 to 10 distinct Falcon-512 signers on each of 32 consecutive anchors measured on 2026-10-26, blocks 24,491,993 to 24,493,016), so all of history imports cleanly. The seal-count floor also bounds how much of history a leaked validator post-quantum key can rewrite for this follower (note of 2026-10-07 below; corrected 2026-10-26: this sentence called it a proposer-liveness property and not a history-verification property, which that note contradicts); a validator, which starts into the full set, does not set the ceiling (source:
|
||||
enforced. Real anchor blocks carry at least one valid seal (one or two on anchors from block 13,014,000 until the emergency ceiling was lifted on 2026-08-14: 83 of the 625 anchors of the warm-up, blocks 13,014,000 to 13,033,999, and later ones such as block 13,283,120; three or more after that; at least seven per scheme since block 20,715,632, with 8 to 10 distinct Falcon-512 signers on each of 32 consecutive anchors measured on 2026-10-26, blocks 24,491,993 to 24,493,016), so all of history imports at the follower's floor of one (corrected 2026-10-27: this sentence said far more than one seal, 3 to 9 when this section was written, which the anchors before 2026-08-14 do not fit). The seal-count floor also bounds how much of history a leaked validator post-quantum key can rewrite for this follower (note of 2026-10-07 below; corrected 2026-10-26: this sentence called it a proposer-liveness property and not a history-verification property, which that note contradicts); a validator, which starts into the full set, does not set the ceiling (source:
|
||||
`RUN-A-NODE.md`). An implementation that instead makes its threshold guard aware of the validator
|
||||
set it will have at the evaluated HEIGHT (rather than at startup) can enforce the full schedule
|
||||
end to end; the published Besu-based package does not do this today [NOT MEASURED: no such
|
||||
|
||||
@ -16,13 +16,15 @@ should not be confused:
|
||||
1. **The binding.** From block 13,014,000 the block hash of every anchored header (every 32nd
|
||||
block; every 128th from block 17,225,968 to block 20,746,736) commits to a Falcon-512 certificate signed by the validators. That is a binding, not a
|
||||
replacement: a rewrite of anchored history must also forge the post-quantum signatures.
|
||||
2. **The enforced minimum.** Since 2026-08-14 a node does not finalize an anchor block unless
|
||||
2. **The enforced minimum.** Since 2026-08-14 a validator does not finalize an anchor block unless
|
||||
its certificate holds at least three valid Falcon-512 seals (f+1 of nine, the guarantee that at
|
||||
least one honest validator signed; eight or nine are carried in practice). Raised at block
|
||||
14,961,456 (August 21, 2026): the enforced minimum became **six**, which at that time was as many as the 2f+1 quorum of the nine-validator set, the same count QBFT itself required to agree on the block.
|
||||
least one honest validator signed; eight or nine are carried in practice). A node started from the
|
||||
published package (`run-node.sh`) lowers that count to one seal, at the cost stated in `SPEC.md`
|
||||
section 6.4 (corrected 2026-10-27: this item said "a node"). Raised at block
|
||||
14,961,456 (August 21, 2026): the enforced minimum became **six**, which at that time was as many as the QBFT quorum of the nine-validator set, the same count QBFT itself required to agree on the block.
|
||||
From 2026-09-11 the set was ten and QBFT's quorum seven, so the same six was above f+1 and
|
||||
below the quorum: the threshold had not moved, the set had. **From block 20,715,632 (AIP-22 stage 1,
|
||||
armed 2026-09-29) the enforced minimum is seven, again as many as the 2f+1 quorum of the ten-validator set.** Below block 24,148,752 the seals proved those validators signed the block, not that it was decided (AIP-22 erratum, 2026-10-01), and from that block a certificate that carries the quorum of one round proves the decision.
|
||||
armed 2026-09-29) the enforced minimum is seven, as many as the quorum of the ten-validator set, which at ten is also 2f+1.** (Corrected 2026-10-27: this item called six the 2f+1 quorum of the nine-validator set; at nine f is 2 and 2f+1 is five, while the QBFT quorum, ceil(2N/3), is six. The two coincide only at N = 3f+1, as at ten.) Below block 24,148,752 the seals proved those validators signed the block, not that it was decided (AIP-22 erratum, 2026-10-01), and from that block a certificate that carries the quorum of one round proves the decision.
|
||||
The schedule is `aere.pq.anchorMinSeals=13014000:0,13034000:3,14961456:6,17102384:0,17102416:6,20715632:7`,
|
||||
uniform on all ten validators; the
|
||||
startup guard refuses any threshold above N - f = 7, the highest count reachable with the fault
|
||||
@ -313,7 +315,7 @@ sentence. Someone else has to do the verifying, which is why it is here.
|
||||
**A certificate at an anchor height is signed by at least seven validators since block 20,715,632
|
||||
(2026-09-29), and was signed by at least six from block 14,961,456 (August 21, 2026). It was f+1
|
||||
before that, and this paragraph said so. Between that date and
|
||||
2026-09-11 six WAS the 2f+1 quorum of a nine-validator set; from 2026-09-11 until block 20,715,632,
|
||||
2026-09-11 six WAS the QBFT quorum of a nine-validator set; from 2026-09-11 until block 20,715,632,
|
||||
with ten validators, the quorum was seven and six was not one, so we did not call it a quorum. From
|
||||
block 20,715,632 (AIP-22 stage 1, armed 2026-09-29) the minimum is seven, the 2f+1 quorum of ten, and there it
|
||||
is a quorum again.** The distinction
|
||||
|
||||
37
run-node.sh
37
run-node.sh
@ -194,8 +194,8 @@ for p in "${PATCHES[@]}"; do apply_patch "$p"; done
|
||||
# --- 5. build ----------------------------------------------------------------------------------
|
||||
say "5/6 Building the node (gradlew installDist)"
|
||||
BESU_BIN="$BUILD_DIR/build/install/besu/bin/besu"
|
||||
# A binary built from an older patch set must not be reused: a node built from 0001-0007 stops at block 20,836,227
|
||||
# (AIP-22 stage 3). The patch set is fingerprinted and a change forces a rebuild.
|
||||
# A binary built from an older patch set must not be reused: a node built from 0001-0007 follows the chain up to block
|
||||
# 20,836,227 and refuses block 20,836,228 (AIP-22 stage 3). The patch set is fingerprinted and a change forces a rebuild.
|
||||
PATCHSET="$(for p in "${PATCHES[@]}"; do printf '%s %s\n' "$(sha256_of "$SCRIPT_DIR/patches/$p")" "$p"; done)"
|
||||
BUILT_FROM="$(cat "$BUILD_DIR/.aere-patchset" 2>/dev/null || true)"
|
||||
if [ -x "$BESU_BIN" ] && [ "$REBUILD" -eq 0 ] && [ "$BUILT_FROM" = "$PATCHSET" ]; then
|
||||
@ -249,18 +249,27 @@ mkdir -p "$DATA_PATH"
|
||||
# - anchor validation: aere.pq.anchorBlock / anchorInterval / anchorMinSeals / anchor.maxSeals / chainId.
|
||||
# - the 1 Gwei base-fee floor active from block 10,141,734: aere.basefee.floor.forkBlock / value.
|
||||
# A node syncing from block 0 starts into the GENESIS validator set, which is small (N=3). The
|
||||
# startup threshold guard (PqAnchorThresholdGuard) refuses to arm a seal threshold at or above that
|
||||
# set's QBFT quorum, because a proposer at that set size could never gather it; the schedule reaches
|
||||
# K=3 (block 13,034,000) and K=6 (block 14,961,456), both unreachable at N=3, so a from-genesis node
|
||||
# refuses to start (AERE-PQC-THRESHOLD-01) without the line below. The emergency ceiling lowers the
|
||||
# EFFECTIVE threshold to what the genesis set supports (quorum(3) - 1 = 1) WITHOUT editing the
|
||||
# published schedule, exactly as that guard's own message instructs (--Xaere-pq-anchor-min-seals-max).
|
||||
# This does not weaken the post-quantum binding a follower checks: every anchor must still carry a
|
||||
# valid validator Falcon seal that verifies against the registry, and its digest must still bind the
|
||||
# certificate under the block hash; only the seal-COUNT floor (a proposer-liveness property relative
|
||||
# to the current set, not a history-verification property) is relaxed to one. Real anchor blocks
|
||||
# carry far more than one seal (measured 2026-09-12 on the live chain: 14 to 20 in total, seven to ten
|
||||
# per half since the certificate became hybrid), so all import cleanly. With the ceiling set the node
|
||||
# startup threshold guard (PqAnchorThresholdGuard) refuses an effective seal threshold above N - f of
|
||||
# that set (AERE-PQC-THRESHOLD-01; 3 at N=3) and, from the AIP-22 stage R height, one above its QBFT
|
||||
# quorum (AERE-PQC-THRESHOLD-02; 2 at N=3); a threshold at or above the quorum below that height only
|
||||
# gets a WARN. The schedule reaches K=6 (block 14,961,456) and K=7 (block 20,715,632), above both
|
||||
# bounds at N=3, so a from-genesis node refuses to start without the line below. The emergency ceiling
|
||||
# lowers the EFFECTIVE threshold to 1, a value below both bounds, WITHOUT editing the published
|
||||
# schedule, exactly as that guard's own message instructs (--Xaere-pq-anchor-min-seals-max).
|
||||
# It weakens one check of this follower (SPEC.md section 6.4): against an adversary holding every
|
||||
# classical validator key and no post-quantum key the follower kept the rewrite bound of a validator
|
||||
# below block 24,148,752, and from that block (AIP-22 stage R) its bound is 33 blocks where a
|
||||
# validator's is 32; but ONE leaked or misused validator post-quantum key makes this follower's
|
||||
# rewrite depth unbounded, where a validator at K=7 needs seven such keys. What is not weakened: every
|
||||
# anchor must still carry a valid validator Falcon seal that verifies against the registry, and its
|
||||
# digest must still bind the certificate under the block hash. Real anchor blocks carry at least one
|
||||
# valid seal (one or two on anchors from block 13,014,000 until the emergency ceiling was lifted on
|
||||
# 2026-08-14, three or more after that, at least seven per scheme since block 20,715,632), so all of
|
||||
# history imports at this floor of one. (Corrected 2026-10-27: until this date this comment said the
|
||||
# guard refuses a threshold at or above the quorum, gave 1 as quorum(3) - 1, said the ceiling does not
|
||||
# weaken what a follower checks and that real anchor blocks carry far more than one seal; RUN-A-NODE.md
|
||||
# and SPEC.md were corrected on 2026-10-26.) An empty AERE_ANCHOR_MIN_SEALS_CEILING keeps the default
|
||||
# of 1 below. With the ceiling set the node
|
||||
# shouts one ERROR per imported block by design (AERE-PQC-EMG-CEILING-01; one per anchor before patch 0008, measured
|
||||
# 2026-10-01); RUN-A-NODE.md says what that is, how to run without it once synced, and
|
||||
# what a real refusal looks like instead. A validator, which starts into the full set and
|
||||
|
||||
@ -14,9 +14,10 @@
|
||||
// (0x0AE6 ML-KEM-768, 0x0AE7 Falcon HashToPoint) is confirmed NOT live on
|
||||
// mainnet, which is itself a published claim that should be falsifiable.
|
||||
//
|
||||
// Ground truth this script does NOT assert: consensus on chain 2800 is
|
||||
// classical secp256k1 ECDSA QBFT. These precompiles are an application and
|
||||
// account layer capability only.
|
||||
// Ground truth this script does NOT assert: anything about consensus on chain
|
||||
// 2800 (when this script was written it was classical secp256k1 ECDSA QBFT;
|
||||
// for the chain of today see SPEC.md; this comment dated on 2026-10-27).
|
||||
// These precompiles are an application and account layer capability only.
|
||||
// ---------------------------------------------------------------------------
|
||||
import { readFileSync } from "node:fs";
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user