AIP-22 stage R and stage 4 on chain 2800, dated corrections (2026-10-26): README patch rows 0009 and 0010 now say the heights were crossed (24,148,752 on 2026-10-24, 24,300,000 on 2026-10-25); RUN-A-NODE: the seal-threshold ceiling of the published follower weakens what it checks (SPEC 6.4), the startup guard refuses above the quorum and only warns below it, the v2 certificate dated 2026-09-04; SPEC 3.7 and 6.4 the same
This commit is contained in:
parent
c3e0bd3858
commit
a537b7c9d1
@ -101,8 +101,8 @@ Both patches target upstream commit `d2032017bb3b8cb215a97303980a1e4a643f7180`,
|
||||
| `patches/0006-aere-pq-transactions.patch` | AIP-20, transaction type `0x50` authorized by ML-DSA | the tree after 0005 |
|
||||
| `patches/0007-aere-pq-finality.patch` | AIP-21, `aere_getPqFinality` and the on-disk seal window | the tree after 0006 |
|
||||
| `patches/0008-aere-pq-aip22.patch` | AIP-22 stages 1 to 3 (post-quantum validator ids from block 20,836,228) and the rest of the fleet distribution of 2026-09-29 | the tree after 0007 |
|
||||
| `patches/0009-aere-pq-seal-judge-snap-cap.patch` | the fleet distribution of 2026-10-02: the heard-seal judge and the pending-commit buffer (both act only from the AIP-22 stage 4 height, block 24,300,000 on chain 2800, announced on 2026-10-22), the snap-request cap | the tree after 0008 |
|
||||
| `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 until the height `aere.pq.commitRoundBlock` is set (not set on chain 2800 at 2026-10-14, block 24,148,752 there since the announcement of 2026-10-22; 6,157,024 on testnet 28001 since 2026-10-14) | the tree after 0009 |
|
||||
| `patches/0009-aere-pq-seal-judge-snap-cap.patch` | the fleet distribution of 2026-10-02: the heard-seal judge and the pending-commit buffer (both act from the AIP-22 stage 4 height, block 24,300,000 on chain 2800, in force since 2026-10-25; announced on 2026-10-22), the snap-request cap | the tree after 0008 |
|
||||
| `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
|
||||
@ -111,7 +111,7 @@ the chain today; it keeps the recipe equal to what the fleet runs, see `RUN-A-NO
|
||||
`run-node.sh` does not set; when the founder sets that height, a node without 0010 stops at the block
|
||||
before it, see `RUN-A-NODE.md`, "Patch 0010". Note added 2026-10-22: that height is block 24,148,752 on
|
||||
chain 2800, carried by `run-node.sh` since 2026-10-21; a node built without 0010 stops at block
|
||||
24,148,751, derived from the code.)
|
||||
24,148,751, derived from the code.) (Note added 2026-10-26: block 24,148,752 was reached on 2026-10-24 and block 24,300,000, the AIP-22 stage 4 height, on 2026-10-25, so both stages are in force on chain 2800, and a node that follows it today is built from 0001 and 0003 to 0010, which is what `run-node.sh` builds.)
|
||||
|
||||
Patch 0003 is a different kind of thing from the first two and is described in `anchor/README.md`.
|
||||
It changes twenty upstream files and adds fifty-five, and it changes one build file by one line.
|
||||
|
||||
@ -144,8 +144,7 @@ Since block 13,014,000 every 32nd header of chain 2800 (every 128th from block 1
|
||||
seals, universal since block 13,889,296, enforced at a minimum of three seals per anchor block (f+1
|
||||
of nine) from 2026-08-14, of six from block 14,961,456 and of seven, as many as the quorum of the ten validators (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), from block 20,715,632, for each scheme once the certificate became hybrid (Falcon-512
|
||||
and SLH-DSA-SHA2-128s) at block 17,047,600; since block 20,746,736 SLH-DSA seals are required at
|
||||
every 128th block only. A node rejects an anchor block whose
|
||||
certificate holds fewer valid seals than the schedule requires at its height. (Correction 2026-08-19:
|
||||
every 128th block only. A validator rejects an anchor block whose certificate holds fewer valid seals than the schedule requires at its height; a node started with the follower configuration below lowers that count to one seal, at the cost stated in "Why the seal-threshold ceiling" (corrected 2026-10-26: this sentence said "A node rejects", which the published follower does not). (Correction 2026-08-19:
|
||||
an earlier version of this paragraph said that from block 14,050,000 the network refuses to finalize
|
||||
any block without a post-quantum quorum; the per-block rule armed at that height is retired in the
|
||||
shipped code in favour of the anchor rules and changed no enforcement, so that sentence is withdrawn.)
|
||||
@ -153,10 +152,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`, `0003`, `0004`, `0005`, `0006` and `0007` together and treat a build missing any of them as
|
||||
unable to follow the current chain (from 2026-09-22 the last two are part of the recipe; see the
|
||||
section 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` stops at block 20,836,227 and one without `0010` at block 24,148,751; see the sections on them below).
|
||||
|
||||
## Patch 0005 exists because the import proof was actually attempted
|
||||
|
||||
@ -272,9 +268,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 still follows the chain**: neither change
|
||||
alters what a node accepts below the AIP-22 stage 4 height (`aere.pq.finalityBlock`), which is
|
||||
set on chain 2800 from block 24,300,000 (armed 2026-10-21); `run-node.sh` sets it from that date; 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 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
|
||||
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
|
||||
@ -450,21 +444,9 @@ export BESU_OPTS="\
|
||||
### Why the seal-threshold ceiling, for a from-genesis node
|
||||
|
||||
A node syncing from block 0 starts into the GENESIS validator set, which is small (three
|
||||
validators). 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
|
||||
published schedule reaches K=3 (block 13,034,000), K=6 (block 14,961,456) and K=7 (block
|
||||
20,715,632), all unreachable at N=3, so without `aere.pq.anchor.minSealsCeiling` a from-genesis node refuses to start with
|
||||
`AERE-PQC-THRESHOLD-01`. The 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`). It 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, which is a proposer-liveness property relative to the current set and not a
|
||||
history-verification property, is relaxed to one. 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-03. A validator, which starts into the full set and proposes,
|
||||
does not set this.
|
||||
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).
|
||||
|
||||
**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
|
||||
@ -479,15 +461,10 @@ WITH A LOWERED SEAL THRESHOLD. The schedule in force asks for K=...
|
||||
|
||||
That is the binary doing what we asked it to do: a safety control that has been lowered must be
|
||||
impossible to forget, so it shouts on every use rather than once at startup. On a from-genesis sync
|
||||
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.
|
||||
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. If you
|
||||
prefer a quiet log once you are past the early heights, restart the node without
|
||||
`aere.pq.anchor.minSealsCeiling` after it is synced beyond block 13,034,000: by then the live
|
||||
validator set is large enough for the scheduled threshold to arm, and the shouting stops because the
|
||||
control is no longer lowered.
|
||||
`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.)
|
||||
|
||||
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
|
||||
|
||||
18
SPEC.md
18
SPEC.md
@ -610,8 +610,7 @@ machine-checked: the z3 model above is of the round-free regime and has not been
|
||||
round-bound premise). The bound above is one number for a validator and for the published follower
|
||||
because, below `H_r`, one honest seal of the undecided sibling is all the exception needs and both
|
||||
accept certificates below the quorum of one round. From `H_r` the two part ways. A validator refuses
|
||||
an anchor whose v3 certificate holds fewer than `K_eff` Falcon seals of ONE round, and from `H_r` the
|
||||
startup guard requires `K_eff` = the quorum of the set (`AERE-PQC-THRESHOLD-02`; 7 at N=10); seven
|
||||
an anchor whose v3 certificate holds fewer than `K_eff` Falcon seals of ONE round, and from `H_r` the validators run `K_eff` = the quorum of the set (7 at N=10), the most the startup guard allows there (it refuses above the quorum, `AERE-PQC-THRESHOLD-02`, and only warns below it, `AERE-PQC-ROUND-05`; corrected 2026-10-26: this clause said that the guard requires `K_eff` = the quorum); seven
|
||||
seals of one round over an undecided sibling cannot exist (a round that decides has the quorum, and
|
||||
a quorum of the same round on another block would contradict QBFT safety), so for a validator the
|
||||
exception closes and the bound is **32** (the latest anchor and the 31 after it). The published
|
||||
@ -979,9 +978,7 @@ file refuses rather than hashes (source: `PqRegistryHash.java`, `Registry` javad
|
||||
Stated because a third-party implementation that produces blocks needs them, and a follower needs
|
||||
to know they exist:
|
||||
|
||||
- `PqAnchorThresholdGuard`: refuses to arm a seal threshold at or above the QBFT quorum of the
|
||||
CURRENT validator set (a proposer could never gather it), and refuses any threshold above
|
||||
N - f (7 at N=9, 7 at N=10) (source: `anchor/consensus/common/.../PqAnchorThresholdGuard.java`;
|
||||
- `PqAnchorThresholdGuard`: refuses any effective seal threshold above N - f of the validator set it starts into (7 at N=9, 7 at N=10; inside the fault model no more seals can exist) and starts with a loud WARN when the threshold is at or above the QBFT quorum; from `H_r` it also refuses an effective threshold above the quorum (`AERE-PQC-THRESHOLD-02`; a certificate then holds the seals of one round) and warns below it (`AERE-PQC-ROUND-05`) (corrected 2026-10-26: until this date the first clause said the guard refuses a threshold at or above the quorum of the current set, the guard of 2026-08-02, which the code retired on 2026-08-20) (source: `anchor/consensus/common/.../PqAnchorThresholdGuard.java`;
|
||||
`anchor/README.md`; `RUN-A-NODE.md`, "Why the seal-threshold ceiling"). The refusal code is
|
||||
`AERE-PQC-THRESHOLD-01`, and it is the reason a from-genesis follower needs the ceiling
|
||||
(section 6.4).
|
||||
@ -1169,21 +1166,14 @@ their liveness at any moment is only provable by your own `net_peerCount` (sourc
|
||||
|
||||
### 6.4 The genesis-set threshold problem, and the published answer
|
||||
|
||||
A node syncing from block 0 starts INTO the genesis validator set (N=3, quorum 2). The anchor
|
||||
threshold guard (section 3.7) refuses to arm K=3, K=6 or K=7 against that set, so a from-genesis
|
||||
follower with the published schedule cannot start at all without one more setting. The published
|
||||
answer is `aere.pq.anchor.minSealsCeiling=1`, which lowers the EFFECTIVE seal-count floor to
|
||||
`quorum(3) - 1 = 1` WITHOUT editing the schedule (source: `RUN-A-NODE.md`, "Why the seal-threshold
|
||||
ceiling").
|
||||
A node syncing from block 0 starts INTO the genesis validator set (N=3, quorum 2). The anchor threshold guard (section 3.7) refuses an effective threshold above N - f = 3 against that set and, from `H_r`, one above its quorum, 2, so it refuses K=6 and K=7, and a from-genesis follower with the published schedule cannot start at all without one more setting. The published answer is `aere.pq.anchor.minSealsCeiling=1`, which lowers the EFFECTIVE seal-count floor to 1 WITHOUT editing the schedule (source: `RUN-A-NODE.md`, "Why the seal-threshold ceiling"). (Corrected 2026-10-26: until this date this paragraph said the guard refuses K=3, K=6 or K=7 against that set and gave the floor as `quorum(3) - 1 = 1`; since 2026-08-20 the guard refuses only above N - f, so K=3 starts there with a WARN, and the value 1 is a choice below both bounds, not the quorum minus one.)
|
||||
|
||||
State the consequence honestly, because it is a real weakening of one check on the follower: with
|
||||
the ceiling at 1, the follower's seal-COUNT requirement is 1 at every height, not 3 or 6. What is
|
||||
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 3 to 9 seals, so all of history imports cleanly. The seal-count
|
||||
floor is a proposer-liveness property relative to the current set, not a history-verification
|
||||
property; a validator, which starts into the full set, does not set the ceiling (source:
|
||||
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:
|
||||
`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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user