igneum/docs/design/genesis-forward.md
igneum-josh 9e256a4bc0 Genesis forward-compatibility (mission item 8): design doc, spec text (W1 scheme byte, W5 succession, the cache rung, the VDF fallback flagged), ledger rows GF1 to GF4, the fast-time harness, override-60x.json
docs/design/genesis-forward.md names the three fields, their defaults, the digest change and the gates; spec 03 W1 and W5
amended and the W5 implementation row filled; spec 01 the cache rung beside the schedule; spec 04 the class-group VDF's
quantum fallback flagged, not sized; infra/fast-time/key-succession.mjs (3 nodes, one CPU miner each: the window fills,
a succession carried once on every node, refused twice, scheme 1 refused by every node; the known-failed case
--expect no-succession first); override-60x.json carries the four new keys at never.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 11:03:37 +01:00

10 KiB

Genesis forward-compatibility: the scheme byte, key succession, the cache rung

7 October 2026, 10:1x UK, Josh's order to build mission item 8 now (docs/analysis/mission/mission.md section 2.8; the research in docs/analysis/mission/future.md sections 1.3, 7 and 10 and docs/design/finality-in-proof.md section 7). Branch genesis-forward on the node fork (from release-0.3.19-node dc141409, the merged line that carries the ladder and the W7 leave item, which ca3-v4-0318 alone does not) and genesis-forward on the repo. Three genesis fields, every switch never on the devnet (its digest does not move), all three set at the testnet genesis by the testnet lane, which holds the cut and re-pins. The class-group VDF's quantum fallback is flagged in spec 04 section 4.8, not built.

1. The scheme byte

Item Place Value
The byte finality::Vote::sig_scheme, finality::KeyReveal::sig_scheme, finality::Succession::successor_scheme SIG_SCHEME_BLS12_381 = 0 everywhere today
The genesis value Params::sig_scheme (override key sig_scheme) 0 on every network
The switch Params::sig_scheme_activation_daa (override key sig_scheme_activation_daa; u64::MAX = never) never on devnet, simnet, mainnet; 0 at the testnet genesis
The digest both fields enter once the switch is set (the 0.3.15 rule) the devnet's digest unchanged; the testnet's moves at the cut
The wire, plain vote item tag 1 (Vote::LEN = 280 bytes), evidence tag 3, reveal IGNK + 288 hex: scheme 0 implied byte for byte what every live network carries
The wire, explicit vote item tag 5 = scheme || vote, evidence tag 6 = scheme || first || second, reveal IGNS + 2 hex of the scheme + 288 hex written by every template once the switch is active (encode_section_explicit_within); a vote of any other scheme is always explicit, so a scheme the node does not run is never mistaken for one it does
The active scheme igneum::active_sig_scheme(genesis, class) = the scheme the program class at the sink names (SIG_SCHEME_OF_CLASS, a genesis table with no row today), else the genesis byte; the finality manager re-reads it at every virtual change 0
The refusal FinalityManager::scheme_refusal: a reveal is not registered, a vote is not recorded, carried or gossiped, a successor is refused; the RPC answers refused: vote carries signature scheme 1; the active scheme is 0 (BLS12-381); another scheme is named only by a program class the 95 percent signal moves to, and none names one every node, whatever its switch

Why a class change names the scheme: the flip is the P2 mechanism (95 percent of mining weight over a window with a floor height, the one path a consensus change takes on this chain), and the aggregated-vote format must ship first (naive ML-DSA-44 votes at 8,192 voters cost 19.4 MB a checkpoint and 57 GB a day, future.md 7.3; with 250x SNARK aggregation about 223 MB a day). Adding a row to the table is a code change under the class path; the byte is in every item from genesis so the row costs no fork.

2. Key succession, W5

Item Place Value
The item finality::Succession (tag 7, 297 bytes): daa, old key, successor key, successor scheme, the old key's signature, the successor's signature, both over "igneum-succeed-v1/" || chain_id || 0 || daa || old || new || scheme under IGNEUM_SUCCEED_V1_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_ the successor's signature is its consent and its proof of possession in one
The switch Params::finality_succession_activation_daa (override key of the same name) never everywhere; 0 at the testnet genesis; in the digest once set
Submission submitFinalitySuccession (RPC op 158, gRPC 1131/1132, wRPC, igneum-miner succeed <grpc url> <old label> <new label>) carried after the leaves in the templates of the node that holds it; no p2p gossip kind (the successor's own node mines it)
The fold successions_at (deterministic like leaves_at: the lowest-DAA carrier in C's past dates it) and fold_successions inside voters_at: the old key's window blocks are credited to the successor as they stand (count and oldest block), the old key leaves the table, a ban or a leave on the old key lands on the successor; the successor's presence counts the old key's carried votes from the first checkpoint whose past holds the carrier; the window inherited, not a fresh one
Once one record per old key: a second succession from a key that handed over is refused (already handed its weight to), a successor that has itself handed over is refused (has itself handed), which also refuses every cycle; a chain old to new to newer is legal a record outlives the weight it moved by one window, then is trimmed
After the old key's votes are refused (handed its weight to), never counted, never carried the old key is dead
The report getFinalityWeights: succeededFrom on the successor's row, a weightless row for the old key with succeededTo both nodes of the unit test agree on every voter list

Not in this round: a p2p gossip kind for successions (the leave's shape, protocol version bump); the app's "rotate key" button, which signs the item from the old key's label and restarts the miner under the new label (the succeed subcommand is the primitive); the aggregated-vote format.

3. The cache rung beside N

Item Place Value
The rung igneum::CacheRung { mib, admissible } as LatencyLadder::cache_rung (override key latency_ladder_cache_rung) {512, false} at genesis; a power of two above the 256 MiB genesis cache
The signal LadderSignal::Cache = both ladder bits set (header version 0xc000; until today both set was "no signal" and no node ever stamped it, so no block written so far changes meaning); IGNEUM_LADDER_SIGNAL=cache code 3 in PowEpochInfo::latency_ladder_signal
The rule latency_ladder_step_signalled_with_cache: the cache step moves 0 to 1 when every one of the newest seven windows reaches 90 percent for the cache rung, the rung is admissible and the cool-down holds (the oldest window begins after the last decision, shared with N); never back; never in the same decision as N (one signal per block, exclusive shares) LadderState::cache_step
The digest the rung's size and flag enter with the ladder, once latency_ladder_activation_daa is set the testnet's digest moves at the cut
The RPC powEpoch.latencyLadderCacheStep, nextLatencyLadderCacheStep, latencyLadderCacheMib, nextLatencyLadderCacheMib, latencyLadderCacheBps, latencyLadderCacheWeakestBps, latencyLadderCacheAdmissible (proto fields 37 to 43); the daemon's ladder line (cache [512 MiB]) the rung visible on every node
The gate admissible in the genesis list, false until measured: the cold verify of one warp with the 512 MiB cache on the reference core with its SMT sibling loaded under 10 ms (the verifier reads the cache, so this is the bound), the day-cache build on a 2019-class core under twice today's, and the 8 GB tier still holding dataset, cache and the prover footprint the rule never enters an inadmissible rung (tested)

Why beside N and not a seventh N rung: the six approved rungs and their indices stand (Josh, 7 October 2026, 09:3x UK); a rung inserted in the list would either sit behind the three inadmissible rungs (unreachable) or shift the approved indices. A second lever on the same signal carrier keeps the list as approved and the cool-down shared.

Owed with the measurement: the engine's consumption of cache_mib (EpochSeeds carries shadow_reps today and no cache size; the pack and the three hosts build a 256 MiB cache), so the flag stays false until the path exists and is measured. Per tier what the rung means: every tier from 8 GB holds a 512 MiB cache; the day-cache build doubles (about 0.7 s on the reference core today, approximate, from the class v4 fill line); the Apple tier's unified memory holds it; a pool user does nothing.

4. The class-group VDF under a quantum computer

Flagged in spec 04 section 4.8, not sized: Shor computes the class-group order, which removes the sequentiality assumption of the Wesolowski VDF, so an attacker with a cryptographically relevant quantum computer grinds the hourly seed (a liveness nuisance against the lottery, not a safety break; finality rests on the vote keys of section 1). The fallback is a hash-chain delay behind the same version byte, designed when the scheme flip is scheduled.

5. Gates

Gate Where Result
The digest test consensus_digest_covers_every_consensus_field_and_nothing_else (30 edits; the scheme byte and the cache rung alone move nothing), override_params_carry_the_genesis_forward_fields_and_the_digest_moves_only_when_set section 6
Scheme 1 refused by every node until the signal unit: a_vote_reveal_or_successor_of_another_signature_scheme_is_refused_until_a_class_names_it (RPC, in a block, a reveal, a successor; the explicit template form); fast-time: probe-scheme on three nodes section 6
A succession carried once and refused twice unit: a_key_hands_its_window_to_a_successor_once_and_a_second_succession_is_refused (two nodes); fast-time: infra/fast-time/key-succession.mjs (the known-failed case --expect no-succession first) section 6
The ladder rung visible in the RPC powEpoch.latencyLadderCache* on getBlockTemplate, the daemon line; unit: latency_ladder_rule (an inadmissible cache rung never entered; with the flag, 90 percent in seven windows enters it, N still steps after it, one rung, never back) section 6
The codec scheme_byte_and_succession_items_round_trip_and_an_older_decoder_stops_at_them section 6

6. Results

Filled in when the box runs are green (build and test lines, the harness summaries copied to docs/design/genesis-forward-harness/).

7. For the testnet lane

Override keys and testnet values: sig_scheme: 0, sig_scheme_activation_daa: 0, finality_succession_activation_daa: 0, latency_ladder_cache_rung: {"mib": 512, "admissible": false} (the six N rungs unchanged). Digest: with the ladder already active from genesis the cache rung's two fields enter after the six rungs' fields; the scheme switch adds two fields, the succession switch one. print_testnet_object prints the four keys.