From b7497bc9a5936a4791aaf4e7b0b6d99c89b4d4b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Wed, 2 Sep 2026 19:06:44 -0300 Subject: [PATCH 01/49] feat(types): Beacon Chain containers under a `beacon` namespace (#1) * build(deps): track libssz from git, and add ethereum-types and sha2 The Beacon Chain containers landing in the next commit hand out `&mut` into an `SszList` (the validator registry, through `altair_validator_lists_mut`), which published libssz-types 0.3.0 cannot do: it exposes only `Deref` and `Index`. `DerefMut` and `IndexMut` landed after that release, in lambdaclass/libssz#33. A git dependency rather than a `[patch.crates-io]` override: nothing outside this workspace depends on libssz, so there are no two copies to unify, which is the job a patch table would be doing. Pointing the four dependencies at the repository says the same thing with less machinery, and avoids committing a `[patch]` table that `shadow/cargo-patch.toml` would then collide with, since that fragment is appended verbatim to this manifest and declares one itself. All four move together because libssz-types depends on libssz and libssz-merkle by path inside that repository, so a mixed set would put two incompatible copies of libssz in the graph. `Cargo.lock` pins the exact commit, so tracking a branch does not make the build drift on its own; it moves when someone runs `cargo update`. Return these to a crates.io version once a release carrying #33 exists. `ethereum-types` and `sha2` join the workspace dependencies for the same incoming containers. `sha2`'s `asm` feature selects the CPU's SHA-256 instructions, which merkleizing a beacon state feels directly, since a state's `hash_tree_root` is almost entirely SHA-256 compressions. * feat(types): add the Beacon Chain containers under a beacon namespace The Beacon Chain is a different protocol from the Lean consensus this repository implements, but the two need to meet at one state type: a single BlockChainServer should be able to dispatch on the state variant rather than existing twice. That means the containers cannot live in a crate that also carries the state transition, because everything reaching for a container would then also pull in blst and c-kzg. They live here instead. Seven forks, phase0 through fulu. Containers that change between forks are defined once per fork as plain structs deriving their SSZ encoding and merkleization, wrapped in an enum. Deriving is the reason for that shape: the per-fork field lists are not a growing tail. Two of phase0's fields are *replaced* in altair, one field changes type in five separate forks, and the state's merkle tree gains a level at electra, so a single container with fork-conditional serialization would have to reproduce all of that by hand. The preset is a compile-time choice, `preset-minimal` against an implicit mainnet default, because SSZ list and vector bounds are const-generic arguments and cannot be selected at run time. Fork *scheduling* is runtime configuration in `config` instead, since fork epochs move per case in the upstream test suites. `constants` holds what the spec fixes outright, `primitives` the scalar aliases and fixed-length byte strings, `error` what the containers return, and `fork` the `ForkName` ordering that later gating reads. This is a port of code verified against the consensus-specs v1.6.1 fixture suites, where it passes 5705 mainnet and 40009 minimal cases across both presets. Those suites exercise the state transition that consumes these containers and are not part of this crate, so what runs here is the containers' own round-trip and shape tests. * feat(types): give ForkName and BeaconState a Lean variant This is the point of moving the containers here. One BlockChainServer should dispatch on the state variant rather than existing once per chain, and that needs a single state type spanning both. `BeaconState::Lean` holds lean's `State`, which gains `PartialEq` because `BeaconState` derives it. `ForkName::Lean` is declared last, so the derived `Ord` puts it after every beacon fork. That is what `fork >= ForkName::X` gating reads, so such a gate reads as true for a lean state rather than accidentally selecting phase0 rules. It is deliberately absent from `ForkName::ALL`. `ALL` is what `parse`, `previous`, `next`, and the upstream fixture harness search, so its absence is what makes `parse("lean")` return `None`, keeps `Fulu.next()` at `None` so a fork upgrade cannot walk off the end into lean, and stops a fixture directory from ever resolving to a lean case. Lean is not a point on the Beacon Chain's fork timeline and must not be reachable by traversing it. Only `fork_name()` and `from_ssz()` are real arms. Every other exhaustive match on `BeaconState` answers `unreachable!()` naming itself, and the accessors on `ForkName` do the same, except those already returning `Result`, which answer `UnsupportedForFork`. That asymmetry is the design, not an oversight. The guarantee that a lean state never reaches a beacon accessor is the single `match` at the top of each handler, not the type system, so the failure mode when that guarantee is broken should be a named panic pointing at the function that was reached, rather than a silent wrong answer computed from a state of the wrong shape. * feat(types): add what the storage and networking layers need Four additions, each pulled here by a crate that must not depend on a Beacon Chain state transition. `fork_digest` computes `compute_fork_data_root` from the fork schedule. Gossip topic names and the eth2 ENR entry both need it, and both belong to the networking layer, which cannot reach for a crate carrying blst and c-kzg just to name a topic. The fulu branch is EIP-7892's: a blob-parameter-only fork perturbs the digest, so mainnet's is 8c9f62fe rather than fulu's bare 82fae541. `fork_choice` holds `LatestMessage` and `PowBlock`. Both are data a fork choice store holds rather than behavior it runs, and the storage layer cannot depend on the consensus layer because the dependency runs the other way. `ForkName` gains a stable one-byte storage selector. A stored state has to record which fork's shape it has, and the derived discriminant is not a stable encoding: it shifts whenever a variant is added, which silently reinterprets every state already on disk. An explicit byte survives that. Lean's `primitives` gains conversions between the beacon `Root` and lean's `H256`. Same 32 bytes in two types, and the boundary is crossed by every store lookup on the beacon path, so the conversion belongs here rather than open-coded at each call site. * docs(types): resolve the beacon namespace's doc links Ten rustdoc warnings, inherited from the source these containers were ported from rather than introduced here, but there is no reason to carry them onto main. Four kinds: - `shared_state_accessors` is a `macro_rules!` with no `#[macro_export]`, so rustdoc has no item to point at and the link never resolved. It becomes a plain code span, which is what it always meant. - `SYNC_COMMITTEE_SUBNET_COUNT` is a private const. altair.rs already refers to it as a plain code span thirteen lines further down, so this follows the convention the file had already settled on. - capella's three links spelled out a target identical to what the label already resolved to. - preset.rs's two sat in an outer doc comment on `pub mod retuned`, which resolves in the parent scope rather than inside the module, so they pointed at nothing. Qualifying them with `retuned::` makes them mean what they say. `cargo doc -p ethlambda-types --no-deps` is now warning-free. * docs: describe the beacon namespace in ethlambda-types Records what a reader needs before touching these types: that the Beacon Chain is a separate protocol sharing the crate only so one state type spans both, that ForkName::Lean sits outside ForkName::ALL on purpose, why the beacon accessors panic rather than error on the Lean variant, and that the preset is a compile-time feature every lean crate inherits. Also records where the verification lives, since it is not in this repo: the state transition that exercises these containers against the consensus-specs fixtures is on feat/beacon-chain-stf. * build(deps): pin the libssz crates by rev, not branch `branch = "main"` leaves a routine `cargo update` free to move the SSZ encoder and merkleizer that decides every `hash_tree_root`. The requirement is a commit carrying lambdaclass/libssz#33, not whatever `main` holds today, so pin the rev `Cargo.lock` already resolved to and make moving it an explicit edit. Also correct what sha2's `asm` feature actually buys: on x86/x86_64 the SHA-NI dispatch happens through `cpufeatures` with or without it, and `asm` only swaps that dispatch's fallback. aarch64 is where the feature is the whole hardware path. * refactor(types): dispatch the beacon fork ladders from one place Every beacon accessor spelled out its own seven-arm match plus a lean arm, so a new fork meant editing twenty ladders, and the boundary panic's wording had already drifted between them. Route the arms through `dispatch_state!`, `dispatch_state_from!` and `dispatch_block!`, and write the panic once as `lean_unreachable!`, in the two forms the two boundaries are crossed by. Also, from the same reviewing pass: - Make the fork matches in `preset::retuned` exhaustive, so a fork added later is a build error instead of falling silently into bellatrix's value. - Keep `get_blob_parameters` on `Config`, where `max_blobs_per_block` and `compute_fork_digest` both reach it; the digest hashes the pair's epoch as well as its limit, so the search cannot be written once per caller. - Convert both presets' `TERMINAL_TOTAL_DIFFICULTY` at compile time, with a test pinning the limbs against the decimal strings the config files carry. - Move the `Root` <-> `H256` conversion to the beacon side of the namespace: beacon is the half that knows about lean, so lean's `primitives` names nothing beacon. * ci: check the minimal preset The beacon containers' SSZ bounds are const-generic arguments, so the minimal preset is a whole second compilation of ethlambda-types that no other step reaches: everything else builds the default mainnet preset only. The fixture suites that select the feature live on another branch, so without this step it would rot between merges. * refactor(types): turn lean_unreachable! into two functions The macro's two arms were already two unrelated diagnostics: one for a beacon accessor handed lean's state, one for a beacon-only function handed ForkName::Lean. Nothing about either needed macro expansion, so they become lean_state_unreachable and lean_fork_unreachable. Both return `!` so they still type-check in every arm position the macro occupied: value arms, the Ok/Err arms of dispatch_state_from!, and the unit arm of Config::with_fork_epoch. #[track_caller] is what a plain function would otherwise have cost us, since without it every panic would report beacon/mod.rs instead of the arm that was actually reached. * refactor(types): replace byte_vector! with plain newtypes Four expansions did not earn a macro, and the $(#[$doc:meta])* passthrough it needed to carry each type's documentation was the least readable part of the module. Written out rather than made newtypes over a generic ByteVector, which would have deduplicated Default and AsRef but turned every construction site into BlsPubkey(ByteVector([9; 48])) and every field read into .0.0. Type aliases are not an option at all: BLS_PUBKEY_SIZE and KZG_POINT_SIZE are both 48, so aliasing would make BlsPubkey and KzgCommitment the same type and give up exactly the confusion the newtypes exist to catch. Default stays hand-written because the standard library implements it for arrays only up to length 32, so a derive has nothing to call for [u8; 48] or [u8; 96]. The Debug bodies share a debug_byte_vector helper so the four cannot drift into printing the same kind of value four ways. * test(types): drop a_state_equals_its_own_clone The assertion was that a derived PartialEq agrees with a derived Clone, which holds by construction and would not fail short of a compiler bug. It was the only test in partial_eq_tests, so the module goes with it. * ci: scope the minimal-preset check to --lib, so the lint job can pass The step runs in the `lint` job, which downloads no fixtures. `cargo test -p ethlambda-types --features preset-minimal` builds every test target of the crate, including `ssz_spectests`, whose datatest-stable harness walks `leanSpec/fixtures/consensus/ssz` and panics with "error reading directory" when that tree is absent. Only the `test` job fetches it, so the step exits 101 on every run, on pull requests and on main alike, without ever reaching the thing it exists to check. `--lib` runs the 102 unit tests instead, which read nothing from disk. Those are what the preset actually changes: it selects the const-generic bounds the beacon containers are declared with, so the whole point is that the crate compiles under it and its own assertions still hold. The fixture suite is preset-independent and already runs, at the default preset, in the `test` job. * feat(types): let BeaconState encode and merkleize its lean variant `BeaconState::from_ssz(ForkName::Lean, ..)` builds `BeaconState::Lean`, while `to_ssz` and `hash_tree_root` dispatched through `dispatch_state!` and so panicked on it. Decoding a state and re-encoding it therefore panicked: the enum accepted a value on the way in that it refused on the way out. Nothing reachable today hits it, since no production caller constructs the variant and `ForkName::parse` cannot return `Lean`. What makes it worth closing anyway is who the first caller will be. The variant exists so one `BlockChainServer` can dispatch on a single state type; that server will decode a state whose fork came from configuration, where `Lean` is a legal value, and re-encoding it to store it is the next thing it does. The other `Lean` arms panic because there is genuinely no beacon answer to give: asking a lean state for its `validators` or its `slot` has no meaning, and a named panic beats a wrong number. These two are not like that. Every variant is an SSZ container, so encoding and merkleizing mean the same thing whichever chain the state belongs to, and the answer was already sitting in the variant. `dispatch_state_including_lean!` is the arm list for exactly those cases, kept separate from `dispatch_state!` so that a beacon accessor cannot reach it by accident: it takes no `$function`, because it has no arm that panics. One subtlety worth naming, since it is what makes a single macro body typecheck for all eight arms. This crate has two `HashTreeRoot` traits, both blanket implemented over `libssz_merkle::HashTreeRoot`, differing only in the wrapper type around the digest. `containers/mod.rs` imports the beacon one alone, so lean's state answers it too, with the same bytes lean's own trait would produce. The new test asserts that equality rather than merely asserting the call does not panic, because a block's `state_root` is checked against this digest. It names lean's trait through its full path: importing it would make the call ambiguous. `SignedBeaconBlock` is left as it is. Its `from_ssz` returns `Error::UnsupportedForFork` for `Lean` and it has no `Lean` variant to encode, so it has no asymmetry to fix. * refactor(types): declare the H-types instead of depending on ethereum-types The beacon namespace pulled `H160`, `H256` and `U256` from `ethereum-types`, which meant the crate carried two 32-byte hashes: that one and lean's own `primitives::H256`. Every beacon block root reaching a store lookup had to be converted between them, and the two `HashTreeRoot` convenience traits over the two hashes were otherwise identical. `beacon::primitives::Root` is now `primitives::H256` itself and `beacon::primitives::HashTreeRoot` re-exports lean's trait, so both conversions and the duplicate trait are gone. What an external crate was actually supplying beyond the hash is two newtypes, `H160` and `U256`, which this module now declares. `U256` holds the 32 little-endian bytes SSZ encodes it as, so encoding and merkleizing are the inner array's. That puts the stored byte order opposite the numeric one, so `Ord` is written out: derived, it would compare the least significant byte first and invert the `terminal_total_difficulty` comparisons that are the only place the specification orders a `uint256`. Mainnet's value fits 128 bits and is now spelled as its decimal digits rather than as limbs; both values stay pinned against the configuration files' decimal strings. `H160` writes out `libssz_merkle::HashTreeRoot` because the derive drops `is_basic_type`, and at 20 bytes wide that answer decides whether a collection of addresses packs or pads. No container holds one today, so both answers agree everywhere it is currently asked; writing it out is what keeps the first container that does hold one from silently getting the other tree. `ethereum-types` stays in `Cargo.lock` as an indirect dependency of `ethrex-common`, which `ethlambda-p2p` needs for discv5. * refactor(types): print an H256 as hex under Debug, not as 32 numbers The derived `Debug` printed the inner array, so a hash came out as `H256([171, 171, ...])`: unreadable alone, and unreadable in bulk inside the `Debug` of a container holding thousands of roots. `ethereum-types` printed hex, so with the beacon `Root` now being this type, keeping the derive would have made every spec-suite assertion failure that prints a state harder to read than before. Same output as `Display`. Nothing asserted on the old form. `ShortRoot` is still the way to truncate at a call site that wants it short. --- .github/workflows/ci.yml | 14 + CLAUDE.md | 58 + Cargo.lock | 114 +- Cargo.toml | 32 +- crates/common/types/Cargo.toml | 9 + crates/common/types/src/beacon/config.rs | 647 ++++++++ crates/common/types/src/beacon/constants.rs | 292 ++++ .../types/src/beacon/containers/altair.rs | 353 +++++ .../types/src/beacon/containers/bellatrix.rs | 371 +++++ .../types/src/beacon/containers/capella.rs | 417 +++++ .../types/src/beacon/containers/deneb.rs | 389 +++++ .../types/src/beacon/containers/electra.rs | 582 +++++++ .../types/src/beacon/containers/fulu.rs | 347 ++++ .../common/types/src/beacon/containers/mod.rs | 706 +++++++++ .../types/src/beacon/containers/phase0.rs | 269 ++++ .../types/src/beacon/containers/shared.rs | 372 +++++ crates/common/types/src/beacon/error.rs | 70 + crates/common/types/src/beacon/fork.rs | 219 +++ crates/common/types/src/beacon/fork_choice.rs | 66 + crates/common/types/src/beacon/fork_digest.rs | 161 ++ crates/common/types/src/beacon/mod.rs | 112 ++ crates/common/types/src/beacon/preset.rs | 1399 +++++++++++++++++ crates/common/types/src/beacon/primitives.rs | 496 ++++++ crates/common/types/src/lib.rs | 1 + crates/common/types/src/primitives.rs | 33 +- crates/common/types/src/state.rs | 6 +- 26 files changed, 7493 insertions(+), 42 deletions(-) create mode 100644 crates/common/types/src/beacon/config.rs create mode 100644 crates/common/types/src/beacon/constants.rs create mode 100644 crates/common/types/src/beacon/containers/altair.rs create mode 100644 crates/common/types/src/beacon/containers/bellatrix.rs create mode 100644 crates/common/types/src/beacon/containers/capella.rs create mode 100644 crates/common/types/src/beacon/containers/deneb.rs create mode 100644 crates/common/types/src/beacon/containers/electra.rs create mode 100644 crates/common/types/src/beacon/containers/fulu.rs create mode 100644 crates/common/types/src/beacon/containers/mod.rs create mode 100644 crates/common/types/src/beacon/containers/phase0.rs create mode 100644 crates/common/types/src/beacon/containers/shared.rs create mode 100644 crates/common/types/src/beacon/error.rs create mode 100644 crates/common/types/src/beacon/fork.rs create mode 100644 crates/common/types/src/beacon/fork_choice.rs create mode 100644 crates/common/types/src/beacon/fork_digest.rs create mode 100644 crates/common/types/src/beacon/mod.rs create mode 100644 crates/common/types/src/beacon/preset.rs create mode 100644 crates/common/types/src/beacon/primitives.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b32291018..284c982bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,6 +49,20 @@ jobs: - name: Clippy run: cargo clippy --locked --workspace --all-targets -- -D warnings + # The beacon containers' SSZ bounds are const-generic arguments, so the + # minimal preset is a whole second compilation of ethlambda-types that + # nothing above reaches: every step so far builds the default (mainnet) + # preset only. Without this the `preset-minimal` feature would rot between + # merges, and the fixture suites that select it live on another branch. + # + # `--lib`, because this job downloads no fixtures. The crate's other test + # target, `ssz_spectests`, walks `leanSpec/fixtures` and panics outright + # when it is absent, which only the `test` job below fetches. The unit + # tests are what the preset actually changes, and they read nothing from + # disk. + - name: Check the minimal preset + run: cargo test -p ethlambda-types --lib --features preset-minimal + # tooling/event-monitor declares its own [workspace] table, so every step # above stops at the root workspace members and never reaches it. Its # tests run in this job rather than in `test` because clippy has already diff --git a/CLAUDE.md b/CLAUDE.md index e8f22ae99..c77c9793b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -304,6 +304,64 @@ The RPC crate serves the API router (`--api-port`, default 5052) and the metrics when they are equal it merges all three routers onto a single listener, so pointing both flags at one port is supported and not a misconfiguration. See [`docs/rpc.md`](docs/rpc.md) for the full reference: CLI flags and defaults, the API endpoints (health, finalized state/block, justified checkpoint, blocks by root/slot, fork-choice tree + D3.js UI, runtime aggregator toggle), the metrics/debug endpoints (Prometheus `/metrics`, jemalloc heap profiling), the Hive test-driver endpoints, plus request/response shapes, status codes, and content types. +## Beacon Chain types (`crates/common/types/src/beacon/`) + +`ethlambda-types` carries the **Ethereum Beacon Chain** containers (phase0 +through fulu) alongside lean's own types. The Beacon Chain is a different +protocol from the Lean consensus this repo implements; the types share a crate +so that one `BlockChainServer` can dispatch on a single state type instead of +existing once per chain. + +- `BeaconState` has a **`Lean` variant holding lean's `State`**, and `ForkName` + a matching `Lean`. Only `fork_name()` and `from_ssz()` handle it; every other + beacon accessor answers `unreachable!()` naming itself. The guarantee is the + single `match` at the top of each handler, not the type system, so a lean + state reaching a beacon accessor should fail as a named panic rather than a + silent wrong answer. +- **`ForkName::Lean` is deliberately absent from `ForkName::ALL`.** `ALL` is + what `parse`, `previous` and `next` search, so its absence keeps + `parse("lean")` at `None` and `Fulu.next()` at `None`, meaning a fork upgrade + cannot walk off the end into lean. Lean is not a point on the Beacon Chain's + fork timeline. `Lean` is declared *last* so the derived `Ord` puts it after + every beacon fork, which is what `fork >= ForkName::X` gating reads. +- Preset is a **compile-time** choice (`preset-minimal` feature on this crate) + because SSZ container bounds are const-generic arguments; fork scheduling is + runtime (`beacon::config`) instead. Every lean crate depends on + `ethlambda-types`, so enabling the feature rebuilds it for the whole graph; + lean code reads none of the beacon preset constants, so it cannot change lean + behavior. +- Per-fork containers are plain structs behind an enum, so SSZ stays derived: + two of phase0's fields are *replaced* in altair, one field changes type in + five separate forks, and the state's merkle tree gains a level at electra. +- **`beacon::primitives::Root` *is* `primitives::H256`**, not a second 32-byte + hash converted at the boundary, and `beacon::primitives::HashTreeRoot` + re-exports lean's convenience trait rather than declaring its own. The + primitive family a beacon container needs beyond that is two newtypes, + `H160` and `U256`, so the crate declares them instead of depending on + `ethereum-types`. Two consequences worth knowing: + - `U256` holds the **32 little-endian bytes SSZ encodes it as**, so its + stored byte order is the reverse of its numeric one and `Ord` is written + out by hand. Do not derive it: a derived `Ord` compares the least + significant byte first, which would silently invert + `terminal_total_difficulty` comparisons. + - `H160` writes out `libssz_merkle::HashTreeRoot` because the derive drops + `is_basic_type`, and at 20 bytes wide that answer changes the merkle tree + of any list or vector of addresses. Everything else here is 32 bytes, + where packing and per-element padding coincide, so the derive is fine. +- **Requires mutable element access on `SszList`**, which no published libssz + release has, so all four libssz crates are **git dependencies** on + `lambdaclass/libssz` (for lambdaclass/libssz#33), pinned by `rev` rather than + tracking `main`: this is the SSZ encoder and merkleizer behind every + `hash_tree_root`, so a routine `cargo update` must not be able to move it. + Return them to a crates.io version once a release carries #33. A git dependency rather than a + `[patch.crates-io]` override because nothing outside this workspace depends on + libssz, so there is no second copy to unify; that also keeps the manifest free + of a `[patch]` table, which `shadow/cargo-patch.toml` would collide with. +- The state transition consuming these containers is **not** in this repo yet; + it lives on `feat/beacon-chain-stf`, where these types are verified against + consensus-specs v1.6.1 (5705 mainnet / 40009 minimal cases). What runs here + is the containers' own round-trip and shape tests. + ## Configuration Files **Genesis:** `config.yaml` (YAML format, cross-client compatible) diff --git a/Cargo.lock b/Cargo.lock index 586c4b3ba..ddf3abc70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1928,8 +1928,8 @@ dependencies = [ "eyre", "hex", "libc", - "libssz", - "libssz-types", + "libssz 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-types 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "rayon", "reqwest", "serde", @@ -1960,8 +1960,8 @@ dependencies = [ "ethlambda-types", "hex", "leansig", - "libssz", - "libssz-types", + "libssz 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-types 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "rand 0.10.1", "rayon", "serde", @@ -2022,10 +2022,10 @@ dependencies = [ "futures", "hex", "libp2p", - "libssz", - "libssz-derive", - "libssz-merkle", - "libssz-types", + "libssz 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-derive 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-merkle 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-types 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "rand 0.8.6", "secp256k1 0.30.0", "sha2", @@ -2053,7 +2053,7 @@ dependencies = [ "hex", "http-body-util", "jemalloc_pprof", - "libssz", + "libssz 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "serde", "serde_json", "tokio", @@ -2071,7 +2071,7 @@ dependencies = [ "ethlambda-test-fixtures", "ethlambda-types", "hex", - "libssz-types", + "libssz-types 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "serde", "serde_json", "thiserror 2.0.18", @@ -2085,9 +2085,9 @@ dependencies = [ "ethlambda-crypto", "ethlambda-types", "leansig", - "libssz", - "libssz-derive", - "libssz-types", + "libssz 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-derive 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-types 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "lru", "rand 0.10.1", "rocksdb", @@ -2103,8 +2103,8 @@ dependencies = [ "ethlambda-state-transition", "ethlambda-types", "hex", - "libssz", - "libssz-types", + "libssz 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-types 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "serde", "serde_json", ] @@ -2116,14 +2116,15 @@ dependencies = [ "datatest-stable", "ethlambda-test-fixtures", "hex", - "libssz", - "libssz-derive", - "libssz-merkle", - "libssz-types", + "libssz 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-derive 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-merkle 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-types 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "rand 0.10.1", "serde", "serde_json", "serde_yaml_ng", + "sha2", "thiserror 2.0.18", ] @@ -2142,8 +2143,8 @@ dependencies = [ "ethrex-storage", "ethrex-trie", "ethrex-vm", - "libssz", - "libssz-merkle", + "libssz 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libssz-merkle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon", "rustc-hash", "thiserror 2.0.18", @@ -2169,10 +2170,10 @@ dependencies = [ "indexmap 2.14.0", "lazy_static", "libc", - "libssz", - "libssz-derive", - "libssz-merkle", - "libssz-types", + "libssz 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libssz-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libssz-merkle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libssz-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lru", "once_cell", "rayon", @@ -2221,10 +2222,10 @@ dependencies = [ "ethrex-rlp", "ethrex-vm", "hex", - "libssz", - "libssz-derive", - "libssz-merkle", - "libssz-types", + "libssz 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libssz-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libssz-merkle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libssz-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rkyv", "serde", "serde_with", @@ -2259,7 +2260,7 @@ dependencies = [ "ethrex-common", "ethrex-crypto", "ethrex-rlp", - "libssz", + "libssz 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "malachite", "rustc-hash", "serde", @@ -4493,6 +4494,14 @@ dependencies = [ "smallvec", ] +[[package]] +name = "libssz" +version = "0.3.0" +source = "git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7#36802dd1d3e3a83d95d2ac552647539cbe3f7fd7" +dependencies = [ + "smallvec", +] + [[package]] name = "libssz-derive" version = "0.3.0" @@ -4504,13 +4513,32 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "libssz-derive" +version = "0.3.0" +source = "git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7#36802dd1d3e3a83d95d2ac552647539cbe3f7fd7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "libssz-merkle" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "863eca32d1a43e5ec41106a515552efa8307768d37c68d26b7f21ff13cfee1a7" dependencies = [ - "libssz", + "libssz 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2", +] + +[[package]] +name = "libssz-merkle" +version = "0.3.0" +source = "git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7#36802dd1d3e3a83d95d2ac552647539cbe3f7fd7" +dependencies = [ + "libssz 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "sha2", ] @@ -4520,8 +4548,18 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4231ac301726840a3fe111f11bd4619d3c97ed155cb94c88dbf92b70e04e017" dependencies = [ - "libssz", - "libssz-merkle", + "libssz 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libssz-merkle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec", +] + +[[package]] +name = "libssz-types" +version = "0.3.0" +source = "git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7#36802dd1d3e3a83d95d2ac552647539cbe3f7fd7" +dependencies = [ + "libssz 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-merkle 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "smallvec", ] @@ -6868,6 +6906,16 @@ dependencies = [ "cfg-if", "cpufeatures 0.2.17", "digest 0.10.7", + "sha2-asm", +] + +[[package]] +name = "sha2-asm" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b845214d6175804686b2bd482bcffe96651bb2d1200742b712003504a2dac1ab" +dependencies = [ + "cc", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1d41c5a70..b92203c5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,14 +81,36 @@ prometheus = "0.14" clap = { version = "4.3", features = ["derive", "env"] } +# Merkleizing a beacon state is almost entirely SHA-256 compressions, so which +# implementation `sha2` picks matters. What `asm` actually buys is aarch64: on +# x86/x86_64, sha2 0.10.9 compiles its `x86` backend and dispatches to the SHA-NI +# intrinsics through `cpufeatures` whether or not this feature is set, and `asm` +# only swaps the *fallback* for that dispatch from pure Rust to `sha2-asm`. On +# aarch64 the feature is the whole hardware path: without it the crate falls +# through to the pure-Rust backend. Selection stays at run time either way, so the +# build remains portable to hardware lacking the extensions. +sha2 = { version = "0.10.9", features = ["asm"] } + # XMSS signatures leansig = { git = "https://github.com/leanEthereum/leanSig", branch = "devnet4" } -# SSZ implementation -libssz = "0.3.0" -libssz-derive = "0.3.0" -libssz-merkle = "0.3.0" -libssz-types = "0.3.0" +# SSZ implementation. +# +# Tracked from git rather than crates.io because the Beacon Chain containers +# hand out `&mut` into an `SszList` (the validator registry, through +# `altair_validator_lists_mut`), which published libssz-types 0.3.0 cannot do: +# it exposes only `Deref` and `Index`. `DerefMut` and `IndexMut` landed after +# that release, in lambdaclass/libssz#33. +# +# Pinned by `rev` rather than tracking `main`: the requirement is a commit that +# carries #33, not whatever `main` holds today, and `main` here is the SSZ encoder +# and merkleizer that decides every `hash_tree_root`, so a routine `cargo update` +# must not be able to move it. Return these to a crates.io version once a release +# carrying #33 exists. +libssz = { git = "https://github.com/lambdaclass/libssz", rev = "36802dd1d3e3a83d95d2ac552647539cbe3f7fd7" } +libssz-derive = { git = "https://github.com/lambdaclass/libssz", rev = "36802dd1d3e3a83d95d2ac552647539cbe3f7fd7" } +libssz-merkle = { git = "https://github.com/lambdaclass/libssz", rev = "36802dd1d3e3a83d95d2ac552647539cbe3f7fd7" } +libssz-types = { git = "https://github.com/lambdaclass/libssz", rev = "36802dd1d3e3a83d95d2ac552647539cbe3f7fd7" } # Build-time version info vergen-git2 = { version = "9", features = ["rustc"] } diff --git a/crates/common/types/Cargo.toml b/crates/common/types/Cargo.toml index 383f77a38..a3dae4d87 100644 --- a/crates/common/types/Cargo.toml +++ b/crates/common/types/Cargo.toml @@ -9,6 +9,14 @@ repository.workspace = true rust-version.workspace = true version.workspace = true +[features] +# Compile the beacon containers against the minimal preset instead of mainnet. +# +# Container shapes are compile-time constants (SSZ list and vector bounds), so +# the preset cannot be selected at runtime. Mainnet is the implicit default. +# `ethlambda-beacon`'s feature of the same name forwards to this one. +preset-minimal = [] + [dependencies] thiserror.workspace = true serde.workspace = true @@ -18,6 +26,7 @@ libssz.workspace = true libssz-derive.workspace = true libssz-merkle.workspace = true libssz-types.workspace = true +sha2.workspace = true [dev-dependencies] serde_json.workspace = true diff --git a/crates/common/types/src/beacon/config.rs b/crates/common/types/src/beacon/config.rs new file mode 100644 index 000000000..a82ef68da --- /dev/null +++ b/crates/common/types/src/beacon/config.rs @@ -0,0 +1,647 @@ +//! Runtime chain configuration: the values `configs/mainnet.yaml` and +//! `configs/minimal.yaml` set per network, as opposed to constants (fixed by +//! the specification, see [`crate::beacon::constants`]) or preset values (compile-time +//! container bounds, see [`crate::beacon::preset`]). +//! +//! Fork *scheduling* lives here rather than at compile time specifically +//! because the `transition` fixture suite needs to move a fork's activation +//! epoch per test case; there is no other reason a fork version or epoch +//! could not have been a preset. Everything else in [`Config`] is here simply +//! because the specification itself calls it configuration. +//! +//! # What is deliberately left out +//! +//! - **Networking values** (gossip mesh parameters, request/response size +//! limits, subnet counts, `MAX_PAYLOAD_SIZE`, and so on): this crate +//! implements the state transition and fork choice, not the wire protocol, +//! so nothing here would ever read them. +//! - **Deposit contract identity** (`DEPOSIT_CHAIN_ID`, `DEPOSIT_NETWORK_ID`, +//! `DEPOSIT_CONTRACT_ADDRESS`): these tell a validator client which Eth1 +//! chain and contract to watch for deposits. The state transition only ever +//! processes deposits that are already included in a block (via +//! `Eth1Data` votes or, from electra onward, execution layer requests); it +//! never itself looks the deposit contract up. +//! +//! The genesis-section values are all included. `GENESIS_FORK_VERSION` is fork +//! scheduling rather than genesis construction, since [`Config::fork_version`] +//! reads it on every phase0-era signature. The other three +//! (`MIN_GENESIS_ACTIVE_VALIDATOR_COUNT`, `MIN_GENESIS_TIME`, `GENESIS_DELAY`) +//! are read only while building a genesis state from Eth1 deposit history, and +//! never again once that state exists, but `ethlambda_beacon::genesis` needs them +//! and the `genesis` fixture suite checks them. + +use crate::beacon::constants; +use crate::beacon::fork::ForkName; +use crate::beacon::lean_fork_unreachable; +use crate::beacon::primitives::{Epoch, ExecutionBlockHash, Gwei, U256, Uint256, Version}; + +/// One entry in fulu's blob schedule: from `epoch` onward (until a later +/// entry takes over), a block may carry up to `max_blobs_per_block` blobs. +/// +/// Modeled as a plain struct rather than a `(Epoch, u64)` tuple so that +/// [`Config::max_blobs_per_block`]'s search reads as "find the entry", not +/// "find the pair". +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct BlobScheduleEntry { + /// The first epoch this entry applies to. + pub epoch: Epoch, + /// The blob count limit from `epoch` onward. + pub max_blobs_per_block: u64, +} + +/// The runtime configuration for one network: fork scheduling plus every +/// other value the state transition and fork choice read at runtime rather +/// than at compile time. +/// +/// Construct one with [`Config::mainnet`], [`Config::minimal`], or +/// [`Config::active`]; adjust a single fork's activation epoch with +/// [`Config::with_fork_epoch`] for fixture-driven tests that need one. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Config { + // -- Genesis construction --------------------------------------------- + /// How many active validators the chain needs before it may start. + pub min_genesis_active_validator_count: u64, + /// The earliest wall-clock time the chain may start at, whatever the Eth1 + /// deposit history says. + pub min_genesis_time: u64, + /// How long after the Eth1 block that satisfies the genesis conditions the + /// chain actually starts. + /// + /// The delay exists so that validators who deposited just before the + /// threshold was crossed still have time to get their nodes running. + pub genesis_delay: u64, + + // -- Fork scheduling -------------------------------------------------- + /// The `Fork.current_version` a phase0 block or attestation signs under, + /// and the value every later fork's version is a successor to. Also + /// mixed into `compute_fork_data_root` when computing the genesis + /// validators root's domain, alongside the all-zero genesis validators + /// root, at chain start. + pub genesis_fork_version: Version, + /// The `Fork.current_version` an altair block or attestation signs under. + pub altair_fork_version: Version, + /// The epoch altair activates at, or [`constants::FAR_FUTURE_EPOCH`] if it + /// is not scheduled on this network. + pub altair_fork_epoch: Epoch, + /// The `Fork.current_version` a bellatrix block or attestation signs + /// under. + pub bellatrix_fork_version: Version, + /// The epoch bellatrix (the Merge) activates at, or + /// [`constants::FAR_FUTURE_EPOCH`] if it is not scheduled. + pub bellatrix_fork_epoch: Epoch, + /// The `Fork.current_version` a capella block or attestation signs under. + pub capella_fork_version: Version, + /// The epoch capella activates at, or [`constants::FAR_FUTURE_EPOCH`] if + /// it is not scheduled. + pub capella_fork_epoch: Epoch, + /// The `Fork.current_version` a deneb block or attestation signs under. + pub deneb_fork_version: Version, + /// The epoch deneb activates at, or [`constants::FAR_FUTURE_EPOCH`] if it + /// is not scheduled. + pub deneb_fork_epoch: Epoch, + /// The `Fork.current_version` an electra block or attestation signs + /// under. + pub electra_fork_version: Version, + /// The epoch electra activates at, or [`constants::FAR_FUTURE_EPOCH`] if + /// it is not scheduled. + pub electra_fork_epoch: Epoch, + /// The `Fork.current_version` a fulu block or attestation signs under. + pub fulu_fork_version: Version, + /// The epoch fulu activates at, or [`constants::FAR_FUTURE_EPOCH`] if it + /// is not scheduled. + pub fulu_fork_epoch: Epoch, + + // -- Time parameters --------------------------------------------------- + /// Wall-clock seconds per slot. Deprecated in favor of + /// [`Self::slot_duration_ms`] for anything needing sub-second precision, + /// but still how `compute_time_at_slot` and the fork choice store's + /// `genesis_time`-to-slot arithmetic convert between a slot number and a + /// wall-clock time. + pub seconds_per_slot: u64, + /// Milliseconds per slot. What the fork choice store's timeliness + /// checks (`get_attestation_due_ms` and friends) actually divide the + /// `*_due_bps` fields below by; equal to `seconds_per_slot * 1000` on + /// every network this crate ships a constructor for, but tracked + /// separately because the specification does. + pub slot_duration_ms: u64, + /// The assumed seconds per execution-layer block, used to convert + /// [`Self::eth1_follow_distance`] (a block count) into a voting-period + /// safety margin. + pub seconds_per_eth1_block: u64, + /// Epochs a validator must wait after its exit is processed before its + /// balance becomes withdrawable. + pub min_validator_withdrawability_delay: Epoch, + /// Epochs a validator must be active before it is eligible to propose, + /// perform voluntary exits, or (from electra) initiate a consolidation. + pub shard_committee_period: Epoch, + /// Execution-layer blocks a state's Eth1 vote must lag the execution + /// chain's head by, so that every node's view of "current" Eth1 data + /// agrees despite network latency and minor reorgs. + pub eth1_follow_distance: u64, + /// Basis points of [`Self::slot_duration_ms`] by which an attestation is + /// due; read by the fork choice store's `get_attestation_due_ms`. + pub attestation_due_bps: u64, + /// Basis points of [`Self::slot_duration_ms`] by which an aggregate + /// attestation is due; read by `get_aggregate_due_ms`. + pub aggregate_due_bps: u64, + /// Basis points of [`Self::slot_duration_ms`] past which a proposer must + /// no longer attempt a late-block reorg; read by + /// `get_proposer_reorg_cutoff_ms`. + pub proposer_reorg_cutoff_bps: u64, + /// Basis points of [`Self::slot_duration_ms`] by which a sync committee + /// message is due (altair); read by `get_sync_message_due_ms`. + pub sync_message_due_bps: u64, + /// Basis points of [`Self::slot_duration_ms`] by which a sync committee + /// contribution is due (altair); read by `get_contribution_due_ms`. + pub contribution_due_bps: u64, + + // -- Validator cycle ----------------------------------------------------- + /// Score points added to a validator's inactivity score for each epoch it + /// is offline (or the chain is leaking) without a timely target vote. + pub inactivity_score_bias: u64, + /// Score points subtracted from a validator's inactivity score for each + /// epoch it casts a timely target vote while the chain is not leaking. + pub inactivity_score_recovery_rate: u64, + /// Effective balance floor below which a validator is force-exited at the + /// next opportunity, regardless of its own wishes. + pub ejection_balance: Gwei, + /// The minimum validators allowed to enter the activation/exit queue in + /// one epoch, regardless of the active validator set's size. Prevents the + /// churn limit from collapsing to zero on a small validator set. + pub min_per_epoch_churn_limit: u64, + /// Active validators per unit of per-epoch activation/exit churn: the + /// churn limit before electra is `active_validator_count / + /// churn_limit_quotient`, floored at [`Self::min_per_epoch_churn_limit`]. + pub churn_limit_quotient: u64, + /// Deneb: an additional cap on the activation churn limit specifically + /// (separate from the combined activation/exit limit above), so that + /// activations cannot alone consume the whole per-epoch churn budget. + /// Superseded by [`Self::max_per_epoch_activation_exit_churn_limit`] from + /// electra onward, but the specification keeps both names rather than + /// reusing one. + pub max_per_epoch_activation_churn_limit: u64, + /// Electra: the churn limit is now denominated in Gwei rather than a + /// validator count (`get_balance_churn_limit`), and this is its floor, + /// replacing [`Self::min_per_epoch_churn_limit`] from electra onward. + pub min_per_epoch_churn_limit_electra: Gwei, + /// Electra: the ceiling on the portion of the (Gwei-denominated) churn + /// limit dedicated to activations and exits, as opposed to + /// consolidations (`get_activation_exit_churn_limit`). + pub max_per_epoch_activation_exit_churn_limit: Gwei, + + // -- Fork choice --------------------------------------------------------- + /// Percentage boost, relative to a single committee's weight, given to a + /// block proposed on time when comparing it against competitors for head. + /// Deters "balancing" attacks that rely on splitting the vote right at a + /// slot boundary. + pub proposer_score_boost: u64, + /// Percentage of committee weight the current head must be below the + /// parent's competing child by for a proposer to consider reorging it out. + pub reorg_head_weight_threshold: u64, + /// Percentage of committee weight the parent block must exceed for a + /// proposer to consider reorging its late child out. + pub reorg_parent_weight_threshold: u64, + /// How many epochs finality is allowed to lag before a proposer refuses to + /// attempt a reorg at all, regardless of the weight thresholds above. + /// Reorgs are a liveness optimization; this bounds how much they may risk + /// finality progress to pursue it. + pub reorg_max_epochs_since_finalization: Epoch, + + // -- Transition (bellatrix) ----------------------------------------------- + /// The proof-of-work total difficulty at or above which a PoW block + /// becomes a valid terminal block for the Merge transition. + /// [`Uint256`]-sized because total difficulty accumulates over the + /// entire PoW chain's history and long since overflowed 64 bits. + pub terminal_total_difficulty: Uint256, + /// A specific PoW block hash that overrides [`Self::terminal_total_difficulty`] + /// as the terminal block, if set to anything other than the zero hash. + /// Existed as an emergency override in case total-difficulty tracking + /// disagreed across clients near the Merge; every shipped network left it + /// unset. + pub terminal_block_hash: ExecutionBlockHash, + /// The epoch at or after which [`Self::terminal_block_hash`], if set, is + /// honored. Guards against an old override value being replayed before + /// the network is ready for it. + pub terminal_block_hash_activation_epoch: Epoch, + + // -- Blob limits ----------------------------------------------------------- + /// Deneb's fixed cap on `blob_kzg_commitments` per block, in effect from + /// deneb until electra raises it. + pub max_blobs_per_block_deneb: u64, + /// Electra's fixed cap on `blob_kzg_commitments` per block. Also the value + /// [`Self::max_blobs_per_block`] falls back to for any epoch fulu's blob + /// schedule does not (yet) cover, matching `get_blob_parameters`'s own + /// fallback of `BlobParameters(ELECTRA_FORK_EPOCH, + /// MAX_BLOBS_PER_BLOCK_ELECTRA)`. + pub max_blobs_per_block_electra: u64, + /// Fulu's blob schedule (EIP7892): a possibly-empty list of `(epoch, + /// limit)` entries, kept sorted ascending by epoch, that lets the blob + /// count limit change again after electra without a new hard fork per + /// change. Read through [`Config::max_blobs_per_block`] rather than + /// directly. + pub blob_schedule: Vec, +} + +/// Mainnet's `TERMINAL_TOTAL_DIFFICULTY`. +/// +/// A `const` rather than `Uint256::from_dec_str(..).expect(..)` inside +/// [`Config::mainnet`], so the digits are converted once at compile time instead +/// of on every construction, and a typo is a build failure rather than a panic. +const MAINNET_TERMINAL_TOTAL_DIFFICULTY: Uint256 = + Uint256::from_u128(58_750_000_000_000_000_000_000); + +/// Minimal's `TERMINAL_TOTAL_DIFFICULTY`, 2^256 - 2^10. +/// +/// Past 128 bits, so written as the little-endian bytes [`Uint256`] stores +/// rather than as decimal digits. Those bytes are unreadable by construction, so +/// a test below pins this and [`MAINNET_TERMINAL_TOTAL_DIFFICULTY`] against the +/// decimal strings the configuration files actually carry. +const MINIMAL_TERMINAL_TOTAL_DIFFICULTY: Uint256 = { + let mut bytes = [0xff; 32]; + bytes[0] = 0x00; + bytes[1] = 0xfc; + U256(bytes) +}; + +impl Config { + /// The configuration matching Ethereum mainnet, as of the pinned + /// specification version's `configs/mainnet.yaml`. + pub fn mainnet() -> Self { + Config { + min_genesis_active_validator_count: 16_384, + min_genesis_time: 1_606_824_000, + genesis_delay: 604_800, + genesis_fork_version: [0x00, 0x00, 0x00, 0x00], + altair_fork_version: [0x01, 0x00, 0x00, 0x00], + altair_fork_epoch: 74_240, + bellatrix_fork_version: [0x02, 0x00, 0x00, 0x00], + bellatrix_fork_epoch: 144_896, + capella_fork_version: [0x03, 0x00, 0x00, 0x00], + capella_fork_epoch: 194_048, + deneb_fork_version: [0x04, 0x00, 0x00, 0x00], + deneb_fork_epoch: 269_568, + electra_fork_version: [0x05, 0x00, 0x00, 0x00], + electra_fork_epoch: 364_032, + fulu_fork_version: [0x06, 0x00, 0x00, 0x00], + fulu_fork_epoch: 411_392, + + seconds_per_slot: 12, + slot_duration_ms: 12_000, + seconds_per_eth1_block: 14, + min_validator_withdrawability_delay: 256, + shard_committee_period: 256, + eth1_follow_distance: 2_048, + attestation_due_bps: 3_333, + aggregate_due_bps: 6_667, + proposer_reorg_cutoff_bps: 1_667, + sync_message_due_bps: 3_333, + contribution_due_bps: 6_667, + + inactivity_score_bias: 4, + inactivity_score_recovery_rate: 16, + ejection_balance: 16_000_000_000, + min_per_epoch_churn_limit: 4, + churn_limit_quotient: 65_536, + max_per_epoch_activation_churn_limit: 8, + min_per_epoch_churn_limit_electra: 128_000_000_000, + max_per_epoch_activation_exit_churn_limit: 256_000_000_000, + + proposer_score_boost: 40, + reorg_head_weight_threshold: 20, + reorg_parent_weight_threshold: 160, + reorg_max_epochs_since_finalization: 2, + + // Reached September 15, 2022 (the Merge); mainnet has been on + // proof of stake ever since, so this and the two fields below + // never trigger again in practice, but are still read by any + // faithful implementation of `validate_merge_block`. + terminal_total_difficulty: MAINNET_TERMINAL_TOTAL_DIFFICULTY, + terminal_block_hash: ExecutionBlockHash::ZERO, + terminal_block_hash_activation_epoch: constants::FAR_FUTURE_EPOCH, + + max_blobs_per_block_deneb: 6, + max_blobs_per_block_electra: 9, + blob_schedule: vec![ + BlobScheduleEntry { + epoch: 412_672, + max_blobs_per_block: 15, + }, + BlobScheduleEntry { + epoch: 419_072, + max_blobs_per_block: 21, + }, + ], + } + } + + /// The configuration matching the specification's `minimal` preset, as of + /// the pinned specification version's `configs/minimal.yaml`. + /// + /// Every fork after phase0 defaults to + /// [`constants::FAR_FUTURE_EPOCH`] here: `minimal` is a base for spec + /// fixtures, not a network of its own, and each fixture's `meta.yaml` + /// picks which single fork boundary it wants to exercise via + /// [`Config::with_fork_epoch`] rather than inheriting a fixed schedule. + pub fn minimal() -> Self { + Config { + min_genesis_active_validator_count: 64, + min_genesis_time: 1_578_009_600, + genesis_delay: 300, + genesis_fork_version: [0x00, 0x00, 0x00, 0x01], + altair_fork_version: [0x01, 0x00, 0x00, 0x01], + altair_fork_epoch: constants::FAR_FUTURE_EPOCH, + bellatrix_fork_version: [0x02, 0x00, 0x00, 0x01], + bellatrix_fork_epoch: constants::FAR_FUTURE_EPOCH, + capella_fork_version: [0x03, 0x00, 0x00, 0x01], + capella_fork_epoch: constants::FAR_FUTURE_EPOCH, + deneb_fork_version: [0x04, 0x00, 0x00, 0x01], + deneb_fork_epoch: constants::FAR_FUTURE_EPOCH, + electra_fork_version: [0x05, 0x00, 0x00, 0x01], + electra_fork_epoch: constants::FAR_FUTURE_EPOCH, + fulu_fork_version: [0x06, 0x00, 0x00, 0x01], + fulu_fork_epoch: constants::FAR_FUTURE_EPOCH, + + seconds_per_slot: 6, + slot_duration_ms: 6_000, + seconds_per_eth1_block: 14, + min_validator_withdrawability_delay: 256, + shard_committee_period: 64, + eth1_follow_distance: 16, + attestation_due_bps: 3_333, + aggregate_due_bps: 6_667, + proposer_reorg_cutoff_bps: 1_667, + sync_message_due_bps: 3_333, + contribution_due_bps: 6_667, + + inactivity_score_bias: 4, + inactivity_score_recovery_rate: 16, + ejection_balance: 16_000_000_000, + min_per_epoch_churn_limit: 2, + churn_limit_quotient: 32, + max_per_epoch_activation_churn_limit: 4, + min_per_epoch_churn_limit_electra: 64_000_000_000, + max_per_epoch_activation_exit_churn_limit: 128_000_000_000, + + proposer_score_boost: 40, + reorg_head_weight_threshold: 20, + reorg_parent_weight_threshold: 160, + reorg_max_epochs_since_finalization: 2, + + // configs/minimal.yaml sets this to 2**256 - 2**10: large enough + // that no spec test's simulated PoW chain reaches it. + terminal_total_difficulty: MINIMAL_TERMINAL_TOTAL_DIFFICULTY, + terminal_block_hash: ExecutionBlockHash::ZERO, + terminal_block_hash_activation_epoch: constants::FAR_FUTURE_EPOCH, + + max_blobs_per_block_deneb: 6, + max_blobs_per_block_electra: 9, + blob_schedule: Vec::new(), + } + } + + /// The configuration matching the compiled-in preset: [`Config::minimal`] + /// when this crate is built with the `preset-minimal` feature, + /// [`Config::mainnet`] otherwise. + /// + /// For code that already knows its preset at compile time (unlike the + /// `transition` fixture suite, which needs to pick a configuration, and + /// possibly override a fork epoch, per test case). + pub fn active() -> Self { + if cfg!(feature = "preset-minimal") { + Self::minimal() + } else { + Self::mainnet() + } + } + + /// The fork active at `epoch`: the newest fork whose activation epoch is + /// both scheduled (not [`constants::FAR_FUTURE_EPOCH`]) and at or before + /// `epoch`. + /// + /// The "scheduled" check matters because an unscheduled fork's epoch + /// field holds [`constants::FAR_FUTURE_EPOCH`], which is a real, huge + /// `Epoch` value, not a `None`. Comparing epochs naively (newest fork + /// whose epoch is `<= epoch`, full stop) would treat that sentinel as a + /// legitimate activation epoch and could only ever be beaten by querying + /// an even larger epoch, so an unscheduled fork would still eventually + /// "activate" once the chain ran long enough. Filtering out + /// [`constants::FAR_FUTURE_EPOCH`] first is what makes "not scheduled" + /// mean "never", as intended. + /// + /// Phase0 is always scheduled (its epoch is + /// [`crate::beacon::constants::GENESIS_EPOCH`], never the sentinel), so this + /// always finds at least phase0 and never needs to fail. + pub fn fork_at_epoch(&self, epoch: Epoch) -> ForkName { + ForkName::ALL + .into_iter() + .rev() + .find(|&fork| { + let scheduled_at = self.fork_epoch(fork); + scheduled_at != constants::FAR_FUTURE_EPOCH && scheduled_at <= epoch + }) + .unwrap_or(ForkName::Phase0) + } + + /// The `Fork.current_version` value blocks and attestations of `fork` + /// sign under. + pub fn fork_version(&self, fork: ForkName) -> Version { + match fork { + ForkName::Phase0 => self.genesis_fork_version, + ForkName::Altair => self.altair_fork_version, + ForkName::Bellatrix => self.bellatrix_fork_version, + ForkName::Capella => self.capella_fork_version, + ForkName::Deneb => self.deneb_fork_version, + ForkName::Electra => self.electra_fork_version, + ForkName::Fulu => self.fulu_fork_version, + ForkName::Lean => lean_fork_unreachable("Config::fork_version"), + } + } + + /// The epoch `fork` activates at, or [`constants::FAR_FUTURE_EPOCH`] if it + /// is not scheduled on this configuration. Phase0 always returns + /// [`constants::GENESIS_EPOCH`]: it is the chain's starting fork, not a + /// configurable activation. + pub fn fork_epoch(&self, fork: ForkName) -> Epoch { + match fork { + ForkName::Phase0 => constants::GENESIS_EPOCH, + ForkName::Altair => self.altair_fork_epoch, + ForkName::Bellatrix => self.bellatrix_fork_epoch, + ForkName::Capella => self.capella_fork_epoch, + ForkName::Deneb => self.deneb_fork_epoch, + ForkName::Electra => self.electra_fork_epoch, + ForkName::Fulu => self.fulu_fork_epoch, + ForkName::Lean => lean_fork_unreachable("Config::fork_epoch"), + } + } + + /// Returns a copy of this configuration with `fork`'s activation epoch + /// set to `epoch`, leaving every other fork's schedule untouched. + /// + /// For the `transition` fixture suite, which starts from + /// [`Config::minimal`] (where every fork after phase0 defaults to + /// unscheduled) and overrides exactly the one boundary each test case + /// exercises. + /// + /// Phase0's activation is not stored as a field (it is always + /// [`constants::GENESIS_EPOCH`], see [`Config::fork_epoch`]), so passing + /// `ForkName::Phase0` here has no effect. + pub fn with_fork_epoch(mut self, fork: ForkName, epoch: Epoch) -> Self { + match fork { + ForkName::Phase0 => {} + ForkName::Altair => self.altair_fork_epoch = epoch, + ForkName::Bellatrix => self.bellatrix_fork_epoch = epoch, + ForkName::Capella => self.capella_fork_epoch = epoch, + ForkName::Deneb => self.deneb_fork_epoch = epoch, + ForkName::Electra => self.electra_fork_epoch = epoch, + ForkName::Fulu => self.fulu_fork_epoch = epoch, + ForkName::Lean => lean_fork_unreachable("Config::with_fork_epoch"), + } + self + } + + /// The blob parameters in effect at `epoch`, as + /// `(epoch, max_blobs_per_block)`, from fulu's [`Self::blob_schedule`]. + /// + /// This is `get_blob_parameters`: the schedule is searched from its + /// latest entry backward for the first one whose epoch is at or before + /// `epoch`; if none matches (the schedule is empty, as in + /// [`Config::minimal`]'s default, or every entry is still in the future), + /// this falls back to electra's own activation and + /// [`Self::max_blobs_per_block_electra`], exactly as the specification's + /// own `get_blob_parameters` falls back to `MAX_BLOBS_PER_BLOCK_ELECTRA`. + /// + /// The pair's *epoch* matters as much as its limit, since + /// [`crate::beacon::fork_digest::compute_fork_digest`] hashes both: that is + /// why this returns the pair and [`Self::max_blobs_per_block`] is the thin + /// half of it, rather than the search being written once per caller. + pub fn blob_parameters(&self, epoch: Epoch) -> (Epoch, u64) { + self.blob_schedule + .iter() + .rev() + .find(|entry| entry.epoch <= epoch) + .map(|entry| (entry.epoch, entry.max_blobs_per_block)) + .unwrap_or((self.electra_fork_epoch, self.max_blobs_per_block_electra)) + } + + /// The blob count limit for a block proposed in `epoch`. See + /// [`Self::blob_parameters`]. + /// + /// This is fulu's helper: a deneb- or electra-only block's blob count is + /// bounded by [`Self::max_blobs_per_block_deneb`] or + /// [`Self::max_blobs_per_block_electra`] directly instead, matching how + /// the specification only introduces `get_blob_parameters` at fulu. + pub fn max_blobs_per_block(&self, epoch: Epoch) -> u64 { + self.blob_parameters(epoch).1 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn the_terminal_total_difficulties_match_the_config_files() { + assert_eq!( + Config::mainnet().terminal_total_difficulty, + Uint256::from_dec_str("58750000000000000000000").unwrap(), + ); + assert_eq!( + Config::minimal().terminal_total_difficulty, + Uint256::from_dec_str( + "115792089237316195423570985008687907853269984665640564039457584007913129638912", + ) + .unwrap(), + ); + } + + #[test] + fn fork_at_epoch_matches_mainnet_boundaries() { + let config = Config::mainnet(); + // At each boundary: the epoch just before it still reports the + // previous fork, and the boundary epoch itself already reports the + // new one. + let boundaries = [ + (config.altair_fork_epoch, ForkName::Phase0, ForkName::Altair), + ( + config.bellatrix_fork_epoch, + ForkName::Altair, + ForkName::Bellatrix, + ), + ( + config.capella_fork_epoch, + ForkName::Bellatrix, + ForkName::Capella, + ), + (config.deneb_fork_epoch, ForkName::Capella, ForkName::Deneb), + ( + config.electra_fork_epoch, + ForkName::Deneb, + ForkName::Electra, + ), + (config.fulu_fork_epoch, ForkName::Electra, ForkName::Fulu), + ]; + for (boundary, before, at_and_after) in boundaries { + assert_eq!(config.fork_at_epoch(boundary - 1), before); + assert_eq!(config.fork_at_epoch(boundary), at_and_after); + } + } + + #[test] + fn unscheduled_forks_are_never_returned() { + // Minimal's stock configuration leaves every fork after phase0 at + // FAR_FUTURE_EPOCH. Querying any epoch, including the largest + // possible one, must still resolve to phase0 rather than treating + // the sentinel as a legitimate (if enormous) activation epoch. + let config = Config::minimal(); + assert_eq!(config.fork_at_epoch(0), ForkName::Phase0); + assert_eq!(config.fork_at_epoch(Epoch::MAX), ForkName::Phase0); + } + + #[test] + fn with_fork_epoch_shifts_a_single_boundary() { + let config = Config::minimal().with_fork_epoch(ForkName::Altair, 10); + assert_eq!(config.fork_at_epoch(9), ForkName::Phase0); + assert_eq!(config.fork_at_epoch(10), ForkName::Altair); + // Every later fork is still unscheduled, so a far-future epoch still + // resolves to the one fork that was actually overridden. + assert_eq!(config.fork_at_epoch(1_000_000), ForkName::Altair); + } + + #[test] + fn max_blobs_per_block_selects_the_active_schedule_entry() { + let config = Config::mainnet(); + let first = config.blob_schedule[0]; + let second = config.blob_schedule[1]; + + assert_eq!( + config.max_blobs_per_block(first.epoch - 1), + config.max_blobs_per_block_electra + ); + assert_eq!( + config.max_blobs_per_block(first.epoch), + first.max_blobs_per_block + ); + assert_eq!( + config.max_blobs_per_block(second.epoch - 1), + first.max_blobs_per_block + ); + assert_eq!( + config.max_blobs_per_block(second.epoch), + second.max_blobs_per_block + ); + assert_eq!( + config.max_blobs_per_block(second.epoch + 1_000), + second.max_blobs_per_block + ); + } + + #[test] + fn minimal_has_no_blob_schedule_and_falls_back_to_electra() { + let config = Config::minimal(); + assert!(config.blob_schedule.is_empty()); + assert_eq!( + config.max_blobs_per_block(0), + config.max_blobs_per_block_electra + ); + } +} diff --git a/crates/common/types/src/beacon/constants.rs b/crates/common/types/src/beacon/constants.rs new file mode 100644 index 000000000..8b65d1df2 --- /dev/null +++ b/crates/common/types/src/beacon/constants.rs @@ -0,0 +1,292 @@ +//! Spec constants: values the specification fixes outright, as opposed to +//! preset values (compile-time, see [`crate::beacon::preset`]) or configuration +//! values (runtime, per network, see [`crate::beacon::config`]). +//! +//! A value lives here only if the spec's own `.md` files list it under a +//! "Constants" heading (or, for domain types, wherever the fork first +//! introduces them; several forks file their `DOMAIN_*` additions under +//! "Custom types" instead, but they are the same kind of value as phase0's). +//! +//! One constant from phase0's table is deliberately not modeled: +//! `ENDIANNESS` ('little'). The specification needs to name it because Python +//! integer-to-bytes conversions take an explicit byte order argument; Rust +//! does not have that ambiguity; `to_le_bytes`/`from_le_bytes` (used +//! throughout this crate and by the SSZ codec) already commit to little-endian +//! in the function name, so there is no value for this constant to hold. + +use crate::beacon::primitives::{DomainType, Epoch, Gwei, Slot}; + +// --------------------------------------------------------------------------- +// Misc (phase0) +// --------------------------------------------------------------------------- + +/// The slot of the genesis block. Always zero: slots count up from genesis, +/// never down, so this is also the smallest valid `Slot`. +pub const GENESIS_SLOT: Slot = 0; + +/// The epoch containing [`GENESIS_SLOT`]. +pub const GENESIS_EPOCH: Epoch = 0; + +/// A sentinel meaning "this has not happened (yet)". +/// +/// Validator lifecycle fields (`activation_eligibility_epoch`, `exit_epoch`, +/// `withdrawable_epoch`, ...) hold this until the corresponding event is +/// scheduled. Comparisons like `validator.exit_epoch == FAR_FUTURE_EPOCH` +/// are how the spec asks "has this validator exited". [`crate::beacon::config`] reuses +/// the same sentinel for fork epochs that have not been scheduled, so that +/// `Config::fork_at_epoch` can skip them the same way. +pub const FAR_FUTURE_EPOCH: Epoch = Epoch::MAX; + +/// The number of ways a single epoch's reward budget is split among +/// validators: proposer inclusion plus one share per attestation component +/// tracked before altair (source, target, head). Altair replaces the +/// three-way split with [`PARTICIPATION_FLAG_WEIGHTS`], but phase0's base +/// reward computation still divides by this constant. +pub const BASE_REWARDS_PER_EPOCH: u64 = 4; + +/// The depth of the deposit contract's incremental merkle tree. Bounds the +/// length of a `Deposit`'s merkle proof (`DEPOSIT_CONTRACT_TREE_DEPTH + 1` +/// entries, the `+ 1` covers the mix-in of the deposit count), hence `usize`. +pub const DEPOSIT_CONTRACT_TREE_DEPTH: usize = 32; + +/// The number of bits in `BeaconState.justification_bits`: one bit per each of +/// the four most recent epochs, tracking whether it was justified. Bounds a +/// `Bitvector`, hence `usize`. +pub const JUSTIFICATION_BITS_LENGTH: usize = 4; + +/// `2**64 - 1`. Used only by `ethlambda_beacon::helpers::math`'s `integer_squareroot` +/// helper as the boundary past which the doubling-based Newton's method +/// bound is replaced by a precomputed answer; unrelated to +/// [`FAR_FUTURE_EPOCH`] despite the identical bit pattern. +pub const UINT64_MAX: u64 = u64::MAX; + +/// `floor(sqrt(UINT64_MAX))`. The precomputed answer `integer_squareroot` +/// returns for an input of exactly [`UINT64_MAX`], where the general +/// algorithm's intermediate arithmetic would otherwise overflow. +pub const UINT64_MAX_SQRT: u64 = 4_294_967_295; + +// --------------------------------------------------------------------------- +// Withdrawal prefixes +// --------------------------------------------------------------------------- +// +// The first byte of `Validator.withdrawal_credentials` selects how the rest +// of the 32 bytes are interpreted. Typed `u8`: each is compared against a +// single byte read out of a `Bytes32`, never SSZ-encoded on its own. + +/// Marks credentials as a raw BLS withdrawal pubkey hash: withdrawals are +/// disabled until the validator submits a `BLSToExecutionChange` upgrading to +/// [`ETH1_ADDRESS_WITHDRAWAL_PREFIX`]. +pub const BLS_WITHDRAWAL_PREFIX: u8 = 0x00; + +/// Marks credentials as wrapping an execution-layer address: withdrawals (from +/// capella onward) pay out to that address, and the validator is capped at +/// `MAX_EFFECTIVE_BALANCE` (a preset value) until it upgrades further to +/// [`COMPOUNDING_WITHDRAWAL_PREFIX`]. +pub const ETH1_ADDRESS_WITHDRAWAL_PREFIX: u8 = 0x01; + +/// Marks credentials as compounding (electra:EIP7251): balance above +/// `MIN_ACTIVATION_BALANCE` (a preset value) stays effective instead of +/// triggering an automatic partial withdrawal. +pub const COMPOUNDING_WITHDRAWAL_PREFIX: u8 = 0x02; + +// --------------------------------------------------------------------------- +// Domain types +// --------------------------------------------------------------------------- +// +// A `DomainType` names one kind of signable message. `get_domain` mixes one +// of these with a fork version and the genesis validators root to produce the +// `Domain` that actually goes into a signing root, so the same message signed +// under two different forks (or two different chains) produces unrelated +// signatures. + +/// Domain for a `BeaconBlock` proposal signature. +pub const DOMAIN_BEACON_PROPOSER: DomainType = [0x00, 0x00, 0x00, 0x00]; +/// Domain for an `AttestationData` signature. +pub const DOMAIN_BEACON_ATTESTER: DomainType = [0x01, 0x00, 0x00, 0x00]; +/// Domain for the per-epoch RANDAO reveal. +pub const DOMAIN_RANDAO: DomainType = [0x02, 0x00, 0x00, 0x00]; +/// Domain for a `DepositMessage`. Unlike the others, deposit signatures are +/// verified with a fixed genesis-independent domain (`compute_domain` called +/// with no fork data), since a deposit must be valid before the chain it +/// targets has even started. +pub const DOMAIN_DEPOSIT: DomainType = [0x03, 0x00, 0x00, 0x00]; +/// Domain for a `VoluntaryExit`. +pub const DOMAIN_VOLUNTARY_EXIT: DomainType = [0x04, 0x00, 0x00, 0x00]; +/// Domain for an aggregator's slot selection proof. +pub const DOMAIN_SELECTION_PROOF: DomainType = [0x05, 0x00, 0x00, 0x00]; +/// Domain for an `AggregateAndProof`. +pub const DOMAIN_AGGREGATE_AND_PROOF: DomainType = [0x06, 0x00, 0x00, 0x00]; +/// Reserves the non-zero bits of the `DomainType` bitspace for +/// application-specific domains outside the specification. Every +/// specification-defined `DomainType` masks to zero against this; a +/// `DomainType` that does not is reserved for other uses (for example +/// re-purposing beacon chain signatures on an application layer) and this +/// crate never produces or expects one. +pub const DOMAIN_APPLICATION_MASK: DomainType = [0x00, 0x00, 0x00, 0x01]; +/// Domain for a `SyncCommitteeMessage` (altair). +pub const DOMAIN_SYNC_COMMITTEE: DomainType = [0x07, 0x00, 0x00, 0x00]; +/// Domain for a sync committee aggregator's selection proof (altair). +pub const DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF: DomainType = [0x08, 0x00, 0x00, 0x00]; +/// Domain for a `ContributionAndProof` (altair). +pub const DOMAIN_CONTRIBUTION_AND_PROOF: DomainType = [0x09, 0x00, 0x00, 0x00]; +/// Domain for a `BLSToExecutionChange` (capella). Signed with the validator's +/// original BLS withdrawal key, proving ownership before switching +/// [`BLS_WITHDRAWAL_PREFIX`] credentials over to +/// [`ETH1_ADDRESS_WITHDRAWAL_PREFIX`]. +pub const DOMAIN_BLS_TO_EXECUTION_CHANGE: DomainType = [0x0a, 0x00, 0x00, 0x00]; + +// --------------------------------------------------------------------------- +// Participation flags and incentivization weights (altair) +// --------------------------------------------------------------------------- +// +// Altair replaces phase0's `PendingAttestation` bookkeeping with three +// per-validator, per-epoch bits (a `ParticipationFlags`), recording whether an +// attestation had the right source, target, and head, and how promptly it +// landed. `TIMELY_*_FLAG_INDEX` is the bit position within that +// `ParticipationFlags` byte for each of the three; `usize` because it is used +// as a shift amount and as an index, never SSZ-encoded on its own. + +/// Bit index recording a timely, correct attestation source. +pub const TIMELY_SOURCE_FLAG_INDEX: usize = 0; +/// Bit index recording a timely, correct attestation target. +pub const TIMELY_TARGET_FLAG_INDEX: usize = 1; +/// Bit index recording a timely, correct attestation head vote. +pub const TIMELY_HEAD_FLAG_INDEX: usize = 2; + +/// Reward share for a timely, correct source vote, out of [`WEIGHT_DENOMINATOR`]. +pub const TIMELY_SOURCE_WEIGHT: u64 = 14; +/// Reward share for a timely, correct target vote, out of [`WEIGHT_DENOMINATOR`]. +pub const TIMELY_TARGET_WEIGHT: u64 = 26; +/// Reward share for a timely, correct head vote, out of [`WEIGHT_DENOMINATOR`]. +pub const TIMELY_HEAD_WEIGHT: u64 = 14; +/// Reward share for participating in the current sync committee, out of +/// [`WEIGHT_DENOMINATOR`]. +pub const SYNC_REWARD_WEIGHT: u64 = 2; +/// Reward share paid to the block proposer for including attestations and +/// sync committee contributions, out of [`WEIGHT_DENOMINATOR`]. +pub const PROPOSER_WEIGHT: u64 = 8; +/// The denominator every `*_WEIGHT` constant is a numerator over. The weights +/// sum to this value exactly, so together they partition the whole reward. +pub const WEIGHT_DENOMINATOR: u64 = 64; + +/// [`TIMELY_SOURCE_WEIGHT`], [`TIMELY_TARGET_WEIGHT`], and +/// [`TIMELY_HEAD_WEIGHT`], indexed by [`TIMELY_SOURCE_FLAG_INDEX`], +/// [`TIMELY_TARGET_FLAG_INDEX`], and [`TIMELY_HEAD_FLAG_INDEX`] +/// respectively. `get_flag_index_deltas` walks this alongside the three flag +/// indices so the reward computation for each flag reads as one shared loop +/// rather than three near-identical copies. +pub const PARTICIPATION_FLAG_WEIGHTS: [u64; 3] = [ + TIMELY_SOURCE_WEIGHT, + TIMELY_TARGET_WEIGHT, + TIMELY_HEAD_WEIGHT, +]; + +// --------------------------------------------------------------------------- +// Fork choice (phase0) +// --------------------------------------------------------------------------- + +/// The number of sub-slot ticks the fork choice store used to divide a slot +/// into (attest, aggregate, and the next slot's boundary). Deprecated in +/// favor of the millisecond-precision basis-point timings +/// (`ATTESTATION_DUE_BPS` and friends, in [`crate::beacon::config`]), but the +/// specification still lists it, and older fixtures may reference it. +pub const INTERVALS_PER_SLOT: u64 = 3; + +/// The denominator the `*_DUE_BPS` configuration values (in [`crate::beacon::config`]) +/// are numerators over, i.e. ten thousand basis points to a whole slot. +/// `get_slot_component_duration_ms` divides by this to turn a basis-point +/// share into a millisecond offset into the slot. +pub const BASIS_POINTS: u64 = 10_000; + +// --------------------------------------------------------------------------- +// Blob (deneb) +// --------------------------------------------------------------------------- + +/// The size of one BLS scalar field element in bytes. +/// +/// A blob is a vector of field elements, so this is the factor relating a field +/// element count to a byte length: `BYTES_PER_BLOB` and `BYTES_PER_CELL` in +/// [`crate::beacon::preset`] are both derived from it. Fixed by the specification rather +/// than by preset, since it follows from the size of the BLS12-381 scalar field +/// and not from any network parameter. Bounds a `ByteVector`, hence `usize`. +pub const BYTES_PER_FIELD_ELEMENT: usize = 32; + +/// The version byte prepended to `hash(kzg_commitment)[1:]` to form a blob's +/// versioned hash. Lets the execution layer's transaction format distinguish +/// a KZG-backed versioned hash from other hash-derived identifiers it might +/// introduce later. +pub const VERSIONED_HASH_VERSION_KZG: u8 = 0x01; + +// --------------------------------------------------------------------------- +// Misc (electra) +// --------------------------------------------------------------------------- + +/// Sentinel for `BeaconState.deposit_requests_start_index`: "no execution +/// layer deposit request has set the start index yet". Deposits before this +/// point in the deposit contract's log are still processed from +/// `Eth1Data` votes; once an execution layer `DepositRequest` is seen, the +/// state records its index here and processes deposits from execution layer +/// requests onward instead. Typed `u64` to match the field itself, a plain +/// index counter rather than an `Epoch`. +pub const UNSET_DEPOSIT_REQUESTS_START_INDEX: u64 = u64::MAX; + +/// The amount that signals "withdraw this validator's entire balance" +/// (electra:EIP7002) rather than a partial withdrawal of the given amount. +/// Typed [`Gwei`], matching the `WithdrawalRequest.amount` field it is +/// compared against; the specification's own constants table writes it as a +/// plain `uint64`, but every place that reads it treats it as an amount. +pub const FULL_EXIT_REQUEST_AMOUNT: Gwei = 0; + +/// The first byte of an execution layer request list entry (electra:EIP7685) +/// that identifies it as a deposit request. `u8`: a single tag byte compared +/// directly against the request's type byte, never SSZ-encoded on its own. +pub const DEPOSIT_REQUEST_TYPE: u8 = 0x00; +/// The first byte identifying an execution layer request as a withdrawal +/// request. +pub const WITHDRAWAL_REQUEST_TYPE: u8 = 0x01; +/// The first byte identifying an execution layer request as a consolidation +/// request. +pub const CONSOLIDATION_REQUEST_TYPE: u8 = 0x02; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn participation_flag_weights_sum_to_the_denominator() { + // The specification calls this out explicitly ("the sum of the + // weights equal WEIGHT_DENOMINATOR"): together with SYNC_REWARD_WEIGHT + // and PROPOSER_WEIGHT, the three flag weights must partition the + // whole reward with nothing left over and nothing double-counted. + let total: u64 = + PARTICIPATION_FLAG_WEIGHTS.iter().sum::() + SYNC_REWARD_WEIGHT + PROPOSER_WEIGHT; + assert_eq!(total, WEIGHT_DENOMINATOR); + } + + #[test] + fn domain_application_mask_is_reserved_correctly() { + // Every specification-defined domain type must mask to zero: none of + // them are "application" domains. + for domain in [ + DOMAIN_BEACON_PROPOSER, + DOMAIN_BEACON_ATTESTER, + DOMAIN_RANDAO, + DOMAIN_DEPOSIT, + DOMAIN_VOLUNTARY_EXIT, + DOMAIN_SELECTION_PROOF, + DOMAIN_AGGREGATE_AND_PROOF, + DOMAIN_SYNC_COMMITTEE, + DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF, + DOMAIN_CONTRIBUTION_AND_PROOF, + DOMAIN_BLS_TO_EXECUTION_CHANGE, + ] { + let masked = [ + domain[0] & DOMAIN_APPLICATION_MASK[0], + domain[1] & DOMAIN_APPLICATION_MASK[1], + domain[2] & DOMAIN_APPLICATION_MASK[2], + domain[3] & DOMAIN_APPLICATION_MASK[3], + ]; + assert_eq!(masked, [0, 0, 0, 0]); + } + } +} diff --git a/crates/common/types/src/beacon/containers/altair.rs b/crates/common/types/src/beacon/containers/altair.rs new file mode 100644 index 000000000..d90407792 --- /dev/null +++ b/crates/common/types/src/beacon/containers/altair.rs @@ -0,0 +1,353 @@ +//! Containers whose shape is specific to altair. +//! +//! Altair's headline change is sync committees: a small, rotating subset of the +//! validator set that signs every block so a light client can follow the +//! chain's head from a single, cheaply verifiable aggregate rather than +//! replaying full state transitions. [`SyncAggregate`] carries the per-block +//! result into [`BeaconBlockBody`], [`SyncCommittee`] carries the current and +//! next committees into [`BeaconState`], and the remaining containers here are +//! the off-chain messages a sync committee member and its aggregator exchange +//! over gossip to produce one: [`SyncCommitteeMessage`], +//! [`SyncCommitteeContribution`], [`ContributionAndProof`], +//! [`SignedContributionAndProof`], and [`SyncAggregatorSelectionData`]. Those +//! five are transcribed from `validator.md` rather than `beacon-chain.md`, +//! since the specification splits sync committee duties into their own +//! document the same way it does phase0's attestation duties. +//! +//! The other change is incentive accounting: altair replaces phase0's +//! accumulate-then-replay attestations with per-validator participation flags +//! recorded as each attestation is processed. Concretely, [`BeaconState`] drops +//! `previous_epoch_attestations` and `current_epoch_attestations` and puts +//! `previous_epoch_participation` and `current_epoch_participation` in the exact +//! same two slots, so this is a type change in place, not an appended pair. +//! Altair then appends `inactivity_scores` and the two sync committee fields +//! after `finalized_checkpoint`. +//! +//! Attestations themselves ([`super::phase0::Attestation`], +//! [`super::phase0::AttesterSlashing`]) are unchanged in altair, so this module +//! imports them rather than redefining them. Electra is where they next change +//! shape; do not go looking for altair-specific versions of them. + +use libssz_derive::{HashTreeRoot, SszDecode, SszEncode}; +use libssz_types::{SszBitvector, SszList, SszVector}; + +use super::phase0::{Attestation, AttesterSlashing}; +use super::shared::{ + Balances, BlockRoots, EpochParticipation, Eth1DataVotes, HistoricalRoots, InactivityScores, + JustificationBits, RandaoMixes, Slashings, StateRoots, Validators, +}; +use super::shared::{ + BeaconBlockHeader, Checkpoint, Deposit, Eth1Data, Fork, ProposerSlashing, SignedVoluntaryExit, +}; +use crate::beacon::preset; +use crate::beacon::primitives::{BlsPubkey, BlsSignature, Bytes32, Root, Slot, ValidatorIndex}; + +/// One bit per sync committee member, recording who contributed to a +/// [`SyncAggregate`]. +pub type SyncCommitteeBits = SszBitvector<{ preset::SYNC_COMMITTEE_SIZE }>; + +/// The public keys making up a sync committee, one per seat. +/// +/// May contain duplicates: `get_next_sync_committee_indices` draws seats with +/// replacement weighted by effective balance, so one validator can hold more +/// than one seat in the same committee. +pub type SyncCommitteePubkeys = SszVector; + +/// How many gossipsub subnets the sync committee aggregation protocol splits a +/// sync committee into, so that a [`SyncCommitteeContribution`] only has to +/// cover one subcommittee rather than the whole committee. +/// +/// This is a fixed specification constant (`validator.md`'s "Constants", +/// mirrored the same in the mainnet and minimal presets), not a preset value, +/// so by this crate's own convention it belongs in `crate::beacon::constants` alongside +/// `JUSTIFICATION_BITS_LENGTH`. It is defined here instead, as a judgment call, +/// because it does not exist anywhere in the crate yet and this file is not +/// permitted to add it to `constants.rs`; whoever owns that module should move +/// it there. +const SYNC_COMMITTEE_SUBNET_COUNT: usize = 4; + +/// One bit per member of a single sync subcommittee (one +/// `SYNC_COMMITTEE_SUBNET_COUNT`th of a full sync committee), recording who +/// contributed to one [`SyncCommitteeContribution`]. +pub type SyncSubcommitteeBits = + SszBitvector<{ preset::SYNC_COMMITTEE_SIZE / SYNC_COMMITTEE_SUBNET_COUNT }>; + +// --------------------------------------------------------------------------- +// Sync committees +// --------------------------------------------------------------------------- + +/// A block's summary of sync committee participation: who signed, and the +/// resulting aggregate signature. +/// +/// Carried in every altair-and-later [`BeaconBlockBody`], since every block +/// needs one regardless of how many attestations or other operations it +/// includes. +#[derive(Debug, Clone, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SyncAggregate { + pub sync_committee_bits: SyncCommitteeBits, + /// The aggregate of every signature from a member set in + /// `sync_committee_bits`, over the previous slot's block root. + pub sync_committee_signature: BlsSignature, +} + +/// The committee currently responsible for signing sync aggregates, plus its +/// combined key precomputed for the common case where every member +/// participates. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SyncCommittee { + pub pubkeys: SyncCommitteePubkeys, + /// The aggregate of every key in `pubkeys`, so `process_sync_aggregate` does + /// not have to re-aggregate from scratch when the whole committee signs. + pub aggregate_pubkey: BlsPubkey, +} + +// --------------------------------------------------------------------------- +// Blocks +// --------------------------------------------------------------------------- + +/// The contents of a block: phase0's operations, plus the sync committee's +/// contribution to this block. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconBlockBody { + /// The proposer's contribution to the chain's randomness, which is a + /// signature over the current epoch and so cannot be chosen freely. + pub randao_reveal: BlsSignature, + /// The proposer's vote on the execution chain's deposit state. + pub eth1_data: Eth1Data, + /// Arbitrary proposer-chosen bytes, which consensus never reads. + pub graffiti: Bytes32, + pub proposer_slashings: SszList, + pub attester_slashings: SszList, + pub attestations: SszList, + pub deposits: SszList, + pub voluntary_exits: SszList, + /// The aggregated sync committee signature over the previous slot's block + /// root, plus which members contributed. This is what lets a light client + /// trust the chain's head without processing every block: it only has to + /// check that a supermajority of a known committee signed. + pub sync_aggregate: SyncAggregate, +} + +/// A block. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconBlock { + pub slot: Slot, + pub proposer_index: ValidatorIndex, + pub parent_root: Root, + /// The root of the state after this block is applied, which the state + /// transition recomputes and compares. + pub state_root: Root, + pub body: BeaconBlockBody, +} + +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SignedBeaconBlock { + pub message: BeaconBlock, + pub signature: BlsSignature, +} + +// --------------------------------------------------------------------------- +// State +// --------------------------------------------------------------------------- + +/// The altair beacon state: 24 fields, in the specification's order. +/// +/// Field order is load-bearing. SSZ encoding and merkleization both follow +/// declaration order, so reordering or omitting a field silently produces a +/// wrong `hash_tree_root`. +/// +/// Fields through `slashings` are identical to phase0's, field for field. From +/// there, altair replaces phase0's `previous_epoch_attestations` and +/// `current_epoch_attestations` (`List`) with +/// `previous_epoch_participation` and `current_epoch_participation` +/// (`List`) in those same two positions, keeps +/// `justification_bits` through `finalized_checkpoint` unchanged, and appends +/// `inactivity_scores`, `current_sync_committee`, and `next_sync_committee`. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconState { + // -- Versioning -- + pub genesis_time: u64, + /// The root of the genesis validator registry, which separates this chain + /// from any other running the same fork schedule. + pub genesis_validators_root: Root, + pub slot: Slot, + pub fork: Fork, + + // -- History -- + /// The most recent block's header, with `state_root` left zero until the + /// slot advances, since a block cannot commit to the root of the state + /// containing it. + pub latest_block_header: BeaconBlockHeader, + pub block_roots: BlockRoots, + pub state_roots: StateRoots, + pub historical_roots: HistoricalRoots, + + // -- Eth1 -- + pub eth1_data: Eth1Data, + pub eth1_data_votes: Eth1DataVotes, + /// How many deposits from the contract have been processed, which is where + /// the next one will be read from. + pub eth1_deposit_index: u64, + + // -- Registry -- + pub validators: Validators, + pub balances: Balances, + + // -- Randomness -- + pub randao_mixes: RandaoMixes, + + // -- Slashings -- + pub slashings: Slashings, + + // -- Participation -- + /// Per-validator participation flags for the previous epoch, positionally + /// parallel to `validators`. Occupies the position phase0 gives + /// `previous_epoch_attestations`: altair scores an attestation the moment + /// it is processed instead of deferring to the epoch boundary, so there is + /// no longer a backlog of whole attestations to keep around, only a flag + /// per validator per epoch. + pub previous_epoch_participation: EpochParticipation, + /// Flags for the current epoch, which become `previous_epoch_participation` + /// at the next epoch boundary. + pub current_epoch_participation: EpochParticipation, + + // -- Finality -- + pub justification_bits: JustificationBits, + pub previous_justified_checkpoint: Checkpoint, + pub current_justified_checkpoint: Checkpoint, + pub finalized_checkpoint: Checkpoint, + + // -- Inactivity -- + /// Per-validator inactivity score, positionally parallel to `validators`. + /// Rises for a validator that misses the timely-target flag during a + /// non-finalizing epoch and falls otherwise, which is what lets the + /// inactivity leak single out validators who are actually offline rather + /// than penalizing everyone during a stall. + pub inactivity_scores: InactivityScores, + + // -- Sync committees -- + /// The committee currently signing sync aggregates. + pub current_sync_committee: SyncCommittee, + /// The committee that takes over from `current_sync_committee` at the next + /// sync committee period boundary. Precomputing it one period ahead is what + /// lets a light client know the next committee before it needs it. + pub next_sync_committee: SyncCommittee, +} + +// --------------------------------------------------------------------------- +// Validator-side containers +// --------------------------------------------------------------------------- +// +// These five are gossiped between sync committee members and their +// aggregators, never stored in the state or a block body, and are transcribed +// from `validator.md` rather than `beacon-chain.md`. + +/// One sync committee member's vote for a slot's block root, before +/// aggregation. +/// +/// The sync committee analogue of a phase0 attestation, but unaggregated: a +/// committee member gossips one of these every slot, and an aggregator +/// combines a subcommittee's worth into a [`SyncCommitteeContribution`]. +#[derive(Debug, Clone, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SyncCommitteeMessage { + pub slot: Slot, + pub beacon_block_root: Root, + pub validator_index: ValidatorIndex, + pub signature: BlsSignature, +} + +/// An aggregator's combination of one subcommittee's [`SyncCommitteeMessage`]s +/// for a slot. +/// +/// Scoped to `subcommittee_index` rather than the whole committee, because +/// `SYNC_COMMITTEE_SUBNET_COUNT` aggregators work in parallel on disjoint +/// slices of the committee, the same way phase0 attestation aggregation is +/// scoped to one committee rather than the whole active set. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SyncCommitteeContribution { + pub slot: Slot, + pub beacon_block_root: Root, + pub subcommittee_index: u64, + pub aggregation_bits: SyncSubcommitteeBits, + /// The aggregate signature of every member set in `aggregation_bits`, over + /// `beacon_block_root`. + pub signature: BlsSignature, +} + +/// A [`SyncCommitteeContribution`] together with proof that its aggregator was +/// selected to produce it. +/// +/// The sync committee analogue of phase0's `AggregateAndProof`. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct ContributionAndProof { + pub aggregator_index: ValidatorIndex, + pub contribution: SyncCommitteeContribution, + /// The aggregator's signature over the selection data, which is what makes + /// selection verifiable rather than self-declared. + pub selection_proof: BlsSignature, +} + +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SignedContributionAndProof { + pub message: ContributionAndProof, + pub signature: BlsSignature, +} + +/// What a prospective sync committee aggregator signs to prove it was +/// selected, before it has anything to aggregate yet. +/// +/// Separate from [`ContributionAndProof::selection_proof`]'s signature target +/// only in name: this is the unsigned message that signature covers. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SyncAggregatorSelectionData { + pub slot: Slot, + pub subcommittee_index: u64, +} + +#[cfg(test)] +mod tests { + use libssz::{SszDecode as _, SszEncode as _}; + + use super::*; + + #[test] + fn sync_committee_and_aggregate_are_fixed_size() { + // A sync committee is a vector of pubkeys plus one more pubkey, and a + // sync aggregate is a bitvector plus a signature: nothing + // variable-length in either, unlike the block body and state that + // carry them. + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + } + + #[test] + fn variable_length_containers_carry_offsets() { + // The state and the body each hold at least one list, so both begin + // their encoding with offsets rather than a fixed layout, and the + // block inherits that from its body. + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + } + + #[test] + fn block_body_round_trips_while_empty() { + // An empty body is the common case for a skipped-operation slot, and it + // exercises every offset in the encoding with zero-length payloads, + // plus the fixed-size sync aggregate altair adds alongside them. + let body = BeaconBlockBody { + randao_reveal: BlsSignature::default(), + eth1_data: Eth1Data::default(), + graffiti: Bytes32::ZERO, + proposer_slashings: Default::default(), + attester_slashings: Default::default(), + attestations: Default::default(), + deposits: Default::default(), + voluntary_exits: Default::default(), + sync_aggregate: SyncAggregate::default(), + }; + + let bytes = body.to_ssz(); + assert_eq!(BeaconBlockBody::from_ssz_bytes(&bytes).unwrap(), body); + } +} diff --git a/crates/common/types/src/beacon/containers/bellatrix.rs b/crates/common/types/src/beacon/containers/bellatrix.rs new file mode 100644 index 000000000..2107aa690 --- /dev/null +++ b/crates/common/types/src/beacon/containers/bellatrix.rs @@ -0,0 +1,371 @@ +//! Containers whose shape is specific to bellatrix. +//! +//! Bellatrix is the merge: block production moves from proof-of-work mining on +//! the execution side to proposal by the beacon chain's validators, and the +//! execution chain's block becomes an opaque payload the beacon block carries +//! rather than a chain validated on its own. Concretely, [`BeaconBlockBody`] +//! appends `execution_payload`, an [`ExecutionPayload`], and [`BeaconState`] +//! appends `latest_execution_payload_header`, an [`ExecutionPayloadHeader`]: +//! the header is what lets a later payload be checked against the one before +//! it (its `parent_hash` must chain to the header's `block_hash`) without the +//! state having to keep the whole payload, transactions included, around. +//! +//! [`ExecutionPayloadHeader`] is otherwise identical to [`ExecutionPayload`]: +//! it replaces `transactions` with `transactions_root`, the same substitution +//! [`super::shared::BeaconBlockHeader`] makes for a beacon block's body. +//! +//! [`PowBlock`] is unrelated to either: it is transcribed from +//! `fork-choice.md` rather than `beacon-chain.md`, and exists only to let fork +//! choice check a candidate terminal proof-of-work block's total difficulty +//! against `TERMINAL_TOTAL_DIFFICULTY` while validating the merge transition +//! block, the one time consensus has to reason about a chain it does not +//! itself produce. +//! +//! Everything else bellatrix touches, sync committees, attestations, and the +//! rest of the block body and state, is unchanged from altair, so this module +//! imports rather than redefines it. + +use libssz_derive::{HashTreeRoot, SszDecode, SszEncode}; +use libssz_types::{SszList, SszVector}; + +use super::altair::{SyncAggregate, SyncCommittee}; +use super::phase0::{Attestation, AttesterSlashing}; +use super::shared::{ + Balances, BeaconBlockHeader, BlockRoots, Checkpoint, Deposit, EpochParticipation, Eth1Data, + Eth1DataVotes, Fork, HistoricalRoots, InactivityScores, JustificationBits, ProposerSlashing, + RandaoMixes, SignedVoluntaryExit, Slashings, StateRoots, Validators, +}; +use crate::beacon::preset; +use crate::beacon::primitives::{ + BlsSignature, Bytes32, ExecutionAddress, ExecutionBlockHash, Root, Slot, Uint256, + ValidatorIndex, +}; + +// --------------------------------------------------------------------------- +// Execution payload collection aliases +// --------------------------------------------------------------------------- +// +// A const-generic argument that is a path needs braces, so these read +// `{ preset::X }` rather than `preset::X`. + +/// One execution-layer transaction, opaque to consensus. +/// +/// The specification's `ByteList[MAX_BYTES_PER_TRANSACTION]` rather than a +/// structured type, since consensus never decodes a transaction; it only +/// carries the bytes the execution engine will. +pub type Transaction = SszList; + +/// The transactions in one [`ExecutionPayload`], in execution order. +pub type Transactions = SszList; + +/// Arbitrary proposer-chosen bytes on the execution side of a payload, the +/// execution analogue of a beacon block's `graffiti`. +pub type ExtraData = SszList; + +/// A Bloom filter summarizing this payload's transaction logs, fixed-length +/// because it is a filter rather than a list of entries. +pub type LogsBloom = SszVector; + +// --------------------------------------------------------------------------- +// Execution payload +// --------------------------------------------------------------------------- + +/// An execution block, carried inside a [`BeaconBlockBody`] rather than +/// gossiped and validated on its own chain. +/// +/// Field order and naming otherwise follow the execution block header; the +/// specification notes that `fee_recipient`, `prev_randao`, and +/// `block_number` correspond to `beneficiary`, `difficulty`, and `number` in +/// the yellow paper, carried over under new names now that consensus, not +/// proof-of-work mining, produces them. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct ExecutionPayload { + pub parent_hash: ExecutionBlockHash, + /// Where this block's fees are paid; `beneficiary` in the yellow paper. + pub fee_recipient: ExecutionAddress, + /// The execution layer's post-state root, unrelated to the beacon block's + /// own `state_root`. + pub state_root: Bytes32, + pub receipts_root: Bytes32, + pub logs_bloom: LogsBloom, + /// The randomness the beacon chain exposes to the EVM for this block; + /// `difficulty` in the yellow paper before the merge repurposed the + /// field, since proof-of-work difficulty no longer exists. + pub prev_randao: Bytes32, + pub block_number: u64, + pub gas_limit: u64, + pub gas_used: u64, + pub timestamp: u64, + pub extra_data: ExtraData, + /// This block's EIP-1559 base fee, a `uint256` because the execution + /// layer's fee market is not bounded to fit a `uint64`. + pub base_fee_per_gas: Uint256, + /// This payload's own hash, which the next payload's `parent_hash` must + /// equal. + pub block_hash: ExecutionBlockHash, + pub transactions: Transactions, +} + +/// An [`ExecutionPayload`] with its transaction list replaced by a merkle +/// root, so [`BeaconState::latest_execution_payload_header`] can commit to +/// the previous payload without the state growing with every transaction +/// ever included. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct ExecutionPayloadHeader { + pub parent_hash: ExecutionBlockHash, + pub fee_recipient: ExecutionAddress, + pub state_root: Bytes32, + pub receipts_root: Bytes32, + pub logs_bloom: LogsBloom, + pub prev_randao: Bytes32, + pub block_number: u64, + pub gas_limit: u64, + pub gas_used: u64, + pub timestamp: u64, + pub extra_data: ExtraData, + pub base_fee_per_gas: Uint256, + /// The hash of the execution block this header summarizes. + pub block_hash: ExecutionBlockHash, + /// The root of the full transaction list [`ExecutionPayload::transactions`] + /// would have carried, so the header stays a fixed shape regardless of + /// how many transactions the block had. + pub transactions_root: Root, +} + +// --------------------------------------------------------------------------- +// Blocks +// --------------------------------------------------------------------------- + +/// The contents of a block: altair's operations, plus this slot's execution +/// payload. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconBlockBody { + /// The proposer's contribution to the chain's randomness, which is a + /// signature over the current epoch and so cannot be chosen freely. + pub randao_reveal: BlsSignature, + /// The proposer's vote on the execution chain's deposit state. + pub eth1_data: Eth1Data, + /// Arbitrary proposer-chosen bytes, which consensus never reads. + pub graffiti: Bytes32, + pub proposer_slashings: SszList, + pub attester_slashings: SszList, + pub attestations: SszList, + pub deposits: SszList, + pub voluntary_exits: SszList, + /// The aggregated sync committee signature over the previous slot's block + /// root, plus which members contributed. + pub sync_aggregate: SyncAggregate, + /// This slot's execution block, carried rather than referenced, since a + /// beacon block and the execution block it produces are proposed and + /// gossiped together. + pub execution_payload: ExecutionPayload, +} + +/// A block. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconBlock { + pub slot: Slot, + pub proposer_index: ValidatorIndex, + pub parent_root: Root, + /// The root of the state after this block is applied, which the state + /// transition recomputes and compares. + pub state_root: Root, + pub body: BeaconBlockBody, +} + +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SignedBeaconBlock { + pub message: BeaconBlock, + pub signature: BlsSignature, +} + +// --------------------------------------------------------------------------- +// State +// --------------------------------------------------------------------------- + +/// The bellatrix beacon state: 25 fields, in the specification's order. +/// +/// Field order is load-bearing. SSZ encoding and merkleization both follow +/// declaration order, so reordering or omitting a field silently produces a +/// wrong `hash_tree_root`. +/// +/// Every field through `next_sync_committee` is identical to altair's, field +/// for field. Bellatrix appends `latest_execution_payload_header`, which is +/// what lets `process_execution_payload` check a proposed block's payload +/// chains to the one actually applied, without the state keeping a full +/// payload's transactions around. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconState { + // -- Versioning -- + pub genesis_time: u64, + /// The root of the genesis validator registry, which separates this chain + /// from any other running the same fork schedule. + pub genesis_validators_root: Root, + pub slot: Slot, + pub fork: Fork, + + // -- History -- + /// The most recent block's header, with `state_root` left zero until the + /// slot advances, since a block cannot commit to the root of the state + /// containing it. + pub latest_block_header: BeaconBlockHeader, + pub block_roots: BlockRoots, + pub state_roots: StateRoots, + pub historical_roots: HistoricalRoots, + + // -- Eth1 -- + pub eth1_data: Eth1Data, + pub eth1_data_votes: Eth1DataVotes, + /// How many deposits from the contract have been processed, which is where + /// the next one will be read from. + pub eth1_deposit_index: u64, + + // -- Registry -- + pub validators: Validators, + pub balances: Balances, + + // -- Randomness -- + pub randao_mixes: RandaoMixes, + + // -- Slashings -- + pub slashings: Slashings, + + // -- Participation -- + /// Per-validator participation flags for the previous epoch, positionally + /// parallel to `validators`. + pub previous_epoch_participation: EpochParticipation, + /// Flags for the current epoch, which become `previous_epoch_participation` + /// at the next epoch boundary. + pub current_epoch_participation: EpochParticipation, + + // -- Finality -- + pub justification_bits: JustificationBits, + pub previous_justified_checkpoint: Checkpoint, + pub current_justified_checkpoint: Checkpoint, + pub finalized_checkpoint: Checkpoint, + + // -- Inactivity -- + /// Per-validator inactivity score, positionally parallel to `validators`. + pub inactivity_scores: InactivityScores, + + // -- Sync committees -- + /// The committee currently signing sync aggregates. + pub current_sync_committee: SyncCommittee, + /// The committee that takes over from `current_sync_committee` at the next + /// sync committee period boundary. + pub next_sync_committee: SyncCommittee, + + // -- Execution -- + /// A commitment to the most recently applied execution payload, so a + /// later block's payload can be checked against it without the state + /// keeping the whole payload around. + pub latest_execution_payload_header: ExecutionPayloadHeader, +} + +// --------------------------------------------------------------------------- +// Fork choice +// --------------------------------------------------------------------------- +// +// Transcribed from `fork-choice.md` rather than `beacon-chain.md`, since it +// belongs to the merge transition handshake rather than to ordinary block +// processing. + +/// One execution-layer (proof-of-work) block, as reported by +/// `get_pow_block`. +/// +/// Fork choice's `is_valid_terminal_pow_block` uses this to check a candidate +/// merge transition block's total difficulty against +/// `TERMINAL_TOTAL_DIFFICULTY`, and its parent's difficulty against the same +/// bound, which is what pins the merge to one specific proof-of-work block +/// rather than any block heavy enough on its own. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct PowBlock { + pub block_hash: ExecutionBlockHash, + pub parent_hash: ExecutionBlockHash, + /// The cumulative proof-of-work difficulty of the chain up to and + /// including this block, which is what `TERMINAL_TOTAL_DIFFICULTY` + /// bounds. + pub total_difficulty: Uint256, +} + +#[cfg(test)] +mod tests { + use libssz::{SszDecode as _, SszEncode as _}; + + use super::*; + + /// Builds an otherwise-empty payload with a correctly sized, all-zero + /// `logs_bloom`, since [`LogsBloom`] is a fixed-length vector rather than + /// a list and so has no `Default`. + fn empty_execution_payload() -> ExecutionPayload { + ExecutionPayload { + parent_hash: ExecutionBlockHash::ZERO, + fee_recipient: ExecutionAddress::ZERO, + state_root: Bytes32::ZERO, + receipts_root: Bytes32::ZERO, + logs_bloom: LogsBloom::try_from(vec![0u8; preset::BYTES_PER_LOGS_BLOOM]).unwrap(), + prev_randao: Bytes32::ZERO, + block_number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: 0, + extra_data: Default::default(), + base_fee_per_gas: Uint256::ZERO, + block_hash: ExecutionBlockHash::ZERO, + transactions: Default::default(), + } + } + + #[test] + fn sync_committee_and_pow_block_are_fixed_size() { + // A sync committee is unchanged from altair, and a pow block is three + // fixed-width fields: neither carries anything variable-length, unlike + // the execution payload, block, and state that surround them. + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + } + + #[test] + fn variable_length_containers_carry_offsets() { + // Both the payload and its header hold `extra_data`, a list, so even + // the header (whose `transactions_root` is fixed-size) begins its + // encoding with offsets. The state and body inherit variability the + // same way altair's do, now compounded by the payload they carry. + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + } + + #[test] + fn execution_payload_round_trips_while_empty() { + let payload = empty_execution_payload(); + + let bytes = payload.to_ssz(); + assert_eq!(ExecutionPayload::from_ssz_bytes(&bytes).unwrap(), payload); + } + + #[test] + fn block_body_round_trips_while_empty() { + // An empty body is the common case for a skipped-operation slot, and it + // exercises every offset in the encoding with zero-length payloads, + // plus the fixed-size sync aggregate and the execution payload + // bellatrix adds alongside them. + let body = BeaconBlockBody { + randao_reveal: BlsSignature::default(), + eth1_data: Eth1Data::default(), + graffiti: Bytes32::ZERO, + proposer_slashings: Default::default(), + attester_slashings: Default::default(), + attestations: Default::default(), + deposits: Default::default(), + voluntary_exits: Default::default(), + sync_aggregate: SyncAggregate::default(), + execution_payload: empty_execution_payload(), + }; + + let bytes = body.to_ssz(); + assert_eq!(BeaconBlockBody::from_ssz_bytes(&bytes).unwrap(), body); + } +} diff --git a/crates/common/types/src/beacon/containers/capella.rs b/crates/common/types/src/beacon/containers/capella.rs new file mode 100644 index 000000000..136eae291 --- /dev/null +++ b/crates/common/types/src/beacon/containers/capella.rs @@ -0,0 +1,417 @@ +//! Containers whose shape is specific to capella. +//! +//! Capella's headline change is validator withdrawals: until this fork, a +//! validator's stake could shrink (via slashing or penalties) but never leave +//! the consensus layer, since there was nowhere for it to go. Capella gives it +//! somewhere to go by having every block sweep a bounded slice of the +//! validator registry for anyone who is fully or partially withdrawable and +//! pay them out on the execution side. Concretely: [`ExecutionPayload`] and +//! [`ExecutionPayloadHeader`] gain a `withdrawals`/`withdrawals_root` field so +//! the payout is part of the execution block, [`Withdrawal`] is the payout +//! itself, and [`BeaconState`] gains `next_withdrawal_index` and +//! `next_withdrawal_validator_index` as the sweep's persistent cursor. Keeping +//! a cursor rather than rescanning the whole registry every block is what +//! bounds the sweep's cost regardless of how large the registry grows. +//! [`BLSToExecutionChange`] and [`SignedBLSToExecutionChange`] are the other +//! new operation: a one-time switch from a raw BLS withdrawal credential to +//! an execution address, which is what makes a validator eligible for the +//! sweep in the first place. +//! +//! The other change is `historical_summaries`, imported unchanged from +//! [`super::shared`] rather than redefined here: `historical_roots` is frozen +//! in place at its bellatrix position and slot, and `historical_summaries` +//! takes over accumulating new history from this fork on. The specification +//! notes the two are `hash_tree_root`-compatible (a [`super::shared::HistoricalSummary`] +//! has the same two fields as phase0's `HistoricalBatch`), which is what lets a +//! verifier that only knows one of the two forms still check a historical +//! proof against either. +//! +//! [`ExtraData`], [`LogsBloom`], and [`Transactions`] are unchanged from +//! bellatrix, so this module imports them rather than redefining them. +//! [`ExecutionPayload`] and [`ExecutionPayloadHeader`] themselves are not +//! imported, since every field of both is repeated here with `withdrawals` +//! (respectively `withdrawals_root`) appended, and a derive needs the whole +//! field list in one struct. + +use libssz_derive::{HashTreeRoot, SszDecode, SszEncode}; +use libssz_types::SszList; + +use super::altair::{SyncAggregate, SyncCommittee}; +use super::bellatrix::{ExtraData, LogsBloom, Transactions}; +use super::phase0::{Attestation, AttesterSlashing}; +use super::shared::{ + Balances, BeaconBlockHeader, BlockRoots, Checkpoint, Deposit, EpochParticipation, Eth1Data, + Eth1DataVotes, Fork, HistoricalRoots, HistoricalSummaries, InactivityScores, JustificationBits, + ProposerSlashing, RandaoMixes, SignedVoluntaryExit, Slashings, StateRoots, Validators, +}; +use crate::beacon::preset; +use crate::beacon::primitives::{ + BlsPubkey, BlsSignature, Bytes32, ExecutionAddress, ExecutionBlockHash, Gwei, Root, Slot, + Uint256, ValidatorIndex, WithdrawalIndex, +}; + +/// Withdrawals a block applies, bounded the same way every other operation +/// list is. +/// +/// Unlike the other lists in [`BeaconBlockBody`], a proposer does not choose +/// these: `process_withdrawals` recomputes the expected set from the sweep +/// cursor and rejects a block whose `withdrawals` does not match exactly. +pub type Withdrawals = SszList; + +// --------------------------------------------------------------------------- +// New containers +// --------------------------------------------------------------------------- + +/// One validator's payout, included in an [`ExecutionPayload`] and applied by +/// decreasing the validator's balance by `amount`. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct Withdrawal { + /// This withdrawal's position in the chain-wide withdrawal sequence, + /// monotonically increasing and never reused. + pub index: WithdrawalIndex, + pub validator_index: ValidatorIndex, + /// Where the payout is sent, taken from the low bytes of the validator's + /// eth1 withdrawal credentials. + pub address: ExecutionAddress, + pub amount: Gwei, +} + +/// A validator's one-time request to switch its withdrawal credentials from a +/// raw BLS public key hash to an execution address. +/// +/// Before this operation, a validator's withdrawal credentials commit only to +/// a BLS key, which the execution layer has no way to pay out to. Processing +/// it is what makes a validator eligible for the withdrawal sweep at all: the +/// sweep only considers credentials already in the eth1 form this operation +/// produces. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BLSToExecutionChange { + pub validator_index: ValidatorIndex, + /// The key whose hash the validator's current withdrawal credentials must + /// match, proving whoever submits this message actually controls them. + pub from_bls_pubkey: BlsPubkey, + pub to_execution_address: ExecutionAddress, +} + +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SignedBLSToExecutionChange { + pub message: BLSToExecutionChange, + pub signature: BlsSignature, +} + +// --------------------------------------------------------------------------- +// Execution payload +// --------------------------------------------------------------------------- + +/// The execution layer's block contents, carried inside [`BeaconBlockBody`]. +/// +/// Bellatrix's payload, with `withdrawals` appended: an execution block can +/// now retire validator balances directly, so the payload has to carry the +/// withdrawals it applies alongside the transactions it applies. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct ExecutionPayload { + pub parent_hash: ExecutionBlockHash, + pub fee_recipient: ExecutionAddress, + /// The execution layer's own state root, unrelated to the enclosing + /// [`BeaconBlock`]'s `state_root`: the two layers keep separate state and + /// neither commits to the other's. + pub state_root: Bytes32, + pub receipts_root: Bytes32, + pub logs_bloom: LogsBloom, + /// The randao mix consensus supplied for this slot, which the execution + /// layer must be given so it can be verified against + /// `get_randao_mix(state, get_current_epoch(state))`. + pub prev_randao: Bytes32, + pub block_number: u64, + pub gas_limit: u64, + pub gas_used: u64, + pub timestamp: u64, + /// Arbitrary bytes the execution client attaches to the block; consensus + /// never reads them. + pub extra_data: ExtraData, + pub base_fee_per_gas: Uint256, + pub block_hash: ExecutionBlockHash, + pub transactions: Transactions, + /// The payouts this block applies, computed deterministically by + /// `get_expected_withdrawals` from the state's sweep cursor rather than + /// chosen by the proposer. + pub withdrawals: Withdrawals, +} + +/// What the state retains of an [`ExecutionPayload`] after processing it: the +/// same fields, but with `transactions` and `withdrawals` replaced by their +/// roots so the state does not have to keep every payload in full forever. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct ExecutionPayloadHeader { + pub parent_hash: ExecutionBlockHash, + pub fee_recipient: ExecutionAddress, + pub state_root: Bytes32, + pub receipts_root: Bytes32, + pub logs_bloom: LogsBloom, + pub prev_randao: Bytes32, + pub block_number: u64, + pub gas_limit: u64, + pub gas_used: u64, + pub timestamp: u64, + pub extra_data: ExtraData, + pub base_fee_per_gas: Uint256, + pub block_hash: ExecutionBlockHash, + /// The merkle root of the corresponding [`ExecutionPayload::transactions`]. + pub transactions_root: Root, + /// The merkle root of the corresponding [`ExecutionPayload::withdrawals`]. + pub withdrawals_root: Root, +} + +// --------------------------------------------------------------------------- +// Blocks +// --------------------------------------------------------------------------- + +/// The contents of a block: bellatrix's operations, plus a validator's +/// withdrawal credential switch. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconBlockBody { + /// The proposer's contribution to the chain's randomness, which is a + /// signature over the current epoch and so cannot be chosen freely. + pub randao_reveal: BlsSignature, + /// The proposer's vote on the execution chain's deposit state. + pub eth1_data: Eth1Data, + /// Arbitrary proposer-chosen bytes, which consensus never reads. + pub graffiti: Bytes32, + pub proposer_slashings: SszList, + pub attester_slashings: SszList, + pub attestations: SszList, + pub deposits: SszList, + pub voluntary_exits: SszList, + /// The aggregated sync committee signature over the previous slot's block + /// root, plus which members contributed. + pub sync_aggregate: SyncAggregate, + /// The execution layer block this beacon block wraps. + pub execution_payload: ExecutionPayload, + /// A validator's one-time withdrawal credential switch, capella's new + /// operation type. `process_operations` runs it last, the same position it + /// holds here, so it never affects this same slot's withdrawal sweep: that + /// sweep already ran, against whatever credentials were in effect before + /// this block. + pub bls_to_execution_changes: + SszList, +} + +/// A block. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconBlock { + pub slot: Slot, + pub proposer_index: ValidatorIndex, + pub parent_root: Root, + /// The root of the state after this block is applied, which the state + /// transition recomputes and compares. + pub state_root: Root, + pub body: BeaconBlockBody, +} + +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SignedBeaconBlock { + pub message: BeaconBlock, + pub signature: BlsSignature, +} + +// --------------------------------------------------------------------------- +// State +// --------------------------------------------------------------------------- + +/// The capella beacon state: 28 fields, in the specification's order. +/// +/// Field order is load-bearing. SSZ encoding and merkleization both follow +/// declaration order, so reordering or omitting a field silently produces a +/// wrong `hash_tree_root`. +/// +/// Fields through `next_sync_committee` are identical to bellatrix's, field for +/// field, including `historical_roots`: it keeps its bellatrix position but is +/// frozen from this fork on, since `historical_summaries` (appended below) is +/// where new history accumulates instead. `latest_execution_payload_header` +/// also keeps its name and position, but changes type: it is this module's own +/// [`ExecutionPayloadHeader`], with `withdrawals_root` appended, not +/// bellatrix's. Capella then appends `next_withdrawal_index`, +/// `next_withdrawal_validator_index`, and `historical_summaries`. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconState { + // -- Versioning -- + pub genesis_time: u64, + /// The root of the genesis validator registry, which separates this chain + /// from any other running the same fork schedule. + pub genesis_validators_root: Root, + pub slot: Slot, + pub fork: Fork, + + // -- History -- + /// The most recent block's header, with `state_root` left zero until the + /// slot advances, since a block cannot commit to the root of the state + /// containing it. + pub latest_block_header: BeaconBlockHeader, + pub block_roots: BlockRoots, + pub state_roots: StateRoots, + /// Frozen as of this fork: no longer appended to. See + /// [`Self::historical_summaries`]. + pub historical_roots: HistoricalRoots, + + // -- Eth1 -- + pub eth1_data: Eth1Data, + pub eth1_data_votes: Eth1DataVotes, + /// How many deposits from the contract have been processed, which is where + /// the next one will be read from. + pub eth1_deposit_index: u64, + + // -- Registry -- + pub validators: Validators, + pub balances: Balances, + + // -- Randomness -- + pub randao_mixes: RandaoMixes, + + // -- Slashings -- + pub slashings: Slashings, + + // -- Participation -- + /// Per-validator participation flags for the previous epoch, positionally + /// parallel to `validators`. + pub previous_epoch_participation: EpochParticipation, + /// Flags for the current epoch, which become `previous_epoch_participation` + /// at the next epoch boundary. + pub current_epoch_participation: EpochParticipation, + + // -- Finality -- + pub justification_bits: JustificationBits, + pub previous_justified_checkpoint: Checkpoint, + pub current_justified_checkpoint: Checkpoint, + pub finalized_checkpoint: Checkpoint, + + // -- Inactivity -- + /// Per-validator inactivity score, positionally parallel to `validators`. + pub inactivity_scores: InactivityScores, + + // -- Sync committees -- + /// The committee currently signing sync aggregates. + pub current_sync_committee: SyncCommittee, + /// The committee that takes over from `current_sync_committee` at the next + /// sync committee period boundary. + pub next_sync_committee: SyncCommittee, + + // -- Execution -- + /// The most recently processed execution payload, kept as a header rather + /// than in full. + pub latest_execution_payload_header: ExecutionPayloadHeader, + + // -- Withdrawals -- + /// The index the next withdrawal will use. + pub next_withdrawal_index: WithdrawalIndex, + /// Where the next withdrawal sweep resumes, wrapping around the validator + /// registry. Advancing a persistent cursor rather than rescanning from + /// index zero every block is what bounds `get_expected_withdrawals`' work + /// regardless of how large the registry grows. + pub next_withdrawal_validator_index: ValidatorIndex, + + // -- History (continued) -- + /// Accumulated block/state root commitments, one appended per historical + /// root period, replacing the growth of `historical_roots` as of this + /// fork. See [`super::shared::HistoricalSummary`] for why the two forms + /// are `hash_tree_root`-compatible. + pub historical_summaries: HistoricalSummaries, +} + +#[cfg(test)] +mod tests { + use libssz::{SszDecode as _, SszEncode as _}; + + use super::*; + + fn empty_execution_payload() -> ExecutionPayload { + ExecutionPayload { + parent_hash: ExecutionBlockHash::ZERO, + fee_recipient: ExecutionAddress::ZERO, + state_root: Bytes32::ZERO, + receipts_root: Bytes32::ZERO, + logs_bloom: LogsBloom::try_from(vec![0u8; preset::BYTES_PER_LOGS_BLOOM]).unwrap(), + prev_randao: Bytes32::ZERO, + block_number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: 0, + extra_data: Default::default(), + base_fee_per_gas: Uint256::ZERO, + block_hash: ExecutionBlockHash::ZERO, + transactions: Default::default(), + withdrawals: Default::default(), + } + } + + #[test] + fn withdrawal_round_trips_through_ssz() { + let withdrawal = Withdrawal { + index: 5, + validator_index: 9, + address: ExecutionAddress::repeat_byte(0xab), + amount: 32_000_000_000, + }; + + let bytes = withdrawal.to_ssz(); + assert_eq!(Withdrawal::from_ssz_bytes(&bytes).unwrap(), withdrawal); + } + + #[test] + fn signed_bls_to_execution_change_round_trips_through_ssz() { + let signed_change = SignedBLSToExecutionChange { + message: BLSToExecutionChange { + validator_index: 3, + from_bls_pubkey: BlsPubkey([1; 48]), + to_execution_address: ExecutionAddress::repeat_byte(0xcd), + }, + signature: BlsSignature([2; 96]), + }; + + let bytes = signed_change.to_ssz(); + assert_eq!( + SignedBLSToExecutionChange::from_ssz_bytes(&bytes).unwrap(), + signed_change + ); + } + + #[test] + fn fixed_and_variable_length_containers() { + // Withdrawal and the BLS-to-execution-change pair hold nothing + // variable-length, unlike the payload, body, block, and state that + // carry lists. + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + + // Both payload containers carry at least one list (`extra_data`, at a + // minimum), so both begin their encoding with offsets. + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + } + + #[test] + fn block_body_round_trips_while_empty() { + // An empty body is the common case for a skipped-operation slot, and it + // exercises every offset in the encoding with zero-length payloads, + // including the nested offsets inside `execution_payload`. + let body = BeaconBlockBody { + randao_reveal: BlsSignature::default(), + eth1_data: Eth1Data::default(), + graffiti: Bytes32::ZERO, + proposer_slashings: Default::default(), + attester_slashings: Default::default(), + attestations: Default::default(), + deposits: Default::default(), + voluntary_exits: Default::default(), + sync_aggregate: SyncAggregate::default(), + execution_payload: empty_execution_payload(), + bls_to_execution_changes: Default::default(), + }; + + let bytes = body.to_ssz(); + assert_eq!(BeaconBlockBody::from_ssz_bytes(&bytes).unwrap(), body); + } +} diff --git a/crates/common/types/src/beacon/containers/deneb.rs b/crates/common/types/src/beacon/containers/deneb.rs new file mode 100644 index 000000000..79460c019 --- /dev/null +++ b/crates/common/types/src/beacon/containers/deneb.rs @@ -0,0 +1,389 @@ +//! Containers whose shape is specific to deneb. +//! +//! Deneb's headline change is data blobs: temporary storage for rollup data +//! that consensus commits to but never processes itself. A blob is far larger +//! than everything else a block carries, so the specification never puts one +//! in the block. Instead the block commits only to a KZG commitment per blob, +//! appended to [`BeaconBlockBody`] as `blob_kzg_commitments`, and each blob is +//! propagated separately as a [`BlobSidecar`] over its own gossip subnet, +//! carrying enough of the block's header to prove the sidecar's commitment +//! really is the one the block committed to. [`BlobIdentifier`] is the +//! request-side counterpart: naming one blob of one block without shipping +//! the blob, for the request-response protocol that backfills sidecars gossip +//! missed. +//! +//! [`ExecutionPayload`] and [`ExecutionPayloadHeader`] both gain +//! `blob_gas_used` and `excess_blob_gas`, deneb's per-block blob fee-market +//! accounting: EIP-4844's analogue of EIP-1559's base fee, scoped to blob +//! space instead of execution gas. [`BeaconState`] otherwise keeps +//! [`super::capella::BeaconState`]'s shape, field for field: only the +//! container held in `latest_execution_payload_header` changes. +//! +//! [`BlobIdentifier`] and [`BlobSidecar`] are transcribed from +//! `p2p-interface.md` rather than `beacon-chain.md`, since the specification +//! defines the wire-level blob types in the networking document rather than +//! the state transition document. Neither is ever stored in the state or a +//! block body; a block only ever holds the commitments the sidecars are +//! checked against. + +use libssz_derive::{HashTreeRoot, SszDecode, SszEncode}; +use libssz_types::{SszList, SszVector}; + +use super::altair::{SyncAggregate, SyncCommittee}; +use super::bellatrix::{ExtraData, LogsBloom, Transactions}; +use super::capella::{SignedBLSToExecutionChange, Withdrawals}; +use super::phase0::{Attestation, AttesterSlashing}; +use super::shared::{ + Balances, BeaconBlockHeader, BlockRoots, Checkpoint, Deposit, EpochParticipation, Eth1Data, + Eth1DataVotes, Fork, HistoricalRoots, HistoricalSummaries, InactivityScores, JustificationBits, + ProposerSlashing, RandaoMixes, SignedBeaconBlockHeader, SignedVoluntaryExit, Slashings, + StateRoots, Validators, +}; +use crate::beacon::preset; +use crate::beacon::primitives::{ + BlobIndex, BlsSignature, Bytes32, ExecutionAddress, ExecutionBlockHash, KzgCommitment, + KzgProof, Root, Slot, Uint256, ValidatorIndex, WithdrawalIndex, +}; + +// --------------------------------------------------------------------------- +// Collection aliases +// --------------------------------------------------------------------------- + +/// Raw blob bytes, as propagated in a [`BlobSidecar`] rather than in the block +/// itself. +/// +/// Bounded by `BYTES_PER_BLOB`, which is large enough that a derived +/// `Default` would zero that many bytes on every construction for no reason. +/// That is why [`BlobSidecar`], the only container that holds one, does not +/// derive `Default`. +pub type Blob = SszVector; + +/// The KZG commitments a block makes to its blobs, one per blob, carried in +/// [`BeaconBlockBody::blob_kzg_commitments`] instead of the blobs themselves. +pub type KzgCommitments = SszList; + +/// The merkle path proving a [`BlobSidecar`]'s commitment sits at its claimed +/// index in the block body's `blob_kzg_commitments`, which is what lets a +/// sidecar be checked against a block header without holding the rest of +/// that block's body. +pub type BlobKzgCommitmentInclusionProof = + SszVector; + +// --------------------------------------------------------------------------- +// Execution payload +// --------------------------------------------------------------------------- + +/// The execution layer's contribution to a block: [`super::capella::ExecutionPayload`]'s +/// fields, with deneb's blob gas accounting appended. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct ExecutionPayload { + pub parent_hash: ExecutionBlockHash, + pub fee_recipient: ExecutionAddress, + pub state_root: Bytes32, + pub receipts_root: Bytes32, + pub logs_bloom: LogsBloom, + pub prev_randao: Bytes32, + pub block_number: u64, + pub gas_limit: u64, + pub gas_used: u64, + pub timestamp: u64, + pub extra_data: ExtraData, + pub base_fee_per_gas: Uint256, + pub block_hash: ExecutionBlockHash, + pub transactions: Transactions, + pub withdrawals: Withdrawals, + /// How much blob gas this block's blob transactions consumed. + pub blob_gas_used: u64, + /// The blob gas market's excess entering this block. Plays the same role + /// for blob space that the base fee's excess plays for execution gas: it + /// sets the blob base fee the next block's transactions pay, so blob + /// space is priced by an independent market from execution gas. + pub excess_blob_gas: u64, +} + +/// [`ExecutionPayload`] with the bulky fields replaced by their roots, which +/// is what the state retains once a payload is no longer the newest one. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct ExecutionPayloadHeader { + pub parent_hash: ExecutionBlockHash, + pub fee_recipient: ExecutionAddress, + pub state_root: Bytes32, + pub receipts_root: Bytes32, + pub logs_bloom: LogsBloom, + pub prev_randao: Bytes32, + pub block_number: u64, + pub gas_limit: u64, + pub gas_used: u64, + pub timestamp: u64, + pub extra_data: ExtraData, + pub base_fee_per_gas: Uint256, + pub block_hash: ExecutionBlockHash, + pub transactions_root: Root, + pub withdrawals_root: Root, + pub blob_gas_used: u64, + pub excess_blob_gas: u64, +} + +// --------------------------------------------------------------------------- +// Blocks +// --------------------------------------------------------------------------- + +/// The contents of a block: capella's operations, with the blob commitments +/// deneb adds appended. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconBlockBody { + /// The proposer's contribution to the chain's randomness, which is a + /// signature over the current epoch and so cannot be chosen freely. + pub randao_reveal: BlsSignature, + /// The proposer's vote on the execution chain's deposit state. + pub eth1_data: Eth1Data, + /// Arbitrary proposer-chosen bytes, which consensus never reads. + pub graffiti: Bytes32, + pub proposer_slashings: SszList, + pub attester_slashings: SszList, + pub attestations: SszList, + pub deposits: SszList, + pub voluntary_exits: SszList, + /// The aggregated sync committee signature over the previous slot's block + /// root, plus which members contributed. + pub sync_aggregate: SyncAggregate, + pub execution_payload: ExecutionPayload, + /// Capella's withdrawal-credential-change operations, unchanged in deneb: + /// each [`SignedBLSToExecutionChange`] wraps a + /// [`super::capella::BLSToExecutionChange`] with a signature proving its + /// holder controls the credential being changed. + pub bls_to_execution_changes: + SszList, + /// One KZG commitment per blob this block's proposer chose to include. + /// Never the blobs themselves: those are propagated separately as + /// [`BlobSidecar`]s, which is what keeps a block's own size independent + /// of how much blob data it references. + pub blob_kzg_commitments: KzgCommitments, +} + +/// A block. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconBlock { + pub slot: Slot, + pub proposer_index: ValidatorIndex, + pub parent_root: Root, + /// The root of the state after this block is applied, which the state + /// transition recomputes and compares. + pub state_root: Root, + pub body: BeaconBlockBody, +} + +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SignedBeaconBlock { + pub message: BeaconBlock, + pub signature: BlsSignature, +} + +// --------------------------------------------------------------------------- +// State +// --------------------------------------------------------------------------- + +/// The deneb beacon state: 28 fields, in the specification's order. +/// +/// Field order is load-bearing. SSZ encoding and merkleization both follow +/// declaration order, so reordering or omitting a field silently produces a +/// wrong `hash_tree_root`. +/// +/// Identical to [`super::capella::BeaconState`], field for field: only the +/// type held in `latest_execution_payload_header` changes, to deneb's +/// [`ExecutionPayloadHeader`]. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconState { + // -- Versioning -- + pub genesis_time: u64, + /// The root of the genesis validator registry, which separates this chain + /// from any other running the same fork schedule. + pub genesis_validators_root: Root, + pub slot: Slot, + pub fork: Fork, + + // -- History -- + /// The most recent block's header, with `state_root` left zero until the + /// slot advances, since a block cannot commit to the root of the state + /// containing it. + pub latest_block_header: BeaconBlockHeader, + pub block_roots: BlockRoots, + pub state_roots: StateRoots, + pub historical_roots: HistoricalRoots, + + // -- Eth1 -- + pub eth1_data: Eth1Data, + pub eth1_data_votes: Eth1DataVotes, + /// How many deposits from the contract have been processed, which is + /// where the next one will be read from. + pub eth1_deposit_index: u64, + + // -- Registry -- + pub validators: Validators, + pub balances: Balances, + + // -- Randomness -- + pub randao_mixes: RandaoMixes, + + // -- Slashings -- + pub slashings: Slashings, + + // -- Participation -- + /// Per-validator participation flags for the previous epoch, positionally + /// parallel to `validators`. + pub previous_epoch_participation: EpochParticipation, + /// Flags for the current epoch, which become + /// `previous_epoch_participation` at the next epoch boundary. + pub current_epoch_participation: EpochParticipation, + + // -- Finality -- + pub justification_bits: JustificationBits, + pub previous_justified_checkpoint: Checkpoint, + pub current_justified_checkpoint: Checkpoint, + pub finalized_checkpoint: Checkpoint, + + // -- Inactivity -- + /// Per-validator inactivity score, positionally parallel to `validators`. + pub inactivity_scores: InactivityScores, + + // -- Sync committees -- + /// The committee currently signing sync aggregates. + pub current_sync_committee: SyncCommittee, + /// The committee that takes over from `current_sync_committee` at the + /// next sync committee period boundary. + pub next_sync_committee: SyncCommittee, + + // -- Execution -- + /// The most recent execution payload's header, replacing the whole + /// payload with its roots once the block containing it is no longer new. + pub latest_execution_payload_header: ExecutionPayloadHeader, + + // -- Withdrawals -- + /// The index the next withdrawal will be assigned, so consecutive + /// withdrawals get consecutive indices even though which validators are + /// due one changes from slot to slot. + pub next_withdrawal_index: WithdrawalIndex, + /// Where the validator sweep for withdrawals resumes next slot. + pub next_withdrawal_validator_index: ValidatorIndex, + + // -- History -- + /// Capella's replacement for whole [`super::shared::HistoricalBatch`] + /// roots: one summary per historical window, appended the same way. + pub historical_summaries: HistoricalSummaries, +} + +// --------------------------------------------------------------------------- +// Blob sidecars +// --------------------------------------------------------------------------- +// +// Both containers are transcribed from `p2p-interface.md` rather than +// `beacon-chain.md`: the specification defines the wire-level blob types in +// the networking document, and neither is ever stored in the state or a +// block body. + +/// A request for one blob of one block, without shipping the blob itself. +/// +/// The unit the `BlobSidecarsByRoot` request-response protocol asks for: a +/// peer that already knows a block's root and which blob index it is missing +/// names exactly that, rather than the slot-range-based +/// `BlobSidecarsByRange` protocol or a fresh gossip subscription. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BlobIdentifier { + pub block_root: Root, + pub index: BlobIndex, +} + +/// One blob, plus everything needed to check it belongs to a specific block +/// without holding the rest of that block's body. +/// +/// `signed_block_header` and `kzg_commitment_inclusion_proof` are what make a +/// sidecar self-verifying: a node that only ever receives this sidecar, never +/// the full [`BeaconBlockBody`], can still check `kzg_commitment` against the +/// block's `body_root` via the merkle proof, and the header itself against +/// the proposer's signature. +/// +/// Does not derive `Default`: `blob` is a [`Blob`], bounded by +/// `BYTES_PER_BLOB`, so a derived default would zero that many bytes for no +/// reason every time a placeholder value is needed. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BlobSidecar { + /// This blob's position among the block's `blob_kzg_commitments`, which + /// is also its leaf index for `kzg_commitment_inclusion_proof`. + pub index: BlobIndex, + pub blob: Blob, + pub kzg_commitment: KzgCommitment, + /// A KZG proof that `blob` evaluates to `kzg_commitment`, checkable + /// without recomputing the commitment from the whole blob. + pub kzg_proof: KzgProof, + /// The header of the block this blob belongs to, signed by its proposer, + /// which is what `kzg_commitment_inclusion_proof` terminates at. + pub signed_block_header: SignedBeaconBlockHeader, + pub kzg_commitment_inclusion_proof: BlobKzgCommitmentInclusionProof, +} + +#[cfg(test)] +mod tests { + use libssz::{SszDecode as _, SszEncode as _}; + + use super::*; + + #[test] + fn blob_identifier_round_trips_through_ssz() { + let identifier = BlobIdentifier { + block_root: Root::repeat_byte(9), + index: 3, + }; + + let bytes = identifier.to_ssz(); + assert_eq!(BlobIdentifier::from_ssz_bytes(&bytes).unwrap(), identifier); + } + + #[test] + fn blob_identifier_is_fixed_size() { + // A root and an index, with nothing variable-length, so the encoding + // has one length for every value. + assert!(::is_fixed_size()); + assert_eq!(::fixed_size(), 32 + 8); + } + + #[test] + fn kzg_commitments_list_round_trips_through_ssz() { + // Exercises the collection alias directly, without needing a whole + // block body around it. + let commitments: KzgCommitments = vec![KzgCommitment([1; 48]), KzgCommitment([2; 48])] + .try_into() + .unwrap(); + + let bytes = commitments.to_ssz(); + assert_eq!( + KzgCommitments::from_ssz_bytes(&bytes).unwrap().into_inner(), + commitments.into_inner() + ); + } + + #[test] + fn blob_sidecar_is_fixed_size_despite_carrying_a_blob() { + // Every field, including `blob` and the inclusion proof, is a fixed- + // length vector of fixed-size elements, so the whole sidecar encodes + // with no offsets. Checked at the type level rather than by building + // an instance, since constructing a full `Blob` (bounded by + // `BYTES_PER_BLOB`) is unnecessary work for a fact the types already + // guarantee. + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + } + + #[test] + fn variable_length_containers_carry_offsets() { + // Each of these holds at least one list, so its encoding begins with + // offsets rather than being a fixed layout. `ExecutionPayloadHeader` + // is variable-size too, despite looking header-shaped: `extra_data` + // is a byte list, not a vector. + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + } +} diff --git a/crates/common/types/src/beacon/containers/electra.rs b/crates/common/types/src/beacon/containers/electra.rs new file mode 100644 index 000000000..9016d4225 --- /dev/null +++ b/crates/common/types/src/beacon/containers/electra.rs @@ -0,0 +1,582 @@ +//! Containers whose shape is specific to electra. +//! +//! Electra bundles several EIPs, and each explains a cluster of the containers +//! below. +//! +//! Through deneb, an attestation names one committee +//! (`AttestationData.index`) and its aggregation bitfield is one bit per +//! member of that single committee. EIP-7549 moves the committee index out of +//! `AttestationData` and into a new [`Attestation::committee_bits`] field +//! naming every committee the attestation covers, so [`AggregationBits`] now +//! has to be wide enough to hold a bit for every attester across every +//! committee in a slot rather than one committee's worth. That reshaping is +//! also why [`preset::MAX_ATTESTATIONS_ELECTRA`] is far smaller than phase0's +//! `MAX_ATTESTATIONS`: one electra attestation now does the work of a whole +//! slot's committees, so a block needs far fewer of them to cover the same +//! validator set. Pre-electra, an unaggregated gossip vote reused +//! `Attestation` itself with one bit set; that no longer works once the +//! bitfield spans the whole slot, which is why [`SingleAttestation`] exists as +//! a separate, explicitly-indexed container. +//! +//! EIP-7251 lets a validator's effective balance grow past +//! `MAX_EFFECTIVE_BALANCE` (given a compounding withdrawal credential), which +//! turns deposits, exits, and consolidations from operations bounded by a +//! count of validators into operations that have to be bounded by balance +//! instead: one very large validator's deposit, exit, or consolidation could +//! otherwise move as much stake in a single slot as thousands of ordinary +//! ones. [`PendingDeposit`], [`PendingPartialWithdrawal`], and +//! [`PendingConsolidation`] are the state's queues for exactly that, each +//! drained a bounded amount per epoch or slot rather than applied the instant +//! they are known about. +//! +//! EIP-6110 and EIP-7002 let the execution layer request a deposit or +//! withdrawal directly, instead of consensus replaying the deposit contract's +//! event log or a validator signing a voluntary exit; EIP-7251 extends the +//! same mechanism to consolidations. [`ExecutionRequests`] is the per-block +//! envelope the execution payload carries all three request kinds in. +//! +//! [`BeaconState`]'s field count crosses a power of two at electra, so its +//! merkle tree gains a level relative to deneb's; see `docs/beacon_stf.md` +//! for the generalized-index table this implies. + +use libssz_derive::{HashTreeRoot, SszDecode, SszEncode}; +use libssz_types::{SszBitlist, SszBitvector, SszList}; + +use super::altair::{SyncAggregate, SyncCommittee}; +use super::capella::SignedBLSToExecutionChange; +use super::deneb::{ExecutionPayload, ExecutionPayloadHeader, KzgCommitments}; +use super::shared::{ + AttestationData, Balances, BeaconBlockHeader, BlockRoots, Checkpoint, Deposit, + EpochParticipation, Eth1Data, Eth1DataVotes, Fork, HistoricalRoots, HistoricalSummaries, + InactivityScores, JustificationBits, ProposerSlashing, RandaoMixes, SignedVoluntaryExit, + Slashings, StateRoots, Validators, +}; +use crate::beacon::preset; +use crate::beacon::primitives::{ + BlsPubkey, BlsSignature, Bytes32, CommitteeIndex, Epoch, ExecutionAddress, Gwei, Root, Slot, + ValidatorIndex, WithdrawalIndex, +}; + +// --------------------------------------------------------------------------- +// Collection aliases +// --------------------------------------------------------------------------- + +/// The attesters covered by one aggregate attestation: one bit per member of +/// every committee named in [`CommitteeBits`], rather than one committee's +/// worth as in every fork before electra. +/// +/// Bounded by `MAX_VALIDATORS_PER_SLOT`, the product of `MAX_COMMITTEES_PER_SLOT` +/// and `MAX_VALIDATORS_PER_COMMITTEE`, since one attestation can now span +/// every committee in the slot. +pub type AggregationBits = SszBitlist<{ preset::MAX_VALIDATORS_PER_SLOT }>; + +/// Which of a slot's committees an [`Attestation`] covers, one bit per +/// committee index. +/// +/// `get_committee_indices` reads this to recover the ordered list of +/// committees, and [`AggregationBits`] is the concatenation of each named +/// committee's member bits in that same ascending order, so `committee_bits` +/// is what tells a reader where one committee's segment ends and the next +/// begins. +pub type CommitteeBits = SszBitvector<{ preset::MAX_COMMITTEES_PER_SLOT }>; + +/// The attesters covered by one aggregate, named explicitly rather than as a +/// bitfield, which is the form signature verification needs. +/// +/// Bounded the same way as [`AggregationBits`], for the same reason: one +/// [`IndexedAttestation`] can now name attesters from every committee in a +/// slot. +pub type AttestingIndices = SszList; + +/// Attestations included in a block. +/// +/// Bounded by `MAX_ATTESTATIONS_ELECTRA`, far smaller than phase0's +/// `MAX_ATTESTATIONS`: one electra attestation now covers a whole slot's +/// committees, so a block needs far fewer of them to cover the same +/// validator set. +pub type Attestations = SszList; + +/// Evidence of conflicting attestations included in a block. +/// +/// Bounded by `MAX_ATTESTER_SLASHINGS_ELECTRA`, tightened from phase0's +/// `MAX_ATTESTER_SLASHINGS`: one electra [`IndexedAttestation`] can now name +/// every attester in a slot, so a single slashing's evidence is +/// proportionally larger to include. +pub type AttesterSlashings = SszList; + +/// Deposits queued in the state, not yet credited to the validator registry. +pub type PendingDeposits = SszList; + +/// Partial withdrawals queued in the state, not yet paid out. +pub type PendingPartialWithdrawals = + SszList; + +/// Validator consolidations queued in the state, not yet applied. +pub type PendingConsolidations = + SszList; + +// --------------------------------------------------------------------------- +// Attestations +// --------------------------------------------------------------------------- + +/// An aggregate attestation, as gossiped and as included in a block. +/// +/// EIP-7549 moves the committee index out of `AttestationData` and into +/// [`Attestation::committee_bits`], so one attestation can now name every +/// committee in a slot rather than just one. From electra on, `data.index` is +/// required to be zero: `committee_bits` is the only source of which +/// committees an attestation covers, and `data` is otherwise shared unchanged +/// with every earlier fork. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct Attestation { + pub aggregation_bits: AggregationBits, + pub data: AttestationData, + /// The aggregate signature of every attester set across every committee + /// named in `committee_bits`, over `data`. + pub signature: BlsSignature, + /// Which committees `aggregation_bits` covers. [`AggregationBits`] is the + /// concatenation of each named committee's member bits, in ascending + /// committee-index order. + pub committee_bits: CommitteeBits, +} + +/// An attestation with its attesters named rather than bit-encoded. +/// +/// Signature verification needs the public keys, which needs the indices, so +/// the state transition converts an [`Attestation`] into this form before +/// checking it. `attesting_indices` now spans every committee an +/// [`Attestation`] covers, following the same widening as [`AggregationBits`]. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct IndexedAttestation { + /// The attesters, which the specification requires to be sorted and + /// unique. + pub attesting_indices: AttestingIndices, + pub data: AttestationData, + pub signature: BlsSignature, +} + +/// Evidence that a set of validators made two conflicting attestations. +/// +/// The container's own shape is unchanged from phase0; what changed is +/// [`IndexedAttestation`] itself, which now names attesters from every +/// committee in a slot instead of one. That is also why this is bounded by +/// `MAX_ATTESTER_SLASHINGS_ELECTRA` rather than phase0's larger +/// `MAX_ATTESTER_SLASHINGS`: evidence spanning a whole slot is proportionally +/// more expensive to include. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct AttesterSlashing { + pub attestation_1: IndexedAttestation, + pub attestation_2: IndexedAttestation, +} + +/// One attester's unaggregated vote, gossiped on a per-committee attestation +/// subnet before an aggregator folds it into an [`Attestation`]. +/// +/// Pre-electra, an unaggregated vote reused [`Attestation`] itself with +/// exactly one bit set in `aggregation_bits`, since that bitfield was already +/// scoped to a single committee. From electra on, `aggregation_bits` spans +/// every committee in the slot, so a lone attester's bit position no longer +/// says which committee it belongs to on its own. `SingleAttestation` carries +/// `committee_index` and `attester_index` explicitly instead, and an +/// aggregator combines every `SingleAttestation` sharing the same `data` into +/// one widened [`Attestation`]. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SingleAttestation { + pub committee_index: CommitteeIndex, + pub attester_index: ValidatorIndex, + pub data: AttestationData, + pub signature: BlsSignature, +} + +// --------------------------------------------------------------------------- +// Execution layer triggered requests +// --------------------------------------------------------------------------- +// +// EIP-6110, EIP-7002, and EIP-7251 let the execution layer request a deposit, +// withdrawal, or consolidation directly, without consensus waiting to replay +// the deposit contract's event log or a validator signing a voluntary exit. +// `ExecutionRequests` is the per-block envelope the execution payload carries +// these three request kinds in. + +/// An execution-layer-triggered deposit (EIP-6110). +/// +/// Carries the same fields a `Deposit`'s underlying data does, plus `index`: +/// unlike a contract-log deposit, a request arrives already ordered by the +/// execution layer, so there is no merkle proof to check, only a position to +/// record. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct DepositRequest { + pub pubkey: BlsPubkey, + pub withdrawal_credentials: Bytes32, + pub amount: Gwei, + pub signature: BlsSignature, + pub index: u64, +} + +/// An execution-layer-triggered exit or partial withdrawal (EIP-7002). +/// +/// `source_address` is the execution-layer account that requested it, which +/// `process_withdrawal_request` checks against the validator's withdrawal +/// credentials before honoring the request. An `amount` of +/// `FULL_EXIT_REQUEST_AMOUNT` signals a full exit rather than a partial +/// withdrawal of that amount. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct WithdrawalRequest { + pub source_address: ExecutionAddress, + pub validator_pubkey: BlsPubkey, + pub amount: Gwei, +} + +/// An execution-layer-triggered validator consolidation (EIP-7251): a request +/// to merge `source_pubkey`'s balance into `target_pubkey`'s and exit the +/// source, which is how a validator raises its effective balance past +/// `MAX_EFFECTIVE_BALANCE` without a fresh deposit. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct ConsolidationRequest { + pub source_address: ExecutionAddress, + pub source_pubkey: BlsPubkey, + pub target_pubkey: BlsPubkey, +} + +/// The execution payload's envelope for every execution-layer-triggered +/// request in this block, grouped by kind. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct ExecutionRequests { + pub deposits: SszList, + pub withdrawals: SszList, + pub consolidations: + SszList, +} + +// --------------------------------------------------------------------------- +// Pending balance queues +// --------------------------------------------------------------------------- +// +// EIP-7251 lets a validator's effective balance grow past +// `MAX_EFFECTIVE_BALANCE`, so the churn that used to be bounded by a count of +// validators now has to be bounded by balance instead. These three +// containers are the state's queues for deposits, partial withdrawals, and +// consolidations that are known about but not yet applied, each drained a +// bounded amount per epoch or slot so no single operation outruns the churn +// limit. + +/// A deposit recorded in the state, not yet credited to the validator +/// registry. +/// +/// Carries the same fields a `Deposit`'s data does, plus `slot`: unlike a +/// `Deposit`, a pending deposit did not arrive with a merkle proof against the +/// deposit contract, so the state has to remember when it was queued instead. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct PendingDeposit { + pub pubkey: BlsPubkey, + pub withdrawal_credentials: Bytes32, + pub amount: Gwei, + pub signature: BlsSignature, + pub slot: Slot, +} + +/// A partial withdrawal recorded in the state, not yet paid out. +/// +/// Queued rather than applied immediately so +/// `MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP` can bound how many of these +/// `get_expected_withdrawals` drains in one slot. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct PendingPartialWithdrawal { + pub validator_index: ValidatorIndex, + pub amount: Gwei, + pub withdrawable_epoch: Epoch, +} + +/// A validator consolidation recorded in the state, not yet applied. +/// +/// `source_index` exits once `target_index` absorbs its balance, which is why +/// only the two indices need to be kept: everything else about the merge +/// follows from the validators' own records at the epoch it is processed. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct PendingConsolidation { + pub source_index: ValidatorIndex, + pub target_index: ValidatorIndex, +} + +// --------------------------------------------------------------------------- +// Blocks +// --------------------------------------------------------------------------- + +/// The contents of a block: deneb's operations, plus the execution-layer- +/// triggered requests this block's payload carries. +/// +/// Unchanged from deneb except for three things: `attester_slashings` and +/// `attestations` are now bounded (and, for attestations, shaped) +/// differently, and `execution_requests` is appended at the end. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconBlockBody { + /// The proposer's contribution to the chain's randomness, which is a + /// signature over the current epoch and so cannot be chosen freely. + pub randao_reveal: BlsSignature, + /// The proposer's vote on the execution chain's deposit state. + pub eth1_data: Eth1Data, + /// Arbitrary proposer-chosen bytes, which consensus never reads. + pub graffiti: Bytes32, + pub proposer_slashings: SszList, + pub attester_slashings: AttesterSlashings, + pub attestations: Attestations, + pub deposits: SszList, + pub voluntary_exits: SszList, + /// The aggregated sync committee signature over the previous slot's block + /// root, plus which members contributed. + pub sync_aggregate: SyncAggregate, + pub execution_payload: ExecutionPayload, + pub bls_to_execution_changes: + SszList, + pub blob_kzg_commitments: KzgCommitments, + /// The execution-layer-triggered deposit, withdrawal, and consolidation + /// requests carried by this block's payload. The one field electra adds + /// to the body. + pub execution_requests: ExecutionRequests, +} + +/// A block. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconBlock { + pub slot: Slot, + pub proposer_index: ValidatorIndex, + pub parent_root: Root, + /// The root of the state after this block is applied, which the state + /// transition recomputes and compares. + pub state_root: Root, + pub body: BeaconBlockBody, +} + +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SignedBeaconBlock { + pub message: BeaconBlock, + pub signature: BlsSignature, +} + +// --------------------------------------------------------------------------- +// State +// --------------------------------------------------------------------------- + +/// The electra beacon state: 37 fields, in the specification's order. +/// +/// Field order is load-bearing. SSZ encoding and merkleization both follow +/// declaration order, so reordering or omitting a field silently produces a +/// wrong `hash_tree_root`. +/// +/// Fields through `historical_summaries` are identical to deneb's, field for +/// field (28 of them). Electra appends nine more, serving two EIPs: +/// `deposit_requests_start_index` (EIP-6110) is where the state switches from +/// crediting deposits off `Eth1Data` votes to crediting them off +/// execution-layer `DepositRequest`s, and the remaining eight (EIP-7251) are +/// the balance-churn accounting and the three pending queues that let a +/// validator's effective balance grow past `MAX_EFFECTIVE_BALANCE` without +/// letting a single large validator's deposit, exit, or consolidation move +/// more stake in one slot than the churn limit allows. +/// +/// Crossing 37 fields also crosses a power of two, so this state's merkle +/// tree gains a level relative to deneb's; see `docs/beacon_stf.md` for the +/// generalized-index table this implies. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconState { + // -- Versioning -- + pub genesis_time: u64, + /// The root of the genesis validator registry, which separates this chain + /// from any other running the same fork schedule. + pub genesis_validators_root: Root, + pub slot: Slot, + pub fork: Fork, + + // -- History -- + /// The most recent block's header, with `state_root` left zero until the + /// slot advances, since a block cannot commit to the root of the state + /// containing it. + pub latest_block_header: BeaconBlockHeader, + pub block_roots: BlockRoots, + pub state_roots: StateRoots, + pub historical_roots: HistoricalRoots, + + // -- Eth1 -- + pub eth1_data: Eth1Data, + pub eth1_data_votes: Eth1DataVotes, + /// How many deposits from the contract have been processed, which is + /// where the next one will be read from. Superseded for new deposits once + /// `deposit_requests_start_index` is set, but kept for deposits still in + /// flight from before that point. + pub eth1_deposit_index: u64, + + // -- Registry -- + pub validators: Validators, + pub balances: Balances, + + // -- Randomness -- + pub randao_mixes: RandaoMixes, + + // -- Slashings -- + pub slashings: Slashings, + + // -- Participation -- + pub previous_epoch_participation: EpochParticipation, + pub current_epoch_participation: EpochParticipation, + + // -- Finality -- + pub justification_bits: JustificationBits, + pub previous_justified_checkpoint: Checkpoint, + pub current_justified_checkpoint: Checkpoint, + pub finalized_checkpoint: Checkpoint, + + // -- Inactivity -- + pub inactivity_scores: InactivityScores, + + // -- Sync committees -- + /// The committee currently signing sync aggregates. + pub current_sync_committee: SyncCommittee, + /// The committee that takes over from `current_sync_committee` at the + /// next sync committee period boundary. + pub next_sync_committee: SyncCommittee, + + // -- Execution -- + pub latest_execution_payload_header: ExecutionPayloadHeader, + + // -- Withdrawals -- + pub next_withdrawal_index: WithdrawalIndex, + /// The next validator index `get_expected_withdrawals`'s registry sweep + /// resumes from, so the sweep makes bounded progress across the whole + /// registry over many slots instead of restarting from zero each time. + pub next_withdrawal_validator_index: ValidatorIndex, + + // -- Deep history -- + pub historical_summaries: HistoricalSummaries, + + // -- Deposit requests (EIP-6110) -- + /// The execution-layer deposit request index at which the state switched + /// from crediting deposits off `Eth1Data` votes to crediting them off + /// `DepositRequest`s directly. Holds `UNSET_DEPOSIT_REQUESTS_START_INDEX` + /// until the first `DepositRequest` is seen. + pub deposit_requests_start_index: u64, + + // -- Balance churn (EIP-7251) -- + /// How much of this epoch's deposit balance churn limit remains unused, + /// so a deposit that would exceed it is queued in `pending_deposits` + /// instead of activating immediately. + pub deposit_balance_to_consume: Gwei, + /// How much of this epoch's exit balance churn limit remains unused, the + /// exit-side counterpart of `deposit_balance_to_consume`. + pub exit_balance_to_consume: Gwei, + /// The earliest epoch an exit initiated now could take effect, advanced + /// by `compute_exit_epoch_and_update_churn` as exits consume the churn + /// limit faster than it refills. + pub earliest_exit_epoch: Epoch, + /// How much of this epoch's consolidation churn limit remains unused. + pub consolidation_balance_to_consume: Gwei, + /// The earliest epoch a consolidation initiated now could take effect, + /// the consolidation-side counterpart of `earliest_exit_epoch`. + pub earliest_consolidation_epoch: Epoch, + + // -- Pending queues (EIP-7251) -- + /// Deposits known but not yet credited to the validator registry, + /// drained a bounded amount per epoch by `process_pending_deposits`. + pub pending_deposits: PendingDeposits, + /// Partial withdrawals known but not yet paid out, drained a bounded + /// amount per slot by `get_expected_withdrawals`. + pub pending_partial_withdrawals: PendingPartialWithdrawals, + /// Consolidations known but not yet applied, drained a bounded amount per + /// epoch by `process_pending_consolidations`. + pub pending_consolidations: PendingConsolidations, +} + +// --------------------------------------------------------------------------- +// Validator-side containers +// --------------------------------------------------------------------------- + +/// An aggregate together with proof that its aggregator was selected to +/// produce it. +/// +/// Unchanged in shape from phase0: `aggregate` simply carries electra's wider +/// [`Attestation`] now. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct AggregateAndProof { + pub aggregator_index: ValidatorIndex, + pub aggregate: Attestation, + /// The aggregator's signature over the slot, which is what makes + /// selection verifiable rather than self-declared. + pub selection_proof: BlsSignature, +} + +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SignedAggregateAndProof { + pub message: AggregateAndProof, + pub signature: BlsSignature, +} + +#[cfg(test)] +mod tests { + use libssz::{SszDecode as _, SszEncode as _}; + + use super::*; + + #[test] + fn attestation_aggregation_bits_span_every_named_committee() { + // Two committees named in committee_bits (indices 0 and 2), each + // contributing a slice of aggregation_bits: this is the electra-only + // shape no earlier fork has, since every earlier fork's + // aggregation_bits covers exactly one committee. + let mut committee_bits = CommitteeBits::default(); + committee_bits.set(0, true).unwrap(); + committee_bits.set(2, true).unwrap(); + + let mut aggregation_bits = AggregationBits::with_length(6).unwrap(); + aggregation_bits.set(0, true).unwrap(); + aggregation_bits.set(4, true).unwrap(); + + let attestation = Attestation { + aggregation_bits, + data: AttestationData::default(), + signature: BlsSignature::default(), + committee_bits, + }; + + let bytes = attestation.to_ssz(); + assert_eq!(Attestation::from_ssz_bytes(&bytes).unwrap(), attestation); + } + + #[test] + fn pending_deposit_round_trips_through_ssz() { + let deposit = PendingDeposit { + pubkey: BlsPubkey([9; 48]), + withdrawal_credentials: Bytes32::repeat_byte(1), + amount: 32_000_000_000, + signature: BlsSignature::default(), + slot: 100, + }; + + let bytes = deposit.to_ssz(); + assert_eq!(PendingDeposit::from_ssz_bytes(&bytes).unwrap(), deposit); + } + + #[test] + fn new_fixed_size_containers_have_no_offsets() { + // Every field of each is itself fixed-length, so none of these carry + // SSZ offsets, unlike Attestation, IndexedAttestation, and + // ExecutionRequests, which each hold at least one list or bitlist. + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + } + + #[test] + fn variable_length_containers_carry_offsets() { + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + } +} diff --git a/crates/common/types/src/beacon/containers/fulu.rs b/crates/common/types/src/beacon/containers/fulu.rs new file mode 100644 index 000000000..61fdeb028 --- /dev/null +++ b/crates/common/types/src/beacon/containers/fulu.rs @@ -0,0 +1,347 @@ +//! Containers whose shape is specific to fulu. +//! +//! Fulu's headline change is how blob data reaches the network. Through +//! electra, verifying a block's blobs means downloading every one of them in +//! full, which stops scaling as the per-block blob count grows. Fulu instead +//! erasure-codes each blob into a wide row of an extended data matrix and +//! slices the matrix into columns, so a node can sample a handful of columns +//! and gain the same statistical confidence that all the data behind them is +//! available, without ever holding the whole matrix itself. [`DataColumnSidecar`] +//! is what a node gossips and serves per column; [`MatrixEntry`] is the +//! row-and-column-addressed cell the matrix is built from, the form +//! `compute_matrix` and `recover_matrix` (`das-core.md`) operate on rather than +//! the per-column grouping a sidecar presents; [`DataColumnsByRootIdentifier`] +//! is how a request-response peer asks for specific columns of a specific +//! block. `BeaconBlockBody`, `BeaconBlock`, `SignedBeaconBlock`, +//! `ExecutionPayload`, and `ExecutionPayloadHeader` are unchanged from electra: +//! a block still commits to the same `blob_kzg_commitments` it always has, +//! since sampling changes how the data behind those commitments travels over +//! the network, not what the block itself contains. This module defines none +//! of those five; state transition code should import them from +//! [`super::electra`] and [`super::deneb`] instead. +//! +//! The other change is [`BeaconState::proposer_lookahead`]. Every fork through +//! electra computes each slot's proposer on demand from the active set and the +//! shuffling seed, so anything that needs to know a proposer ahead of time has +//! to redo that computation itself. Fulu instead has the state precompute a +//! window of upcoming proposers at each epoch boundary, so +//! `get_beacon_proposer_index` becomes a lookup into that window rather than a +//! shuffle. + +use libssz_derive::{HashTreeRoot, SszDecode, SszEncode}; +use libssz_types::{SszList, SszVector}; + +use super::altair::SyncCommittee; +use super::deneb::{ExecutionPayloadHeader, KzgCommitments}; +use super::electra::{PendingConsolidations, PendingDeposits, PendingPartialWithdrawals}; +use super::shared::{ + Balances, BlockRoots, EpochParticipation, Eth1DataVotes, HistoricalRoots, HistoricalSummaries, + InactivityScores, JustificationBits, RandaoMixes, Slashings, StateRoots, Validators, +}; +use super::shared::{BeaconBlockHeader, Checkpoint, Eth1Data, Fork, SignedBeaconBlockHeader}; +use crate::beacon::preset; +use crate::beacon::primitives::{ + Bytes32, ColumnIndex, Epoch, Gwei, KzgProof, Root, Slot, ValidatorIndex, WithdrawalIndex, +}; + +// --------------------------------------------------------------------------- +// Collection aliases +// --------------------------------------------------------------------------- + +/// The window of upcoming proposer indices `BeaconState::proposer_lookahead` +/// precomputes: the rest of the current epoch plus `MIN_SEED_LOOKAHEAD` full +/// epochs beyond it. +pub type ProposerLookahead = SszVector; + +/// One cell of the extended data matrix: a fixed-size slice of a blob's +/// Reed-Solomon extension, small enough that a node can fetch and verify one +/// without fetching the blob it came from. +pub type Cell = SszVector; + +/// One data column: the same-indexed cell from every blob in a block, which is +/// what a [`DataColumnSidecar`] actually carries. +/// +/// Bounded by `MAX_BLOB_COMMITMENTS_PER_BLOCK` rather than a column-specific +/// constant, since a column holds exactly one cell per blob in the block, and +/// a block can hold at most that many blobs. +pub type DataColumn = SszList; + +/// The KZG proofs accompanying a [`DataColumn`], one per cell in the same +/// order, so `verify_data_column_sidecar_kzg_proofs` can batch-verify the +/// column against `DataColumnSidecar::kzg_commitments` without a separate +/// lookup. +pub type KzgProofs = SszList; + +/// The merkle path proving a [`DataColumnSidecar`]'s `kzg_commitments` sit at +/// their claimed position in the block body. +/// +/// Shallower than deneb's per-commitment inclusion proof, because this one +/// proves the root of the whole `blob_kzg_commitments` list at once rather +/// than one leaf: every sidecar of the same block shares the same commitment +/// list, so proving the list once and repeating it in each sidecar is cheaper +/// than a per-commitment proof would be. +pub type KzgCommitmentsInclusionProof = + SszVector; + +/// The column indices a [`DataColumnsByRootIdentifier`] request asks for. +pub type ColumnIndices = SszList; + +/// A row identifier in the extended data matrix, naming which blob in the +/// block a [`MatrixEntry`] belongs to. +/// +/// `das-core.md` lists this as a custom type alongside +/// [`crate::beacon::primitives::ColumnIndex`], but only [`MatrixEntry`] needs it, so it +/// is defined here instead of in `crate::beacon::primitives`. +pub type RowIndex = u64; + +// --------------------------------------------------------------------------- +// Data availability sampling +// --------------------------------------------------------------------------- + +/// One column's worth of one block's blob data, as gossiped and served over +/// request-response. +/// +/// Self-verifying without a separate fetch of the block: `column`, +/// `kzg_commitments`, and `kzg_proofs` are enough to check the cells against +/// the commitments directly, and `kzg_commitments_inclusion_proof` is enough +/// to check that those commitments are the ones the block actually committed +/// to, via `signed_block_header`. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct DataColumnSidecar { + pub index: ColumnIndex, + pub column: DataColumn, + /// The block's full `blob_kzg_commitments`, repeated in every one of that + /// block's sidecars rather than fetched separately, which is what lets a + /// sidecar be checked on its own. + pub kzg_commitments: KzgCommitments, + pub kzg_proofs: KzgProofs, + pub signed_block_header: SignedBeaconBlockHeader, + pub kzg_commitments_inclusion_proof: KzgCommitmentsInclusionProof, +} + +/// One cell of the extended data matrix, addressed by which blob it belongs to +/// and which column it sits in. +/// +/// What [`DataColumnSidecar::column`] is assembled from: a sidecar groups +/// every blob's cell at one column index together, while a `MatrixEntry` +/// names a single cell independent of that grouping, which is the form +/// `compute_matrix` and `recover_matrix` operate on when demonstrating how a +/// node might store and reconstruct the matrix. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct MatrixEntry { + pub cell: Cell, + pub kzg_proof: KzgProof, + pub column_index: ColumnIndex, + pub row_index: RowIndex, +} + +/// A request for specific columns of a specific block, used by the +/// `DataColumnSidecarsByRoot` request-response protocol. +#[derive(Debug, Clone, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct DataColumnsByRootIdentifier { + pub block_root: Root, + pub columns: ColumnIndices, +} + +// --------------------------------------------------------------------------- +// State +// --------------------------------------------------------------------------- + +/// The fulu beacon state: electra's 37 fields plus `proposer_lookahead`, 38 +/// total, in the specification's order. +/// +/// Field order is load-bearing. SSZ encoding and merkleization both follow +/// declaration order, so reordering or omitting a field silently produces a +/// wrong `hash_tree_root`. +/// +/// Every field through `pending_consolidations` is identical to electra's, +/// field for field; `proposer_lookahead` is appended after it rather than +/// inserted anywhere earlier, so nothing electra already committed to shifts +/// position. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconState { + // -- Versioning -- + pub genesis_time: u64, + /// The root of the genesis validator registry, which separates this chain + /// from any other running the same fork schedule. + pub genesis_validators_root: Root, + pub slot: Slot, + pub fork: Fork, + + // -- History -- + /// The most recent block's header, with `state_root` left zero until the + /// slot advances, since a block cannot commit to the root of the state + /// containing it. + pub latest_block_header: BeaconBlockHeader, + pub block_roots: BlockRoots, + pub state_roots: StateRoots, + /// Frozen since capella: further history is committed to by + /// `historical_summaries` instead. Kept rather than removed so a fulu + /// state's shape stays hash-tree-root-compatible with every root + /// committed while this field was still growing. + pub historical_roots: HistoricalRoots, + + // -- Eth1 -- + pub eth1_data: Eth1Data, + pub eth1_data_votes: Eth1DataVotes, + /// How many deposits from the contract have been processed, which is + /// where the next one will be read from. + pub eth1_deposit_index: u64, + + // -- Registry -- + pub validators: Validators, + pub balances: Balances, + + // -- Randomness -- + pub randao_mixes: RandaoMixes, + + // -- Slashings -- + pub slashings: Slashings, + + // -- Participation -- + /// Per-validator participation flags for the previous epoch, positionally + /// parallel to `validators`. See altair for why this replaces phase0's + /// accumulated attestations. + pub previous_epoch_participation: EpochParticipation, + /// Flags for the current epoch, which become `previous_epoch_participation` + /// at the next epoch boundary. + pub current_epoch_participation: EpochParticipation, + + // -- Finality -- + pub justification_bits: JustificationBits, + pub previous_justified_checkpoint: Checkpoint, + pub current_justified_checkpoint: Checkpoint, + pub finalized_checkpoint: Checkpoint, + + // -- Inactivity -- + /// Per-validator inactivity score, positionally parallel to `validators`. + pub inactivity_scores: InactivityScores, + + // -- Sync committees -- + /// The committee currently signing sync aggregates. + pub current_sync_committee: SyncCommittee, + /// The committee that takes over from `current_sync_committee` at the + /// next sync committee period boundary. + pub next_sync_committee: SyncCommittee, + + // -- Execution -- + /// The most recently applied execution payload, retained as a header so + /// the beacon state never has to hold a full payload's transactions and + /// withdrawals, which consensus never reads back out of the state once + /// the payload has been applied. + pub latest_execution_payload_header: ExecutionPayloadHeader, + + // -- Withdrawals -- + /// Where the withdrawal sweep across `validators` last stopped, so + /// `get_expected_withdrawals` resumes from here each slot instead of + /// rescanning the registry from the start. + pub next_withdrawal_index: WithdrawalIndex, + pub next_withdrawal_validator_index: ValidatorIndex, + + // -- History (capella) -- + /// The commitment to history from capella onward, appended to instead of + /// `historical_roots` once that field was frozen. + pub historical_summaries: HistoricalSummaries, + + // -- Deposits, exits, and consolidations (electra) -- + /// The deposit contract log index at which the state switched from + /// crediting `Eth1Data` votes to crediting execution layer deposit + /// requests directly, or `UNSET_DEPOSIT_REQUESTS_START_INDEX` before the + /// first request arrives. + pub deposit_requests_start_index: u64, + /// Deposit churn left over from the current epoch's activation queue, + /// carried into the next epoch rather than wasted. + pub deposit_balance_to_consume: Gwei, + /// Exit churn left over from the current epoch's exit queue, carried + /// forward the same way as `deposit_balance_to_consume`. + pub exit_balance_to_consume: Gwei, + /// The earliest epoch the exit queue has not yet exhausted its churn for. + pub earliest_exit_epoch: Epoch, + /// Consolidation churn left over from the current epoch's consolidation + /// queue. + pub consolidation_balance_to_consume: Gwei, + /// The earliest epoch the consolidation queue has not yet exhausted its + /// churn for. + pub earliest_consolidation_epoch: Epoch, + /// Deposits credited on the execution layer but not yet applied to the + /// registry, drained a bounded number at a time each epoch. + pub pending_deposits: PendingDeposits, + /// Partial withdrawals requested but not yet paid out. + pub pending_partial_withdrawals: PendingPartialWithdrawals, + /// Validator consolidations requested but not yet applied. + pub pending_consolidations: PendingConsolidations, + + // -- Proposer lookahead (fulu) -- + /// The proposer for every slot from the start of the current epoch + /// through `MIN_SEED_LOOKAHEAD` full epochs ahead, precomputed at each + /// epoch boundary by `process_proposer_lookahead` so that + /// `get_beacon_proposer_index` becomes a lookup into this vector rather + /// than a shuffle computed on demand. + pub proposer_lookahead: ProposerLookahead, +} + +#[cfg(test)] +mod tests { + use libssz::{SszDecode as _, SszEncode as _}; + + use super::*; + + #[test] + fn beacon_state_and_data_column_sidecar_are_variable_size() { + // Both hold at least one list, so both begin their encoding with + // offsets rather than a fixed layout. Checked at the type level, since + // building a full state or a full sidecar is not needed to know this. + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + // A request identifier holds a list of columns too. + assert!(!::is_fixed_size()); + } + + #[test] + fn matrix_entry_is_fixed_size() { + // A cell, a proof, and two indices: nothing variable-length, unlike + // the sidecar that groups many matrix entries together per column. + assert!(::is_fixed_size()); + } + + #[test] + fn matrix_entry_round_trips_through_ssz() { + // One cell is small enough to build directly in a test, unlike a full + // data column, which would need one cell per blob in a block. + let cell = Cell::try_from(vec![7u8; preset::BYTES_PER_CELL]).unwrap(); + let entry = MatrixEntry { + cell, + kzg_proof: KzgProof([1; crate::beacon::primitives::KZG_POINT_SIZE]), + column_index: 3, + row_index: 0, + }; + + let bytes = entry.to_ssz(); + assert_eq!(MatrixEntry::from_ssz_bytes(&bytes).unwrap(), entry); + } + + #[test] + fn data_columns_by_root_identifier_round_trips_with_some_columns() { + let identifier = DataColumnsByRootIdentifier { + block_root: Root::repeat_byte(9), + columns: ColumnIndices::try_from(vec![0, 1, 42]).unwrap(), + }; + + let bytes = identifier.to_ssz(); + assert_eq!( + DataColumnsByRootIdentifier::from_ssz_bytes(&bytes).unwrap(), + identifier + ); + } + + #[test] + fn data_columns_by_root_identifier_round_trips_while_empty() { + let identifier = DataColumnsByRootIdentifier::default(); + + let bytes = identifier.to_ssz(); + assert_eq!( + DataColumnsByRootIdentifier::from_ssz_bytes(&bytes).unwrap(), + identifier + ); + } +} diff --git a/crates/common/types/src/beacon/containers/mod.rs b/crates/common/types/src/beacon/containers/mod.rs new file mode 100644 index 000000000..1dc2cf481 --- /dev/null +++ b/crates/common/types/src/beacon/containers/mod.rs @@ -0,0 +1,706 @@ +//! The specification's containers. +//! +//! Containers whose shape is the same in every fork are defined once, in +//! [`shared`]. Containers that change are defined once per fork, in a module per +//! fork, and wrapped in an enum here. +//! +//! # Why an enum over per-fork structs +//! +//! Each per-fork struct derives its SSZ encoding, decoding, and merkleization. +//! That is the point: the per-fork field lists are not a growing tail, so +//! hand-written fork-conditional codecs would have to reproduce a lot of detail +//! that a derive gets from the struct definition. +//! +//! - phase0's `previous_epoch_attestations` and `current_epoch_attestations` do +//! not exist from altair on. They are replaced in position by +//! `previous_epoch_participation` and `current_epoch_participation`, which have +//! a different type. +//! - `latest_execution_payload_header` keeps its name from bellatrix on, but is a +//! different container in bellatrix, capella, and deneb; electra and fulu keep +//! deneb's shape unchanged. +//! - The state's field count crosses a power of two at electra, so its merkle +//! tree is five levels deep through deneb and six from electra on. The same +//! logical field has a different generalized index in different forks. +//! - [`SignedBeaconBlock::Fulu`] is the reverse case: fulu changes no field of a +//! block at all, so its variant wraps [`electra::SignedBeaconBlock`] rather +//! than a `fulu` type that would otherwise be a copy of it. See that variant's +//! doc for why it still needs to be its own variant rather than folded into +//! `Electra`. +//! +//! # Reading the state without matching on the fork +//! +//! About twenty of the state's fields exist unchanged in every fork. The +//! `shared_state_accessors` macro generates their accessors from one list, and +//! that list is this crate's statement of which fields are fork-invariant: if a +//! future fork changes one, it leaves the list and gains an explicit match at +//! each use site. +//! +//! State transition functions therefore read through accessors and match on the +//! fork only where the specification itself changes behavior, so a match arm can +//! be reviewed against the spec's own diff. + +pub mod altair; +pub mod bellatrix; +pub mod capella; +pub mod deneb; +pub mod electra; +pub mod fulu; +pub mod phase0; +pub mod shared; + +pub use shared::*; + +use libssz::{SszDecode as _, SszEncode as _}; + +use crate::beacon::error::{Error, Result}; +use crate::beacon::fork::ForkName; +use crate::beacon::lean_state_unreachable; +use crate::beacon::primitives::{ + BlsSignature, Bytes32, Epoch, Gwei, HashTreeRoot as _, Root, Slot, ValidatorIndex, + WithdrawalIndex, +}; + +/// Runs `$body` against whichever fork's state this is. +/// +/// For the reads every beacon fork answers the same way: the arm list lives here +/// once instead of once per accessor, so a new fork is one line in this macro and +/// one in [`BeaconState::fork_name`] rather than one line in each of twenty match +/// ladders. `$function` names the accessor for the lean arm's panic only. +macro_rules! dispatch_state { + ($self:expr, $function:expr, |$state:ident| $body:expr) => { + match $self { + BeaconState::Phase0($state) => $body, + BeaconState::Altair($state) => $body, + BeaconState::Bellatrix($state) => $body, + BeaconState::Capella($state) => $body, + BeaconState::Deneb($state) => $body, + BeaconState::Electra($state) => $body, + BeaconState::Fulu($state) => $body, + BeaconState::Lean(_) => lean_state_unreachable($function), + } + }; +} + +/// Runs `$body` against whichever state this is, the lean one included. +/// +/// The counterpart to `dispatch_state!` for the two operations that are not +/// beacon-specific at all. Every variant is an SSZ container, lean's as much as +/// any fork's, so encoding one and merkleizing one mean the same thing whichever +/// chain it belongs to, and answering them for lean is what keeps +/// [`BeaconState::from_ssz`] from handing out a value its own encoder rejects. +/// +/// No `$function` parameter, because no arm panics. `$body` has to typecheck for +/// all eight: `to_ssz` does because every variant derives `SszEncode`, and +/// `hash_tree_root` because [`crate::beacon::primitives::HashTreeRoot`] is +/// blanket-implemented over `libssz_merkle::HashTreeRoot` and is the only trait +/// of that name in scope here, so lean's state answers it too, with the same +/// bytes its own `crate::primitives::HashTreeRoot` would produce. +macro_rules! dispatch_state_including_lean { + ($self:expr, |$state:ident| $body:expr) => { + match $self { + BeaconState::Phase0($state) => $body, + BeaconState::Altair($state) => $body, + BeaconState::Bellatrix($state) => $body, + BeaconState::Capella($state) => $body, + BeaconState::Deneb($state) => $body, + BeaconState::Electra($state) => $body, + BeaconState::Fulu($state) => $body, + BeaconState::Lean($state) => $body, + } + }; +} + +/// Runs `$body` against the forks that carry a field, and names the ones that +/// predate it. +/// +/// Same purpose as `dispatch_state!`, for a field the specification introduces +/// partway along the fork schedule: `carried_by` is the forks whose state has it, +/// `absent_from` the forks that answer [`Error::UnsupportedForFork`]. Both lists +/// are spelled out rather than one being derived from the other, so that a new +/// fork does not silently join either side. +macro_rules! dispatch_state_from { + ( + $self:expr, $function:expr, |$state:ident| $body:expr, + carried_by: [$($fork:ident),+ $(,)?], + absent_from: [$($absent:ident),+ $(,)?], + ) => { + match $self { + $(BeaconState::$fork($state) => Ok($body),)+ + $(BeaconState::$absent(_) => Err(Error::UnsupportedForFork { + function: $function, + fork: ForkName::$absent, + }),)+ + BeaconState::Lean(_) => lean_state_unreachable($function), + } + }; +} + +/// Runs `$body` against whichever fork's block this is. +/// +/// [`SignedBeaconBlock`] has no lean variant, so unlike `dispatch_state!` there +/// is no boundary arm and nothing to name in a panic. +macro_rules! dispatch_block { + ($self:expr, |$block:ident| $body:expr) => { + match $self { + SignedBeaconBlock::Phase0($block) => $body, + SignedBeaconBlock::Altair($block) => $body, + SignedBeaconBlock::Bellatrix($block) => $body, + SignedBeaconBlock::Capella($block) => $body, + SignedBeaconBlock::Deneb($block) => $body, + SignedBeaconBlock::Electra($block) => $body, + SignedBeaconBlock::Fulu($block) => $body, + } + }; +} + +/// The beacon state, in whichever fork's shape it currently has, plus the lean +/// state. +/// +/// [`BeaconState::Lean`] is not a Beacon Chain shape. It is here so that one +/// `BlockChainServer` can dispatch on a single state type. Every accessor that +/// reads a *beacon* field treats it as unreachable, and the enforced boundary is +/// the single `match` at the top of each handler. The four operations that are +/// not beacon-specific answer it for real: [`BeaconState::fork_name`], +/// [`BeaconState::from_ssz`], [`BeaconState::to_ssz`] and +/// [`BeaconState::hash_tree_root`], the last three because every variant is an +/// SSZ container whatever chain it came from. +#[derive(Debug, Clone, PartialEq)] +pub enum BeaconState { + Phase0(phase0::BeaconState), + Altair(altair::BeaconState), + Bellatrix(bellatrix::BeaconState), + Capella(capella::BeaconState), + Deneb(deneb::BeaconState), + Electra(electra::BeaconState), + Fulu(fulu::BeaconState), + Lean(crate::state::State), +} + +impl BeaconState { + /// The fork whose rules and shape apply to this state. + pub fn fork_name(&self) -> ForkName { + match self { + BeaconState::Phase0(_) => ForkName::Phase0, + BeaconState::Altair(_) => ForkName::Altair, + BeaconState::Bellatrix(_) => ForkName::Bellatrix, + BeaconState::Capella(_) => ForkName::Capella, + BeaconState::Deneb(_) => ForkName::Deneb, + BeaconState::Electra(_) => ForkName::Electra, + BeaconState::Fulu(_) => ForkName::Fulu, + BeaconState::Lean(_) => ForkName::Lean, + } + } + + /// Decodes a state of a known fork. + /// + /// The fork cannot be recovered from the bytes, since SSZ carries no type + /// tag, so it comes from context: the caller's configuration, or the fixture + /// directory being run. Every fork this crate implements has a shape, so + /// unlike other fork-dispatching functions in this crate, there is no + /// `Error::UnsupportedForFork` arm to fall through to here. + pub fn from_ssz(fork: ForkName, bytes: &[u8]) -> Result { + match fork { + ForkName::Phase0 => Ok(BeaconState::Phase0(phase0::BeaconState::from_ssz_bytes( + bytes, + )?)), + ForkName::Altair => Ok(BeaconState::Altair(altair::BeaconState::from_ssz_bytes( + bytes, + )?)), + ForkName::Bellatrix => Ok(BeaconState::Bellatrix( + bellatrix::BeaconState::from_ssz_bytes(bytes)?, + )), + ForkName::Capella => Ok(BeaconState::Capella(capella::BeaconState::from_ssz_bytes( + bytes, + )?)), + ForkName::Deneb => Ok(BeaconState::Deneb(deneb::BeaconState::from_ssz_bytes( + bytes, + )?)), + ForkName::Electra => Ok(BeaconState::Electra(electra::BeaconState::from_ssz_bytes( + bytes, + )?)), + ForkName::Fulu => Ok(BeaconState::Fulu(fulu::BeaconState::from_ssz_bytes(bytes)?)), + // Lean has a real shape, unlike SignedBeaconBlock::from_ssz's + // ForkName::Lean arm: there is something to build here. + ForkName::Lean => Ok(BeaconState::Lean(crate::state::State::from_ssz_bytes( + bytes, + )?)), + } + } + + /// Encodes the state. + /// + /// Answers for [`BeaconState::Lean`] rather than treating it as unreachable, + /// unlike the accessors that read a beacon field: this is the inverse of + /// [`BeaconState::from_ssz`], which builds that variant, so refusing here + /// would make decoding a state and re-encoding it panic. + pub fn to_ssz(&self) -> Vec { + dispatch_state_including_lean!(self, |state| state.to_ssz()) + } + + /// The state's merkle root, which a block's `state_root` must equal. + /// + /// Answers for [`BeaconState::Lean`] too, for the reason + /// [`BeaconState::to_ssz`] gives. The digest is lean's own state root: both + /// of this crate's `HashTreeRoot` traits merkleize through `libssz_merkle` + /// with the same hasher, and only the wrapper type around the bytes differs. + pub fn hash_tree_root(&self) -> Root { + dispatch_state_including_lean!(self, |state| state.hash_tree_root()) + } +} + +/// Generates read and write accessors for state fields that every fork shares. +/// +/// The `copy` and `reference` lists are this crate's statement of which state +/// fields are fork-invariant. A fork that changes one of them moves it out of the +/// list and gains an explicit match at each use site. +/// +/// Two field lists rather than one, because returning a reference to a `u64` +/// would make the state transition noisier than it needs to be: `copy` fields are +/// returned by value, `reference` fields by reference. Both also get a `_mut` +/// accessor, and both names are given explicitly, since `macro_rules!` cannot +/// concatenate identifiers on stable Rust. +/// +/// The arms come from `dispatch_state!`, which is also why the variant list is +/// not a parameter of this macro: `macro_rules!` zips two repetitions at the same +/// nesting depth rather than nesting them, so a `variants: [...]` list would be +/// iterated in lockstep with the field list instead of once per field. Calling +/// one macro from the other sidesteps that and keeps the fork list in one place. +macro_rules! shared_state_accessors { + ( + copy: [$(($field:ident, $field_mut:ident, $ty:ty)),* $(,)?], + reference: [$(($ref_field:ident, $ref_field_mut:ident, $ref_ty:ty)),* $(,)?], + ) => { + impl BeaconState { + $( + pub fn $field(&self) -> $ty { + dispatch_state!(self, stringify!($field), |state| state.$field) + } + + pub fn $field_mut(&mut self) -> &mut $ty { + dispatch_state!(self, stringify!($field_mut), |state| &mut state.$field) + } + )* + + $( + pub fn $ref_field(&self) -> &$ref_ty { + dispatch_state!(self, stringify!($ref_field), |state| &state.$ref_field) + } + + pub fn $ref_field_mut(&mut self) -> &mut $ref_ty { + dispatch_state!( + self, + stringify!($ref_field_mut), + |state| &mut state.$ref_field + ) + } + )* + } + }; +} + +shared_state_accessors!( + copy: [ + (genesis_time, genesis_time_mut, u64), + (genesis_validators_root, genesis_validators_root_mut, Root), + (slot, slot_mut, Slot), + (eth1_deposit_index, eth1_deposit_index_mut, u64), + (previous_justified_checkpoint, previous_justified_checkpoint_mut, Checkpoint), + (current_justified_checkpoint, current_justified_checkpoint_mut, Checkpoint), + (finalized_checkpoint, finalized_checkpoint_mut, Checkpoint), + ], + reference: [ + (fork, fork_mut, Fork), + (latest_block_header, latest_block_header_mut, BeaconBlockHeader), + (block_roots, block_roots_mut, BlockRoots), + (state_roots, state_roots_mut, StateRoots), + (historical_roots, historical_roots_mut, HistoricalRoots), + (eth1_data, eth1_data_mut, Eth1Data), + (eth1_data_votes, eth1_data_votes_mut, Eth1DataVotes), + (validators, validators_mut, Validators), + (balances, balances_mut, Balances), + (randao_mixes, randao_mixes_mut, RandaoMixes), + (slashings, slashings_mut, Slashings), + (justification_bits, justification_bits_mut, JustificationBits), + ], +); + +impl BeaconState { + /// The validator at `index`. + /// + /// A named error rather than an `Option`, since the specification indexes the + /// registry in many places and an out-of-range index is always a fault. + pub fn validator(&self, index: ValidatorIndex) -> Result<&Validator> { + self.validators() + .get(index as usize) + .ok_or(Error::UnknownValidator(index)) + } + + /// The validator at `index`, mutably. + pub fn validator_mut(&mut self, index: ValidatorIndex) -> Result<&mut Validator> { + self.validators_mut() + .get_mut(index as usize) + .ok_or(Error::UnknownValidator(index)) + } + + /// The balance of the validator at `index`. + pub fn balance(&self, index: ValidatorIndex) -> Result { + self.balances() + .get(index as usize) + .copied() + .ok_or(Error::UnknownValidator(index)) + } + + /// The randao mix for `epoch`, which the specification indexes modulo the + /// vector length so the vector acts as a ring buffer. + pub fn randao_mix(&self, epoch: Epoch) -> Bytes32 { + let mixes = self.randao_mixes(); + mixes[epoch as usize % mixes.len()] + } + + /// The withdrawal sweep's cursor: how many withdrawals the chain has ever + /// made, and which validator the next sweep resumes from. + /// + /// Both exist from capella on, so they cannot join + /// `shared_state_accessors`' fork-invariant lists, and they are read + /// through here rather than through a per-fork projection to a concrete + /// state struct because the sweep that reads them is genuinely shared: deneb + /// reuses capella's `get_expected_withdrawals` unchanged, and a projection + /// returning `&capella::BeaconState` cannot serve a deneb state at all. That + /// mistake was made once here and cost a runtime `UnsupportedForFork` on + /// every deneb block carrying a withdrawal. + pub fn withdrawal_cursor(&self) -> Result<(WithdrawalIndex, ValidatorIndex)> { + dispatch_state_from!( + self, + "BeaconState::withdrawal_cursor", + |state| ( + state.next_withdrawal_index, + state.next_withdrawal_validator_index, + ), + carried_by: [Capella, Deneb, Electra, Fulu], + absent_from: [Phase0, Altair, Bellatrix], + ) + } + + /// The withdrawal sweep's cursor, mutably. See [`Self::withdrawal_cursor`]. + pub fn withdrawal_cursor_mut(&mut self) -> Result<(&mut WithdrawalIndex, &mut ValidatorIndex)> { + dispatch_state_from!( + self, + "BeaconState::withdrawal_cursor_mut", + |state| ( + &mut state.next_withdrawal_index, + &mut state.next_withdrawal_validator_index, + ), + carried_by: [Capella, Deneb, Electra, Fulu], + absent_from: [Phase0, Altair, Bellatrix], + ) + } + + /// The three per-validator lists that exist from altair on, by reference and + /// all at once. + /// + /// These cannot join `shared_state_accessors`' lists, since phase0 has + /// none of them, and a per-fork projection to a concrete state struct (the + /// way `ethlambda_beacon::helpers::altair::altair_state_ref` reaches them) cannot + /// serve every fork that carries them: bellatrix, capella, deneb, electra, + /// and fulu all keep the identical three fields, but each is a distinct + /// Rust type, so a projection typed to return `&altair::BeaconState` can + /// only ever answer for an altair state. + /// + /// Handed back together rather than one accessor per field for the same + /// reason [`Self::altair_validator_lists_mut`] does: the fork condition + /// that gates all three is identical, so one match serves every caller, + /// including one that only needs one or two of the three and destructures + /// the rest away with `_`. + pub fn altair_validator_lists( + &self, + ) -> Result<(&EpochParticipation, &EpochParticipation, &InactivityScores)> { + dispatch_state_from!( + self, + "BeaconState::altair_validator_lists", + |state| ( + &state.previous_epoch_participation, + &state.current_epoch_participation, + &state.inactivity_scores, + ), + carried_by: [Altair, Bellatrix, Capella, Deneb, Electra, Fulu], + absent_from: [Phase0], + ) + } + + /// The three per-validator lists that exist from altair on, mutably and all + /// at once. See [`Self::altair_validator_lists`] for why this cannot be a + /// per-fork projection instead. + /// + /// Handed back together for two reasons that stack: + /// `ethlambda_beacon::stf::operations::add_validator_to_registry` genuinely needs + /// all three, since they are positionally parallel with `validators` and + /// `balances`, so a validator entering the registry has to grow all five + /// or leave the state internally inconsistent in a way nothing else would + /// notice until a `hash_tree_root` came out wrong; and every caller that + /// needs fewer than three still reaches them through this one accessor, + /// discarding what it does not need, rather than a matching per-field + /// accessor that would need the identical fork match written out again. + /// + /// Borrowing three fields of one struct at once is what the tuple is for. + /// Rust permits it because the fields are disjoint, whereas three successive + /// accessor calls would each borrow the whole enum. + pub fn altair_validator_lists_mut( + &mut self, + ) -> Result<( + &mut EpochParticipation, + &mut EpochParticipation, + &mut InactivityScores, + )> { + dispatch_state_from!( + self, + "BeaconState::altair_validator_lists_mut", + |state| ( + &mut state.previous_epoch_participation, + &mut state.current_epoch_participation, + &mut state.inactivity_scores, + ), + carried_by: [Altair, Bellatrix, Capella, Deneb, Electra, Fulu], + absent_from: [Phase0], + ) + } + + /// The current and next sync committee, by reference. + /// + /// Both exist from altair on, byte-for-byte the same field in every later + /// fork (see, for instance, bellatrix's own state doc), so they cannot + /// join `shared_state_accessors`' lists, since phase0 predates sync + /// committees entirely. A per-fork projection cannot serve here either: + /// `ethlambda_beacon::stf::altair::process_sync_aggregate` is called for every + /// fork from altair through fulu (see that function's own documentation), + /// and a projection typed to return `&altair::BeaconState` can only ever answer + /// for an altair state, not for the bellatrix, capella, deneb, electra, or + /// fulu ones the same call site also has to serve. + pub fn sync_committees(&self) -> Result<(&altair::SyncCommittee, &altair::SyncCommittee)> { + dispatch_state_from!( + self, + "BeaconState::sync_committees", + |state| (&state.current_sync_committee, &state.next_sync_committee), + carried_by: [Altair, Bellatrix, Capella, Deneb, Electra, Fulu], + absent_from: [Phase0], + ) + } + + /// The current and next sync committee, mutably. See + /// [`Self::sync_committees`] for why this cannot be a per-fork projection. + /// + /// Handed back together, rather than as two separate accessors, because + /// `ethlambda_beacon::stf::epoch::altair::process_sync_committee_updates` rotates + /// the pair by replacing one with the other at each sync committee period + /// boundary, which needs both mutable borrows alive for the one + /// `core::mem::replace` that does it. + pub fn sync_committees_mut( + &mut self, + ) -> Result<(&mut altair::SyncCommittee, &mut altair::SyncCommittee)> { + dispatch_state_from!( + self, + "BeaconState::sync_committees_mut", + |state| ( + &mut state.current_sync_committee, + &mut state.next_sync_committee, + ), + carried_by: [Altair, Bellatrix, Capella, Deneb, Electra, Fulu], + absent_from: [Phase0], + ) + } +} + +/// A signed block, in whichever fork's shape it currently has. +/// +/// `Fulu` wraps [`electra::SignedBeaconBlock`] rather than a `fulu` type of its +/// own, deliberately: fulu changes no field of a block (see the [`fulu`] module +/// doc), so there is no `fulu::SignedBeaconBlock`, and this crate must not +/// invent one just to fill out the enum. The variant still has to exist and +/// stay distinct from `Electra`, because fulu does change how a block is +/// processed even though it does not change what a block is: `get_blob_parameters` +/// makes the blob commitment limit `process_operations` checks depend on the +/// epoch rather than being a single fixed preset from electra on. Code that +/// dispatches on fork therefore still needs to be able to tell a fulu block +/// from an electra one, even though both carry the identical +/// `electra::SignedBeaconBlock` payload. +#[derive(Debug, Clone, PartialEq)] +pub enum SignedBeaconBlock { + Phase0(phase0::SignedBeaconBlock), + Altair(altair::SignedBeaconBlock), + Bellatrix(bellatrix::SignedBeaconBlock), + Capella(capella::SignedBeaconBlock), + Deneb(deneb::SignedBeaconBlock), + Electra(electra::SignedBeaconBlock), + /// Fulu's block. See the enum doc for why this wraps + /// [`electra::SignedBeaconBlock`] instead of a `fulu` type. + Fulu(electra::SignedBeaconBlock), +} + +impl SignedBeaconBlock { + /// The fork whose rules apply to this block. + /// + /// Not the same question as "what shape is this value": `Fulu` and + /// `Electra` answer this differently while sharing a shape, which is the + /// whole reason `Fulu` is its own variant rather than being folded into + /// `Electra`. + pub fn fork_name(&self) -> ForkName { + match self { + SignedBeaconBlock::Phase0(_) => ForkName::Phase0, + SignedBeaconBlock::Altair(_) => ForkName::Altair, + SignedBeaconBlock::Bellatrix(_) => ForkName::Bellatrix, + SignedBeaconBlock::Capella(_) => ForkName::Capella, + SignedBeaconBlock::Deneb(_) => ForkName::Deneb, + SignedBeaconBlock::Electra(_) => ForkName::Electra, + SignedBeaconBlock::Fulu(_) => ForkName::Fulu, + } + } + + /// Decodes a signed block of a known fork. + /// + /// The fork cannot be recovered from the bytes, since SSZ carries no type + /// tag, so it comes from context, the same way [`BeaconState::from_ssz`]'s + /// does. `ForkName::Fulu` decodes as [`electra::SignedBeaconBlock`], since + /// that is the type [`SignedBeaconBlock::Fulu`] wraps. + pub fn from_ssz(fork: ForkName, bytes: &[u8]) -> Result { + match fork { + ForkName::Phase0 => Ok(SignedBeaconBlock::Phase0( + phase0::SignedBeaconBlock::from_ssz_bytes(bytes)?, + )), + ForkName::Altair => Ok(SignedBeaconBlock::Altair( + altair::SignedBeaconBlock::from_ssz_bytes(bytes)?, + )), + ForkName::Bellatrix => Ok(SignedBeaconBlock::Bellatrix( + bellatrix::SignedBeaconBlock::from_ssz_bytes(bytes)?, + )), + ForkName::Capella => Ok(SignedBeaconBlock::Capella( + capella::SignedBeaconBlock::from_ssz_bytes(bytes)?, + )), + ForkName::Deneb => Ok(SignedBeaconBlock::Deneb( + deneb::SignedBeaconBlock::from_ssz_bytes(bytes)?, + )), + ForkName::Electra => Ok(SignedBeaconBlock::Electra( + electra::SignedBeaconBlock::from_ssz_bytes(bytes)?, + )), + ForkName::Fulu => Ok(SignedBeaconBlock::Fulu( + electra::SignedBeaconBlock::from_ssz_bytes(bytes)?, + )), + // There is no lean variant of SignedBeaconBlock, and this fork + // value comes straight from the caller, so a bad argument is + // reported rather than crashing. + ForkName::Lean => Err(Error::UnsupportedForFork { + function: "SignedBeaconBlock::from_ssz", + fork: ForkName::Lean, + }), + } + } + + /// Encodes the signed block. + pub fn to_ssz(&self) -> Vec { + dispatch_block!(self, |block| block.to_ssz()) + } + + /// The merkle root of the unsigned `message`, which is what the proposer's + /// `signature` is actually over. + /// + /// Deliberately not named `hash_tree_root`: that name is left free for the + /// root of the whole signed container (message and signature together), + /// which no code in this crate needs yet but which would mean something + /// different from this method if added later. + pub fn message_hash_tree_root(&self) -> Root { + dispatch_block!(self, |block| block.message.hash_tree_root()) + } +} + +/// Generates read accessors for signed-block fields that every fork shares. +/// +/// A signed block has far fewer share points than [`BeaconState`], and none of +/// them need a `_mut` accessor, since nothing in this crate mutates a decoded +/// block in place. The list is still split in two, the same way +/// `shared_state_accessors`'s is: every field here happens to be `Copy`, so +/// the split is not `copy` versus `reference` but `message` versus `outer`, +/// separating the fields nested under `message` from `signature`, the one +/// field [`SignedBeaconBlock`] carries directly. As with +/// `shared_state_accessors`, the arms come from `dispatch_block!` rather than +/// from a variant list of this macro's own. +macro_rules! signed_beacon_block_accessors { + ( + message: [$(($field:ident, $ty:ty)),* $(,)?], + outer: [$(($outer_field:ident, $outer_ty:ty)),* $(,)?], + ) => { + impl SignedBeaconBlock { + $( + pub fn $field(&self) -> $ty { + dispatch_block!(self, |block| block.message.$field) + } + )* + + $( + pub fn $outer_field(&self) -> $outer_ty { + dispatch_block!(self, |block| block.$outer_field) + } + )* + } + }; +} + +signed_beacon_block_accessors!( + message: [ + (slot, Slot), + (proposer_index, ValidatorIndex), + (parent_root, Root), + (state_root, Root), + ], + outer: [ + (signature, BlsSignature), + ], +); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn a_lean_state_reports_the_lean_fork() { + let state = BeaconState::Lean(crate::state::State::from_genesis(0, Vec::new())); + assert_eq!(state.fork_name(), ForkName::Lean); + } + + #[test] + fn a_lean_state_round_trips_through_the_beacon_enum() { + // `from_ssz` builds the Lean variant, so its inverse has to accept one. + // Before `to_ssz` answered for lean, decoding a state and re-encoding it + // panicked, which is the one asymmetry this enum cannot afford: it is + // exactly what a `BlockChainServer` dispatching on a configured fork + // does. + let lean = crate::state::State::from_genesis(0, Vec::new()); + let bytes = BeaconState::Lean(lean.clone()).to_ssz(); + + let decoded = BeaconState::from_ssz(ForkName::Lean, &bytes).expect("a lean state"); + assert_eq!(decoded, BeaconState::Lean(lean.clone())); + assert_eq!(decoded.to_ssz(), bytes); + } + + #[test] + fn a_lean_state_merkleizes_to_its_own_root() { + // Not merely "does not panic": the digest has to be the one lean's own + // trait produces, since a block's `state_root` is checked against it. + // Only the wrapper type around the bytes differs. Lean's trait is named + // through its full path rather than imported: both are blanket impls + // over `libssz_merkle::HashTreeRoot`, so bringing the second one into + // scope would make the call ambiguous. + let lean = crate::state::State::from_genesis(0, Vec::new()); + let via_beacon = BeaconState::Lean(lean.clone()).hash_tree_root(); + let via_lean = crate::primitives::HashTreeRoot::hash_tree_root(&lean); + + assert_eq!(via_beacon.0, via_lean.0); + } + + #[test] + #[should_panic(expected = "lean state reached a beacon accessor")] + fn a_lean_state_panics_in_a_beacon_accessor() { + // The guarantee is structural, not type-level: BeaconState::Lean is + // constructible anywhere, so this pins the failure mode to a named + // panic rather than a silent wrong answer. + let state = BeaconState::Lean(crate::state::State::from_genesis(0, Vec::new())); + let _ = state.slot(); + } +} diff --git a/crates/common/types/src/beacon/containers/phase0.rs b/crates/common/types/src/beacon/containers/phase0.rs new file mode 100644 index 000000000..ee9438c86 --- /dev/null +++ b/crates/common/types/src/beacon/containers/phase0.rs @@ -0,0 +1,269 @@ +//! Containers whose shape is specific to phase0. +//! +//! The distinguishing feature of phase0's state is that it accumulates whole +//! attestations, in `previous_epoch_attestations` and +//! `current_epoch_attestations`, and replays them at the epoch boundary to work +//! out who voted for what. Altair replaces that with per-validator participation +//! flags recorded as each attestation is processed, which is both cheaper and +//! bounded, and drops these two fields entirely. + +use libssz_derive::{HashTreeRoot, SszDecode, SszEncode}; +use libssz_types::{SszBitlist, SszList}; + +use super::shared::{ + AttestationData, BeaconBlockHeader, Checkpoint, Deposit, Eth1Data, Eth1DataVotes, Fork, + ProposerSlashing, SignedVoluntaryExit, +}; +use super::shared::{ + Balances, BlockRoots, HistoricalRoots, JustificationBits, RandaoMixes, Slashings, StateRoots, + Validators, +}; +use crate::beacon::preset; +use crate::beacon::primitives::{BlsSignature, Bytes32, Root, Slot, ValidatorIndex}; + +/// The attesters covered by one aggregate, as a bit per committee member. +/// +/// Bounded by the largest a single committee can be, since a phase0 attestation +/// covers exactly one committee. Electra widens this to a whole slot's worth of +/// committees. +pub type AggregationBits = SszBitlist<{ preset::MAX_VALIDATORS_PER_COMMITTEE }>; + +/// The attesters covered by one aggregate, named explicitly rather than as a +/// bitfield, which is the form signature verification needs. +pub type AttestingIndices = SszList; + +/// Attestations retained in the state, awaiting the epoch boundary. +pub type PendingAttestations = SszList; + +// --------------------------------------------------------------------------- +// Attestations +// --------------------------------------------------------------------------- + +/// An aggregate attestation, as gossiped and as included in a block. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct Attestation { + pub aggregation_bits: AggregationBits, + pub data: AttestationData, + /// The aggregate signature of every attester set in `aggregation_bits`, over + /// `data`. + pub signature: BlsSignature, +} + +/// An attestation with its attesters named rather than bit-encoded. +/// +/// Signature verification needs the public keys, which needs the indices, so the +/// state transition converts an [`Attestation`] into this form before checking +/// it. Slashing evidence is expressed in this form too, since a slashing has to +/// be checkable without the committee that produced it. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct IndexedAttestation { + /// The attesters, which the specification requires to be sorted and unique. + pub attesting_indices: AttestingIndices, + pub data: AttestationData, + pub signature: BlsSignature, +} + +/// Evidence that a set of validators made two conflicting attestations. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct AttesterSlashing { + pub attestation_1: IndexedAttestation, + pub attestation_2: IndexedAttestation, +} + +/// An attestation retained in the state until the epoch boundary. +/// +/// Phase0 cannot score an attestation when it arrives, because the reward +/// depends on facts not yet settled, so it stores the attestation along with the +/// two things it will need later and defers the work. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct PendingAttestation { + pub aggregation_bits: AggregationBits, + pub data: AttestationData, + /// How many slots passed between the attested slot and the block that + /// included this attestation. Rewards scale inversely with it, which is what + /// pays for prompt attesting. + pub inclusion_delay: Slot, + /// Who included it, so that the proposer reward can be paid at the epoch + /// boundary to a proposer identified when the attestation arrived. + pub proposer_index: ValidatorIndex, +} + +// --------------------------------------------------------------------------- +// Blocks +// --------------------------------------------------------------------------- + +/// The contents of a block: everything the proposer chose to include. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconBlockBody { + /// The proposer's contribution to the chain's randomness, which is a + /// signature over the current epoch and so cannot be chosen freely. + pub randao_reveal: BlsSignature, + /// The proposer's vote on the execution chain's deposit state. + pub eth1_data: Eth1Data, + /// Arbitrary proposer-chosen bytes, which consensus never reads. + pub graffiti: Bytes32, + pub proposer_slashings: SszList, + pub attester_slashings: SszList, + pub attestations: SszList, + pub deposits: SszList, + pub voluntary_exits: SszList, +} + +/// A block. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconBlock { + pub slot: Slot, + pub proposer_index: ValidatorIndex, + pub parent_root: Root, + /// The root of the state after this block is applied, which the state + /// transition recomputes and compares. + pub state_root: Root, + pub body: BeaconBlockBody, +} + +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SignedBeaconBlock { + pub message: BeaconBlock, + pub signature: BlsSignature, +} + +// --------------------------------------------------------------------------- +// State +// --------------------------------------------------------------------------- + +/// The phase0 beacon state: 21 fields, in the specification's order. +/// +/// Field order is load-bearing. SSZ encoding and merkleization both follow +/// declaration order, so reordering or omitting a field silently produces a +/// wrong `hash_tree_root`. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconState { + // -- Versioning -- + pub genesis_time: u64, + /// The root of the genesis validator registry, which separates this chain + /// from any other running the same fork schedule. + pub genesis_validators_root: Root, + pub slot: Slot, + pub fork: Fork, + + // -- History -- + /// The most recent block's header, with `state_root` left zero until the slot + /// advances, since a block cannot commit to the root of the state containing + /// it. + pub latest_block_header: BeaconBlockHeader, + pub block_roots: BlockRoots, + pub state_roots: StateRoots, + pub historical_roots: HistoricalRoots, + + // -- Eth1 -- + pub eth1_data: Eth1Data, + pub eth1_data_votes: Eth1DataVotes, + /// How many deposits from the contract have been processed, which is where + /// the next one will be read from. + pub eth1_deposit_index: u64, + + // -- Registry -- + pub validators: Validators, + pub balances: Balances, + + // -- Randomness -- + pub randao_mixes: RandaoMixes, + + // -- Slashings -- + pub slashings: Slashings, + + // -- Attestations -- + /// Attestations for the previous epoch, replayed at the epoch boundary. Only + /// phase0 has these; altair replaces them with participation flags. + pub previous_epoch_attestations: PendingAttestations, + /// Attestations for the current epoch, which become + /// `previous_epoch_attestations` at the next boundary. + pub current_epoch_attestations: PendingAttestations, + + // -- Finality -- + pub justification_bits: JustificationBits, + pub previous_justified_checkpoint: Checkpoint, + pub current_justified_checkpoint: Checkpoint, + pub finalized_checkpoint: Checkpoint, +} + +// --------------------------------------------------------------------------- +// Validator-side containers +// --------------------------------------------------------------------------- + +/// An aggregate together with proof that its aggregator was selected to produce +/// it. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct AggregateAndProof { + pub aggregator_index: ValidatorIndex, + pub aggregate: Attestation, + /// The aggregator's signature over the slot, which is what makes selection + /// verifiable rather than self-declared. + pub selection_proof: BlsSignature, +} + +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SignedAggregateAndProof { + pub message: AggregateAndProof, + pub signature: BlsSignature, +} + +#[cfg(test)] +mod tests { + use libssz::{SszDecode as _, SszEncode as _}; + + use super::*; + + #[test] + fn pending_attestation_round_trips_through_ssz() { + let attestation = PendingAttestation { + aggregation_bits: { + let mut bits = AggregationBits::with_length(5).unwrap(); + bits.set(0, true).unwrap(); + bits.set(3, true).unwrap(); + bits + }, + data: AttestationData::default(), + inclusion_delay: 2, + proposer_index: 9, + }; + + let bytes = attestation.to_ssz(); + assert_eq!( + PendingAttestation::from_ssz_bytes(&bytes).unwrap(), + attestation + ); + } + + #[test] + fn variable_length_containers_carry_offsets() { + // Each of these holds at least one list or bitlist, so its encoding + // begins with offsets rather than being a fixed layout. The state, the + // body, and an attestation are the three that matter. + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + assert!(!::is_fixed_size()); + } + + #[test] + fn block_body_round_trips_while_empty() { + // An empty body is the common case for a skipped-operation slot, and it + // exercises every offset in the encoding with zero-length payloads. + let body = BeaconBlockBody { + randao_reveal: BlsSignature::default(), + eth1_data: Eth1Data::default(), + graffiti: Bytes32::ZERO, + proposer_slashings: Default::default(), + attester_slashings: Default::default(), + attestations: Default::default(), + deposits: Default::default(), + voluntary_exits: Default::default(), + }; + + let bytes = body.to_ssz(); + assert_eq!(BeaconBlockBody::from_ssz_bytes(&bytes).unwrap(), body); + } +} diff --git a/crates/common/types/src/beacon/containers/shared.rs b/crates/common/types/src/beacon/containers/shared.rs new file mode 100644 index 000000000..a9de858ad --- /dev/null +++ b/crates/common/types/src/beacon/containers/shared.rs @@ -0,0 +1,372 @@ +//! Containers whose definition does not change between forks, and the SSZ +//! collection aliases the per-fork modules build on. +//! +//! A container belongs here only if every fork that has it defines it +//! identically. Anything a fork reshapes lives in that fork's module instead, so +//! that a reader looking for "what changed in electra" finds it in one place. +//! +//! This module grows as forks land. It currently covers what phase0 needs. + +use libssz_derive::{HashTreeRoot, SszDecode, SszEncode}; +use libssz_types::{SszBitvector, SszList, SszVector}; + +use crate::beacon::constants; +use crate::beacon::preset; +use crate::beacon::primitives::{ + BlsPubkey, BlsSignature, Bytes32, CommitteeIndex, Domain, Epoch, Gwei, ParticipationFlags, + Root, Slot, ValidatorIndex, Version, +}; + +// --------------------------------------------------------------------------- +// Collection aliases +// --------------------------------------------------------------------------- +// +// A const-generic argument that is a path needs braces, so these read +// `{ preset::X }` rather than `preset::X`. + +/// The rolling window of recent block roots the state keeps, indexed by slot +/// modulo its length so it acts as a ring buffer. +pub type BlockRoots = SszVector; + +/// The rolling window of recent state roots, indexed the same way as +/// [`BlockRoots`]. +pub type StateRoots = SszVector; + +/// Accumulated roots of [`HistoricalBatch`], one appended per historical batch, +/// which is how the chain keeps a commitment to history older than the rolling +/// windows without keeping the roots themselves. +pub type HistoricalRoots = SszList; + +/// Eth1 data votes accumulated over one voting period, tallied and then reset. +pub type Eth1DataVotes = SszList; + +/// The validator registry. Append-only: a validator is never removed, only +/// exited, since indices are referenced by attestations and must stay stable. +pub type Validators = SszList; + +/// Balances, positionally parallel to [`Validators`]. +/// +/// Kept separate from the registry rather than as a `Validator` field because it +/// changes every epoch while the rest of a validator's record rarely does, and a +/// separate list means rewards do not redirty the registry's merkle tree. +pub type Balances = SszList; + +/// Past randao mixes, indexed by epoch modulo the vector length, so the state +/// retains a bounded history of the beacon chain's randomness. +pub type RandaoMixes = SszVector; + +/// Slashed balance totals per epoch, indexed by epoch modulo the vector length. +/// Epoch processing reads the whole vector to size the proportional slashing +/// penalty, which is what makes correlated slashings cost more than isolated +/// ones. +pub type Slashings = SszVector; + +/// One bit per recent epoch recording whether it was justified, which is the +/// state that lets finalization look back over several epochs at once. +pub type JustificationBits = SszBitvector<{ constants::JUSTIFICATION_BITS_LENGTH }>; + +/// The merkle path proving a deposit against the deposit contract's root. +/// +/// One longer than the contract's tree depth, since the extra node is the +/// mix-in of the deposit count. +pub type DepositProof = SszVector; + +/// Per-validator participation flags for one epoch, positionally parallel to +/// [`Validators`]. Altair uses this in place of phase0's accumulated +/// attestations. +pub type EpochParticipation = SszList; + +/// Per-validator inactivity scores, positionally parallel to [`Validators`] +/// (altair and later). +pub type InactivityScores = SszList; + +/// Accumulated [`HistoricalSummary`] entries, which replace [`HistoricalRoots`] +/// as the commitment to history from capella onward. +pub type HistoricalSummaries = SszList; + +// --------------------------------------------------------------------------- +// Misc +// --------------------------------------------------------------------------- + +/// Which fork the chain is on, and which one it came from. +/// +/// Both versions are kept because a signature is verified under the fork version +/// in effect when the message was signed, so a message from just before a fork +/// boundary still verifies just after it. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct Fork { + /// The version in effect before [`Fork::epoch`]. + pub previous_version: Version, + /// The version in effect from [`Fork::epoch`] onward. + pub current_version: Version, + /// The epoch at which `current_version` took effect. + pub epoch: Epoch, +} + +/// A fork version paired with the chain's genesis validators root, hashed +/// together to produce a signing domain. +/// +/// Including the genesis validators root is what separates two chains running +/// the same fork schedule: a signature from one never verifies on the other. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct ForkData { + pub current_version: Version, + pub genesis_validators_root: Root, +} + +/// An epoch and the block root at its start: what attestations vote on and what +/// justification and finalization track. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct Checkpoint { + pub epoch: Epoch, + /// The root of the first block of [`Checkpoint::epoch`], or of the most + /// recent block before it if that slot was empty. + pub root: Root, +} + +/// A registry entry for one validator. +#[derive(Debug, Clone, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct Validator { + /// The key attestations and proposals are signed with. + pub pubkey: BlsPubkey, + /// Where a withdrawal pays out. The first byte selects how the rest is + /// interpreted; see the prefixes in [`crate::beacon::constants`]. + pub withdrawal_credentials: Bytes32, + /// The balance actually used for voting weight and rewards, which is the + /// real balance rounded down to a multiple of `EFFECTIVE_BALANCE_INCREMENT` + /// and capped. Rounding with hysteresis is what keeps the merkle tree from + /// being redirtied by every small balance change. + pub effective_balance: Gwei, + pub slashed: bool, + /// The epoch the validator's balance first reached the activation minimum, + /// making it a candidate for activation. Distinct from + /// [`Validator::activation_epoch`], which is when the churn limit actually + /// let it in: eligibility is immediate, activation is queued. + pub activation_eligibility_epoch: Epoch, + /// The epoch the validator became active. + pub activation_epoch: Epoch, + /// The epoch the validator stops being active. + pub exit_epoch: Epoch, + /// The epoch the validator's balance may be withdrawn, which lags + /// [`Validator::exit_epoch`] so that slashable offences remain punishable + /// for a while after exit. + pub withdrawable_epoch: Epoch, +} + +/// What an attestation actually attests to. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct AttestationData { + /// The slot being attested for. + pub slot: Slot, + /// Which of the slot's committees the attester belongs to. + pub index: CommitteeIndex, + /// The attester's view of the head of the chain, which is the LMD GHOST + /// vote. + pub beacon_block_root: Root, + /// The justified checkpoint the attester builds on, which is the FFG vote's + /// source. + pub source: Checkpoint, + /// The checkpoint the attester is trying to justify, which is the FFG vote's + /// target. + pub target: Checkpoint, +} + +/// The execution chain's deposit state, as voted on by proposers. +#[derive(Debug, Clone, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct Eth1Data { + /// The deposit contract's merkle root at this point. + pub deposit_root: Root, + /// The total number of deposits the contract has ever seen, not the number + /// still unprocessed. + pub deposit_count: u64, + pub block_hash: Root, +} + +/// The parts of an execution layer block a proposer needs in order to vote on +/// [`Eth1Data`]. +/// +/// The specification defines only these three fields and notes the rest are +/// omitted, since nothing in consensus reads them. +#[derive(Debug, Clone, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct Eth1Block { + pub timestamp: u64, + pub deposit_root: Root, + pub deposit_count: u64, +} + +/// A window of block and state roots, whose root is appended to +/// [`HistoricalRoots`] once the window is full. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct HistoricalBatch { + pub block_roots: BlockRoots, + pub state_roots: StateRoots, +} + +/// A commitment to one historical window, replacing [`HistoricalBatch`] roots +/// from capella onward. +/// +/// Keeping the two roots separately, rather than hashing them together as +/// [`HistoricalBatch`] does, is what lets a light client prove a block root +/// against history without also having the state roots. +#[derive(Debug, Clone, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct HistoricalSummary { + pub block_summary_root: Root, + pub state_summary_root: Root, +} + +/// A root paired with the domain it is signed under, hashed together to give the +/// message a signature actually covers. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SigningData { + pub object_root: Root, + pub domain: Domain, +} + +// --------------------------------------------------------------------------- +// Deposits +// --------------------------------------------------------------------------- + +/// The part of a deposit a depositor signs. +/// +/// Separate from [`DepositData`] precisely because the signature cannot cover +/// itself: the signature in `DepositData` is over the `DepositMessage` with the +/// same fields. +#[derive(Debug, Clone, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct DepositMessage { + pub pubkey: BlsPubkey, + pub withdrawal_credentials: Bytes32, + pub amount: Gwei, +} + +/// A deposit as recorded by the deposit contract. +#[derive(Debug, Clone, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct DepositData { + pub pubkey: BlsPubkey, + pub withdrawal_credentials: Bytes32, + pub amount: Gwei, + /// Proof of possession over the corresponding [`DepositMessage`]. An invalid + /// signature does not make the deposit invalid: it is simply not credited to + /// a new validator, which is why the public key here is never assumed to be a + /// valid curve point. + pub signature: BlsSignature, +} + +/// A deposit together with its merkle proof against the deposit contract root. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct Deposit { + pub proof: DepositProof, + pub data: DepositData, +} + +// --------------------------------------------------------------------------- +// Block headers and operations +// --------------------------------------------------------------------------- + +/// A block without its body, which is what the state retains and what proposer +/// slashings compare. +#[derive(Debug, Clone, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct BeaconBlockHeader { + pub slot: Slot, + pub proposer_index: ValidatorIndex, + pub parent_root: Root, + /// The root of the state after applying this block. Left zero in the state's + /// own copy of the latest header until the slot advances, since a block + /// cannot commit to the root of the state that contains it. + pub state_root: Root, + /// The root of the body, which is what lets the header stand in for the + /// whole block. + pub body_root: Root, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SignedBeaconBlockHeader { + pub message: BeaconBlockHeader, + pub signature: BlsSignature, +} + +/// Evidence that a proposer signed two different blocks for the same slot. +#[derive(Debug, Clone, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct ProposerSlashing { + pub signed_header_1: SignedBeaconBlockHeader, + pub signed_header_2: SignedBeaconBlockHeader, +} + +/// A validator's request to stop validating. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct VoluntaryExit { + /// The earliest epoch the exit may be processed at. + pub epoch: Epoch, + pub validator_index: ValidatorIndex, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct SignedVoluntaryExit { + pub message: VoluntaryExit, + pub signature: BlsSignature, +} + +#[cfg(test)] +mod tests { + use libssz::{SszDecode as _, SszEncode as _}; + + use super::*; + + #[test] + fn checkpoint_is_fixed_size() { + // An epoch and a root, with nothing variable-length, so the encoding has + // one length for every value. + assert!(::is_fixed_size()); + assert_eq!(::fixed_size(), 8 + 32); + } + + #[test] + fn validator_round_trips_through_ssz() { + let validator = Validator { + pubkey: BlsPubkey([3; 48]), + withdrawal_credentials: Bytes32::repeat_byte(7), + effective_balance: 32_000_000_000, + slashed: true, + activation_eligibility_epoch: 1, + activation_epoch: 2, + exit_epoch: 3, + withdrawable_epoch: 4, + }; + + let bytes = validator.to_ssz(); + assert_eq!(Validator::from_ssz_bytes(&bytes).unwrap(), validator); + } + + #[test] + fn deposit_is_fixed_size_despite_holding_a_proof() { + // Every field of a Deposit is itself fixed-length, including the proof + // vector, so the container is fixed-size and carries no offsets. + assert!(::is_fixed_size()); + } + + #[test] + fn every_fork_invariant_container_is_fixed_size() { + // Worth asserting rather than assuming: none of the containers in this + // module has a variable-length field, not even the ones holding + // collections, since those collections are all `Vector`s of fixed-size + // elements. Every variable-length container in phase0 (`Attestation` with + // its bitlist, `BeaconBlockBody` with its operation lists, `BeaconState`) + // is fork-specific and lives elsewhere. So an offset appearing anywhere + // in this module's encodings would mean something changed shape. + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + assert!(::is_fixed_size()); + } +} diff --git a/crates/common/types/src/beacon/error.rs b/crates/common/types/src/beacon/error.rs new file mode 100644 index 000000000..6db1db528 --- /dev/null +++ b/crates/common/types/src/beacon/error.rs @@ -0,0 +1,70 @@ +//! The crate's error type. +//! +//! The specification expresses validity conditions as `assert` statements. Each +//! one becomes an [`Error::SpecAssert`] carrying the condition it checked, which +//! keeps the enum small while still naming the failing rule in test output. The +//! structured variants exist for conditions worth inspecting programmatically +//! or worth reporting with their values. + +use crate::beacon::fork::ForkName; + +pub type Result = core::result::Result; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// A validity condition from the specification did not hold. The message is + /// the condition, phrased as the spec phrases it. + #[error("spec assertion failed: {0}")] + SpecAssert(&'static str), + + /// A function that the specification introduces in a later fork was called + /// on an earlier state. + #[error("{function} does not exist in {fork}")] + UnsupportedForFork { + function: &'static str, + fork: ForkName, + }, + + #[error("index {index} out of bounds, length {len}")] + IndexOutOfBounds { index: usize, len: usize }, + + #[error("no validator at index {0}")] + UnknownValidator(u64), + + #[error("arithmetic overflow in {0}")] + ArithmeticOverflow(&'static str), + + #[error("signature verification failed for {0}")] + InvalidSignature(&'static str), + + #[error("SSZ decoding failed: {0:?}")] + SszDecode(libssz::DecodeError), + + /// A bounded SSZ collection was given more elements than its type permits. + #[error("SSZ type error: {0:?}")] + SszType(libssz_types::TypeError), +} + +impl From for Error { + fn from(err: libssz::DecodeError) -> Self { + Error::SszDecode(err) + } +} + +impl From for Error { + fn from(err: libssz_types::TypeError) -> Self { + Error::SszType(err) + } +} + +/// Returns `Err(Error::SpecAssert)` unless `condition` holds. +/// +/// Mirrors the specification's `assert` statements, so a reader can match the +/// implementation against the spec line by line. +pub fn verify(condition: bool, what: &'static str) -> Result<()> { + if condition { + Ok(()) + } else { + Err(Error::SpecAssert(what)) + } +} diff --git a/crates/common/types/src/beacon/fork.rs b/crates/common/types/src/beacon/fork.rs new file mode 100644 index 000000000..5578b548b --- /dev/null +++ b/crates/common/types/src/beacon/fork.rs @@ -0,0 +1,219 @@ +//! Fork identity. +//! +//! The variant order is the fork order, so the derived [`Ord`] is the comparison +//! the state transition uses to gate behavior: `fork >= ForkName::Altair` reads +//! as "altair or later", matching how the specification introduces changes. + +use core::fmt; + +/// A named fork of the Beacon Chain, ordered oldest to newest, followed by +/// Lean. +/// +/// The variant order is the fork order, so the derived [`Ord`] is the comparison +/// the state transition uses to gate behavior: `fork >= ForkName::Altair` reads +/// as "altair or later". +/// +/// [`ForkName::Lean`] is last so that every such gate reads as true for a lean +/// state, and is deliberately absent from [`ForkName::ALL`]: lean is not a point +/// on the Beacon Chain's fork timeline, has no spec fixtures, and must never be +/// a target of `ethlambda_beacon::upgrade`-style traversal. See +/// [`ForkName::ALL`]. +/// +/// Forks after fulu exist upstream but are out of scope for this crate. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum ForkName { + Phase0, + Altair, + Bellatrix, + Capella, + Deneb, + Electra, + Fulu, + /// The Lean consensus protocol, which this repository implements alongside + /// the Beacon Chain. Not a Beacon Chain fork, and not in [`ForkName::ALL`]. + Lean, +} + +impl ForkName { + /// Every *Beacon Chain* fork this crate implements, in order. + /// + /// [`ForkName::Lean`] is not here: it is not a Beacon Chain fork. Because + /// `parse`, `previous`, `next`, and the spec-fixture harness all search this + /// array, its absence is what makes `parse("lean")` return `None`, keeps + /// `Fulu.next()` at `None`, and stops any fixture directory from resolving + /// to a lean case. + pub const ALL: [ForkName; 7] = [ + ForkName::Phase0, + ForkName::Altair, + ForkName::Bellatrix, + ForkName::Capella, + ForkName::Deneb, + ForkName::Electra, + ForkName::Fulu, + ]; + + /// The lowercase name the specification and its fixture paths use. + pub fn as_str(self) -> &'static str { + match self { + ForkName::Phase0 => "phase0", + ForkName::Altair => "altair", + ForkName::Bellatrix => "bellatrix", + ForkName::Capella => "capella", + ForkName::Deneb => "deneb", + ForkName::Electra => "electra", + ForkName::Fulu => "fulu", + ForkName::Lean => "lean", + } + } + + /// Parses a fork name as written in the specification and its fixture paths. + /// + /// Returns `None` for forks outside this crate's scope, which lets fixture + /// runners skip unsupported directories rather than fail on them. + pub fn parse(name: &str) -> Option { + ForkName::ALL.into_iter().find(|f| f.as_str() == name) + } + + /// The fork immediately before this one, or `None` for phase0. + pub fn previous(self) -> Option { + let index = ForkName::ALL.iter().position(|f| *f == self)?; + index.checked_sub(1).map(|i| ForkName::ALL[i]) + } + + /// The fork immediately after this one, or `None` for the newest. + pub fn next(self) -> Option { + let index = ForkName::ALL.iter().position(|f| *f == self)?; + ForkName::ALL.get(index + 1).copied() + } + + /// The one-byte tag this fork is stored under in a `States` value. + /// + /// Spelled out rather than `self as u8`. The variant order is already + /// load-bearing for the derived [`Ord`] (see this enum's own doc), so + /// deriving the on-disk tag from it too would mean a reorder made for the + /// ordering's sake silently reinterpreted every state already written. + /// + /// [`ForkName::Lean`] takes 255 rather than 7 so that the beacon forks after + /// fulu can keep taking the next free value as they land. + pub const fn selector(self) -> u8 { + match self { + ForkName::Phase0 => 0, + ForkName::Altair => 1, + ForkName::Bellatrix => 2, + ForkName::Capella => 3, + ForkName::Deneb => 4, + ForkName::Electra => 5, + ForkName::Fulu => 6, + ForkName::Lean => 255, + } + } + + /// The inverse of [`ForkName::selector`]. + /// + /// `None` for a byte this build does not know, which means a corrupt or + /// future-format database rather than anything a caller can recover from. + pub const fn from_selector(byte: u8) -> Option { + match byte { + 0 => Some(ForkName::Phase0), + 1 => Some(ForkName::Altair), + 2 => Some(ForkName::Bellatrix), + 3 => Some(ForkName::Capella), + 4 => Some(ForkName::Deneb), + 5 => Some(ForkName::Electra), + 6 => Some(ForkName::Fulu), + 255 => Some(ForkName::Lean), + _ => None, + } + } +} + +impl fmt::Display for ForkName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ordering_follows_fork_order() { + assert!(ForkName::Phase0 < ForkName::Altair); + assert!(ForkName::Deneb < ForkName::Electra); + assert!(ForkName::Fulu > ForkName::Phase0); + } + + #[test] + fn parse_round_trips_every_fork() { + for fork in ForkName::ALL { + assert_eq!(ForkName::parse(fork.as_str()), Some(fork)); + } + assert_eq!(ForkName::parse("gloas"), None); + } + + #[test] + fn neighbours_terminate_at_the_ends() { + assert_eq!(ForkName::Phase0.previous(), None); + assert_eq!(ForkName::Fulu.next(), None); + assert_eq!(ForkName::Altair.previous(), Some(ForkName::Phase0)); + assert_eq!(ForkName::Altair.next(), Some(ForkName::Bellatrix)); + } + + #[test] + fn lean_sorts_after_every_beacon_fork() { + // "Lean is the next fork": every `fork >= ForkName::X` gate in the + // state transition reads as true for a lean state. + for fork in ForkName::ALL { + assert!(ForkName::Lean > fork, "Lean must outrank {fork}"); + } + } + + #[test] + fn lean_is_not_a_beacon_fork() { + // ALL drives `parse`, `previous`, `next`, and the fixture harness's + // test-list construction. Lean is outside all four. + assert!(!ForkName::ALL.contains(&ForkName::Lean)); + assert_eq!(ForkName::parse("lean"), None); + assert_eq!(ForkName::Lean.next(), None); + assert_eq!(ForkName::Lean.previous(), None); + } + + #[test] + fn fulu_is_still_the_last_beacon_fork() { + // Guards the reason Lean is kept out of ALL: adding it there would make + // this None into Some(Lean) and let `upgrade` walk off the end. + assert_eq!(ForkName::Fulu.next(), None); + } + + #[test] + fn lean_has_a_name() { + assert_eq!(ForkName::Lean.as_str(), "lean"); + } + + #[test] + fn every_fork_round_trips_through_its_selector() { + for fork in ForkName::ALL { + assert_eq!(ForkName::from_selector(fork.selector()), Some(fork)); + } + // Lean is outside ALL but is exactly the value the tag exists to + // distinguish, so it is checked separately rather than left out. + assert_eq!( + ForkName::from_selector(ForkName::Lean.selector()), + Some(ForkName::Lean) + ); + } + + #[test] + fn selectors_are_pinned_to_their_on_disk_values() { + // These bytes are a storage format: changing one makes every existing + // database decode as the wrong fork. Asserted literally rather than + // derived from the variant order, which the derived Ord already owns. + assert_eq!(ForkName::Phase0.selector(), 0); + assert_eq!(ForkName::Fulu.selector(), 6); + // Lean sits at the top of the byte range so gloas and heze can keep + // taking the next free value after fulu. + assert_eq!(ForkName::Lean.selector(), 255); + assert_eq!(ForkName::from_selector(7), None); + } +} diff --git a/crates/common/types/src/beacon/fork_choice.rs b/crates/common/types/src/beacon/fork_choice.rs new file mode 100644 index 000000000..d79d39d2a --- /dev/null +++ b/crates/common/types/src/beacon/fork_choice.rs @@ -0,0 +1,66 @@ +//! The two fork-choice containers that are neither a block nor a state. +//! +//! They live here rather than in `ethlambda-beacon`'s `fork_choice` module +//! because the DB-backed `ethlambda_storage::Store` holds them, and +//! `ethlambda-storage` cannot depend on `ethlambda-beacon`: the dependency runs +//! the other way. `ethlambda_beacon::fork_choice` re-exports both at their old +//! paths, so every use site inside that crate is unchanged. + +use libssz_derive::{HashTreeRoot, SszDecode, SszEncode}; + +use crate::beacon::primitives::{Epoch, Root, Uint256}; + +/// One validator's most recent attestation: the epoch it targeted, and the +/// block it attested to (the LMD GHOST vote). +/// +/// `Copy`, matching the specification's `@dataclass(eq=True, frozen=True)`: +/// there is nothing here worth borrowing rather than copying. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct LatestMessage { + pub epoch: Epoch, + pub root: Root, +} + +/// The execution chain's own block header, as far as bellatrix's merge +/// transition check needs it: `specs/bellatrix/fork-choice.md`'s `PowBlock`. +/// +/// The specification's own `get_pow_block(hash) -> Optional[PowBlock]` is +/// "implementation and context dependent": a real client would ask its +/// execution engine. The fork choice store's own record of these, populated by +/// the fixture suites' `on_merge_block` step, is what stands in for that. +/// +/// Defined at the top level here, unlike in its former home: this module has no +/// `Result` alias of its own for the `SszDecode` derive's generated code to +/// collide with, so the nested module that used to shield it is gone. +#[derive(Debug, Clone, Copy, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +pub struct PowBlock { + pub block_hash: Root, + pub parent_hash: Root, + /// The total work behind `block_hash`, compared against + /// [`crate::beacon::config::Config::terminal_total_difficulty`] to decide + /// whether this is the one PoW block the merge transitioned at. + pub total_difficulty: Uint256, +} + +#[cfg(test)] +mod tests { + use libssz::{SszDecode as _, SszEncode as _}; + + use super::*; + + #[test] + fn a_pow_block_round_trips_through_ssz() { + // The store persists these, so the derive has to survive the move out + // of `ethlambda-beacon` intact. + let block = PowBlock { + block_hash: Root::repeat_byte(1), + parent_hash: Root::repeat_byte(2), + total_difficulty: Uint256::from(3u64), + }; + let bytes = block.to_ssz(); + assert_eq!( + PowBlock::from_ssz_bytes(&bytes).expect("valid pow block"), + block + ); + } +} diff --git a/crates/common/types/src/beacon/fork_digest.rs b/crates/common/types/src/beacon/fork_digest.rs new file mode 100644 index 000000000..c20af99c3 --- /dev/null +++ b/crates/common/types/src/beacon/fork_digest.rs @@ -0,0 +1,161 @@ +//! The four bytes that separate one network, fork, and blob schedule from +//! another on the wire. +//! +//! Lives here rather than in `ethlambda-beacon` because the networking crate +//! needs it and must not depend on the state transition: `ethlambda-beacon` +//! pulls in `blst` and `c-kzg`, neither of which a gossip topic name has any +//! business requiring. `ethlambda_beacon::helpers::misc` re-exports +//! [`compute_fork_data_root`] at its old path. + +use sha2::{Digest as _, Sha256}; + +use crate::beacon::config::Config; +use crate::beacon::constants; +use crate::beacon::containers::shared::ForkData; +use crate::beacon::fork::ForkName; +use crate::beacon::primitives::{Epoch, ForkDigest, HashTreeRoot as _, Root, Version}; + +/// The root binding a fork version to a chain's genesis validator set. +/// +/// Mixing both into every signing domain and into the fork digest is what keeps +/// a signature, or a gossip topic, from one chain or fork from being valid on +/// another. +pub fn compute_fork_data_root(current_version: Version, genesis_validators_root: Root) -> Root { + ForkData { + current_version, + genesis_validators_root, + } + .hash_tree_root() +} + +/// The four bytes every gossip topic name and the `eth2` ENR entry carry, for a +/// chain with this schedule, this genesis validator set, and this epoch. +/// +/// This is fulu's `compute_fork_digest` (EIP-7892). Before fulu the digest is +/// simply the fork data root's first four bytes. From fulu on, the blob +/// parameters are xored in, so that a blob-parameter-only fork moves the digest +/// and therefore the topic names without needing a new fork version. +pub fn compute_fork_digest( + config: &Config, + genesis_validators_root: Root, + epoch: Epoch, +) -> ForkDigest { + let fork = config.fork_at_epoch(epoch); + let base = compute_fork_data_root(config.fork_version(fork), genesis_validators_root); + + if fork < ForkName::Fulu { + return base.0[..4].try_into().expect("a Root is 32 bytes"); + } + + let (bp_epoch, bp_max_blobs) = config.blob_parameters(epoch); + let mut hasher = Sha256::new(); + hasher.update(bp_epoch.to_le_bytes()); + hasher.update(bp_max_blobs.to_le_bytes()); + let mask = hasher.finalize(); + + core::array::from_fn(|index| base.0[index] ^ mask[index]) +} + +/// The next epoch at which [`compute_fork_digest`] changes, if there is one. +/// +/// Both fork activations and blob-schedule entries qualify: crossing either one +/// strands a running node on topic names no peer is publishing to. Unscheduled +/// forks carry [`constants::FAR_FUTURE_EPOCH`], a real value rather than a +/// `None`, so they are filtered out before the minimum is taken. +pub fn next_fork_boundary(config: &Config, epoch: Epoch) -> Option { + ForkName::ALL + .into_iter() + .map(|fork| config.fork_epoch(fork)) + .chain(config.blob_schedule.iter().map(|entry| entry.epoch)) + .filter(|&boundary| boundary != constants::FAR_FUTURE_EPOCH && boundary > epoch) + .min() +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::config::Config; + use crate::beacon::primitives::Root; + + /// Ethereum mainnet's `genesis_validators_root`. + fn mainnet_gvr() -> Root { + Root::from_slice( + &hex::decode("4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95") + .expect("valid hex"), + ) + } + + #[test] + fn mainnet_digests_match_the_ones_observed_on_the_wire() { + // Every value here was read off a live mainnet discv5 crawl and is + // recorded in docs/discovery.md. Both branches of the fulu rule are + // covered: the pre-fulu truncation and the EIP-7892 blob-parameter xor. + let config = Config::mainnet(); + let gvr = mainnet_gvr(); + let cases = [ + // phase0, still advertised by bootnode records never re-published. + (0u64, [0xb5, 0x30, 0x3f, 0x2a]), + // electra. + (364_032u64, [0xad, 0x53, 0x2c, 0xeb]), + // fulu, before the first blob-schedule entry: the parameters fall + // back to (electra_fork_epoch, max_blobs_per_block_electra). + (411_392u64, [0xcc, 0x2c, 0x5c, 0xdb]), + // fulu, first BPO fork. + (412_672u64, [0xcb, 0x0d, 0x1a, 0xcc]), + // fulu, second BPO fork: mainnet's current digest. + (419_072u64, [0x8c, 0x9f, 0x62, 0xfe]), + ]; + for (epoch, expected) in cases { + assert_eq!( + compute_fork_digest(&config, gvr, epoch), + expected, + "digest at epoch {epoch}" + ); + } + } + + #[test] + fn the_digest_holds_between_boundaries() { + // A digest that changed every epoch would mean the node re-subscribed + // constantly; it must only move at a fork or blob-schedule boundary. + let config = Config::mainnet(); + let gvr = mainnet_gvr(); + assert_eq!( + compute_fork_digest(&config, gvr, 419_072), + compute_fork_digest(&config, gvr, 419_072 + 5_000) + ); + assert_ne!( + compute_fork_digest(&config, gvr, 419_071), + compute_fork_digest(&config, gvr, 419_072) + ); + } + + #[test] + fn next_boundary_covers_both_fork_and_blob_schedule_epochs() { + let config = Config::mainnet(); + // A plain fork boundary. + assert_eq!(next_fork_boundary(&config, 0), Some(74_240)); + // A blob-parameter-only fork is a boundary too: it moves the digest. + assert_eq!(next_fork_boundary(&config, 411_392), Some(412_672)); + assert_eq!(next_fork_boundary(&config, 412_672), Some(419_072)); + // Past the last scheduled boundary there is nothing left to warn about. + assert_eq!(next_fork_boundary(&config, 419_072), None); + } + + #[test] + fn far_future_forks_are_not_boundaries() { + // Minimal leaves every fork after phase0 at FAR_FUTURE_EPOCH, which is a + // real, enormous Epoch rather than a None; treating it as a boundary + // would schedule a warning for the heat death of the universe. + assert_eq!(next_fork_boundary(&Config::minimal(), 0), None); + } + + #[test] + fn fork_data_root_binds_the_version_and_the_chain() { + let a = compute_fork_data_root([1, 0, 0, 0], Root::ZERO); + let b = compute_fork_data_root([2, 0, 0, 0], Root::ZERO); + let c = compute_fork_data_root([1, 0, 0, 0], Root::repeat_byte(1)); + assert_ne!(a, b); + assert_ne!(a, c); + } +} diff --git a/crates/common/types/src/beacon/mod.rs b/crates/common/types/src/beacon/mod.rs new file mode 100644 index 000000000..79c231f5b --- /dev/null +++ b/crates/common/types/src/beacon/mod.rs @@ -0,0 +1,112 @@ +//! Beacon Chain types, namespaced away from the lean types alongside them. +//! +//! `ethlambda-types` already has `primitives`, `constants`, and `checkpoint` +//! modules of its own, and lean's `Checkpoint` is a different type from +//! beacon's by the same name. Everything moved out of `ethlambda-beacon` lives +//! under this module so both sets can coexist. + +pub mod config; +pub mod constants; +pub mod containers; +pub mod error; +pub mod fork; +pub mod fork_choice; +pub mod fork_digest; +pub mod preset; +pub mod primitives; + +/// Panics, naming the beacon accessor a lean state reached. +/// +/// The boundary is structural rather than type-level: [`containers::BeaconState`] +/// carries a `Lean` variant, so every beacon-only accessor needs an arm for it. +/// Written once here so the wording, and the diagnosis it points at, cannot +/// drift from one such arm to the next. +/// +/// This is the state-shaped boundary: reaching it means a handler dispatched on +/// the wrong thing. For the fork-shaped one see [`lean_fork_unreachable`], kept +/// separate because the two are crossed by different mistakes. +/// +/// `#[track_caller]` so the panic still reports the arm's own file and line, the +/// way an `unreachable!` written inline there would have. +#[cold] +#[track_caller] +pub(crate) fn lean_state_unreachable(function: &str) -> ! { + unreachable!( + "lean state reached a beacon accessor ({function}); \ + BlockChainServer must dispatch on fork_name() before this point" + ) +} + +/// Panics, naming the Beacon Chain-only function [`fork::ForkName::Lean`] reached. +/// +/// The fork-shaped counterpart to [`lean_state_unreachable`]: lean is not a point +/// on the beacon fork schedule at all, so no state is involved and the fault is +/// the argument the caller passed rather than the state it dispatched on. +#[cold] +#[track_caller] +pub(crate) fn lean_fork_unreachable(function: &str) -> ! { + unreachable!( + "ForkName::Lean reached a Beacon Chain function ({function}); \ + lean is not a point on the beacon fork schedule, so the caller \ + passed a fork it should have dispatched on first" + ) +} + +#[cfg(test)] +mod tests { + /// A type-level assertion that the namespace does not reintroduce a second + /// 32-byte hash: assigning one to the other only compiles while + /// [`primitives::Root`] names the very same type as the lean `H256`, which + /// is what lets a beacon block root reach a store lookup unconverted. + #[test] + fn a_beacon_root_is_the_lean_hash() { + let beacon: super::primitives::Root = super::primitives::Root::ZERO; + let _lean: crate::primitives::H256 = beacon; + } + + #[test] + fn beacon_constants_are_reachable_beside_lean_constants() { + // Both crates define a `constants` module; the namespace keeps them + // apart. `FAR_FUTURE_EPOCH` is the sentinel every unscheduled fork + // epoch carries. + assert_eq!(super::constants::FAR_FUTURE_EPOCH, u64::MAX); + assert_eq!(crate::constants::FORK_DIGEST, "12345678"); + } + + #[test] + fn fork_ordering_is_reachable_from_the_namespace() { + use super::fork::ForkName; + assert!(ForkName::Fulu > ForkName::Phase0); + } + + #[test] + fn preset_slots_per_epoch_matches_the_selected_preset() { + #[cfg(not(feature = "preset-minimal"))] + assert_eq!(super::preset::SLOTS_PER_EPOCH, 32); + #[cfg(feature = "preset-minimal")] + assert_eq!(super::preset::SLOTS_PER_EPOCH, 8); + } + + #[test] + fn mainnet_config_carries_the_fulu_schedule() { + let config = super::config::Config::mainnet(); + assert_eq!(config.fulu_fork_version, [0x06, 0x00, 0x00, 0x00]); + assert_eq!(config.fulu_fork_epoch, 411_392); + // The two blob-parameter-only forks, which perturb the fork digest. + assert_eq!(config.blob_schedule.len(), 2); + assert_eq!(config.blob_schedule[0].epoch, 412_672); + assert_eq!(config.blob_schedule[0].max_blobs_per_block, 15); + assert_eq!(config.blob_schedule[1].epoch, 419_072); + assert_eq!(config.blob_schedule[1].max_blobs_per_block, 21); + } + + #[test] + fn the_beacon_containers_are_reachable_from_the_namespace() { + use super::containers::{BeaconState, phase0}; + + // A type-level assertion: naming the variant constructor as a function + // proves both the enum and the per-fork struct resolve, with nothing to + // construct. No fork's BeaconState derives Default. + let _: fn(phase0::BeaconState) -> BeaconState = BeaconState::Phase0; + } +} diff --git a/crates/common/types/src/beacon/preset.rs b/crates/common/types/src/beacon/preset.rs new file mode 100644 index 000000000..550518d70 --- /dev/null +++ b/crates/common/types/src/beacon/preset.rs @@ -0,0 +1,1399 @@ +//! Preset constants: the compile-time-selectable half of the specification's +//! tunables. +//! +//! The specification splits its numeric parameters into two kinds. *Configuration* +//! values (genesis time, fork-activation epochs, network-specific limits) can +//! differ between two networks running the same client binary, so they belong in +//! [`crate::beacon::config`] as runtime data. *Preset* values instead fix the shape of the +//! SSZ containers the state transition operates on: how many slots a historical +//! roots vector holds, how many attestations fit in a block, how many field +//! elements make up a blob. Two networks that disagree on a preset value are +//! running different, mutually unintelligible protocols, because every hash tree +//! root over a preset-bounded list or vector depends on that bound. That is also +//! why the values below are Rust constants rather than fields on a struct: a +//! container's SSZ shape is a type-level property (`SszList`), +//! decided once when the crate is compiled, not something a running node could +//! switch at runtime without also swapping out its state's memory layout. +//! +//! The specification defines exactly two presets, `mainnet` and `minimal` +//! (`minimal` exists to keep spec test fixtures and local devnets fast). This +//! crate mirrors that: [`mainnet`] and [`minimal`] each define every preset +//! constant the specification uses from phase0 through fulu, and the top-level +//! re-export picks one at compile time, gated on the `preset-minimal` feature. +//! Downstream code should import from here (`preset::SLOTS_PER_EPOCH`, not +//! `preset::mainnet::SLOTS_PER_EPOCH`), so that it automatically follows whichever +//! preset the crate was built against. +//! +//! # Why some constants are `usize` and others are `u64` +//! +//! A constant that bounds an SSZ collection (`List`, `Vector`, `Bitlist`, +//! `Bitvector`) in some container, in any fork from phase0 through fulu, is typed +//! `usize` here, because it gets threaded through this crate as a const-generic +//! parameter on that collection's Rust representation, and const generics require +//! `usize`. Every other preset constant (reward/penalty divisors, Gwei amounts, +//! epoch/slot durations that never size a container by themselves) is typed `u64`, +//! matching the `uint64` the specification gives it. A few constants are factors +//! of a container bound without being one themselves (`SLOTS_PER_EPOCH` is the +//! textbook case: it never bounds anything alone, only in products like +//! `SLOTS_PER_EPOCH * EPOCHS_PER_ETH1_VOTING_PERIOD`), so they stay `u64` and the +//! product gets its own `usize` constant instead. +//! +//! # Derived constants +//! +//! Some values a container needs are not literal preset entries at all: the +//! specification writes them as an inline formula over other presets, directly in +//! a container's field-type annotation rather than in the preset YAML. This module +//! gives each of those formulas a name (`MAX_PENDING_ATTESTATIONS`, +//! `SLOTS_PER_ETH1_VOTING_PERIOD`, `BYTES_PER_BLOB`, `BYTES_PER_CELL`, +//! `PROPOSER_LOOKAHEAD_LENGTH`, `MAX_VALIDATORS_PER_SLOT`) and computes it from the +//! constants it depends on, so the relationship is checked by the compiler instead +//! of copied by hand into two places. +//! +//! Constants that the specification instead lists as fixed, preset-independent +//! `Constant`s (for example `JUSTIFICATION_BITS_LENGTH`, `BYTES_PER_FIELD_ELEMENT`, +//! `DEPOSIT_CONTRACT_TREE_DEPTH`) do not appear here even when they bound a +//! container or feed one of the formulas above; they belong to this crate's +//! `constants` module instead, since they cannot vary between `mainnet` and +//! `minimal` in the first place. + +/// The mainnet preset: the values that secure the real Ethereum network. +/// +/// Sourced from `presets/mainnet/{phase0,altair,bellatrix,capella,deneb,electra, +/// fulu}.yaml` in the specification, plus the derived constants documented at the +/// module level. +pub mod mainnet { + // ================================================================ + // Phase0 + // ================================================================ + + // --- Misc --- + + /// How many committees a single slot's active validators are split into. + /// Also bounds `Attestation.committee_bits` from electra onward + /// (`Bitvector`), and is a factor of + /// `MAX_VALIDATORS_PER_SLOT`. + pub const MAX_COMMITTEES_PER_SLOT: usize = 64; + + /// The committee size `get_committee_count_per_slot` aims for when splitting a + /// slot's active validators into committees. Not itself a container bound. + pub const TARGET_COMMITTEE_SIZE: u64 = 128; + + /// Bounds `Attestation.aggregation_bits` (a `Bitlist`) and, pre-electra, + /// `IndexedAttestation.attesting_indices` (a `List`). From + /// electra onward it is instead a factor of `MAX_VALIDATORS_PER_SLOT`, which + /// bounds those same fields. + pub const MAX_VALIDATORS_PER_COMMITTEE: usize = 2048; + + /// Number of swap-or-not shuffle rounds `compute_shuffled_index` performs when + /// deriving committee membership from a seed. + pub const SHUFFLE_ROUND_COUNT: u64 = 90; + + /// Denominator of the balance band, centered on a multiple of + /// `EFFECTIVE_BALANCE_INCREMENT`, that a validator's effective balance must + /// leave before `process_effective_balance_updates` moves it. + pub const HYSTERESIS_QUOTIENT: u64 = 4; + + /// Numerator narrowing the downward half of the hysteresis band relative to + /// `HYSTERESIS_QUOTIENT`, so effective balance falls faster than it rises. + pub const HYSTERESIS_DOWNWARD_MULTIPLIER: u64 = 1; + + /// Numerator widening the upward half of the hysteresis band relative to + /// `HYSTERESIS_QUOTIENT`, damping effective balance increases. + pub const HYSTERESIS_UPWARD_MULTIPLIER: u64 = 5; + + // --- Gwei values --- + + /// Smallest deposit amount `process_deposit` accepts onto the validator + /// registry (deposits below this are recorded but never activate a + /// validator). + pub const MIN_DEPOSIT_AMOUNT: u64 = 1_000_000_000; + + /// Ceiling that reward, penalty, and churn-limit math clamps a validator's + /// effective balance to, pre-electra (electra validators with a compounding + /// withdrawal credential instead use `MAX_EFFECTIVE_BALANCE_ELECTRA`). + pub const MAX_EFFECTIVE_BALANCE: u64 = 32_000_000_000; + + /// Rounding granularity effective balance is truncated to, and the unit that + /// base-reward math scales by. + pub const EFFECTIVE_BALANCE_INCREMENT: u64 = 1_000_000_000; + + // --- Time parameters --- + + /// Minimum number of slots `process_attestation` requires between an + /// attestation's slot and the slot it is included in. + pub const MIN_ATTESTATION_INCLUSION_DELAY: u64 = 1; + + /// Slots per epoch. Never bounds a container by itself; it is a factor of + /// several derived bounds below (`SLOTS_PER_ETH1_VOTING_PERIOD`, + /// `MAX_PENDING_ATTESTATIONS`, `PROPOSER_LOOKAHEAD_LENGTH`). + pub const SLOTS_PER_EPOCH: u64 = 32; + + /// Epochs the RANDAO mix used to seed a shuffling lags behind the epoch it + /// shuffles, so the seed is unpredictable before that epoch starts. Also a + /// factor of `PROPOSER_LOOKAHEAD_LENGTH`. + pub const MIN_SEED_LOOKAHEAD: u64 = 1; + + /// Epochs an exiting validator's withdrawable epoch is delayed past its exit + /// epoch, bounding how far in advance the exit queue can be gamed. + pub const MAX_SEED_LOOKAHEAD: u64 = 4; + + /// Epochs a single ETH1 voting period spans. A factor of + /// `SLOTS_PER_ETH1_VOTING_PERIOD`; not itself a container bound. + pub const EPOCHS_PER_ETH1_VOTING_PERIOD: u64 = 64; + + /// `EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH`, the specification's + /// formula for the bound on `BeaconState.eth1_data_votes` + /// (`List`), the votes collected + /// during one ETH1 voting period. + pub const SLOTS_PER_ETH1_VOTING_PERIOD: usize = + EPOCHS_PER_ETH1_VOTING_PERIOD as usize * SLOTS_PER_EPOCH as usize; + + /// Bounds `BeaconState.block_roots` and `state_roots`, both + /// `Vector`. + pub const SLOTS_PER_HISTORICAL_ROOT: usize = 8192; + + /// Epochs since the last finality advance before + /// `process_inactivity_updates`-adjacent penalty logic starts leaking an + /// inactive validator's balance. + pub const MIN_EPOCHS_TO_INACTIVITY_PENALTY: u64 = 4; + + // --- State list lengths --- + + /// Bounds `BeaconState.randao_mixes` (`Vector`), the ring buffer of past RANDAO mixes + /// shufflings are seeded from. + pub const EPOCHS_PER_HISTORICAL_VECTOR: usize = 65536; + + /// Bounds `BeaconState.slashings` (`Vector`), + /// the ring buffer `process_slashings` sums to scale the correlated slashing + /// penalty. + pub const EPOCHS_PER_SLASHINGS_VECTOR: usize = 8192; + + /// Bounds `BeaconState.historical_roots`, and from capella onward + /// `historical_summaries` (both `List<_, HISTORICAL_ROOTS_LIMIT>`). + pub const HISTORICAL_ROOTS_LIMIT: usize = 16_777_216; + + /// Bounds every validator-indexed list in `BeaconState`: `validators`, + /// `balances`, and, from altair, `previous_epoch_participation`, + /// `current_epoch_participation`, and `inactivity_scores`. + pub const VALIDATOR_REGISTRY_LIMIT: usize = 1_099_511_627_776; + + // --- Rewards and penalties --- + + /// Numerator of the base reward per increment of effective balance, before + /// dividing by the integer square root of total active balance. + pub const BASE_REWARD_FACTOR: u64 = 64; + + /// Divisor of a slashed validator's effective balance that sets the combined + /// whistleblower/proposer reward `slash_validator` pays out. + pub const WHISTLEBLOWER_REWARD_QUOTIENT: u64 = 512; + + /// Divisor of the whistleblower reward that the block proposer's share is set + /// to; the remainder goes to whoever reported the slashable offense. + pub const PROPOSER_REWARD_QUOTIENT: u64 = 8; + + /// Divisor controlling how fast effective balance leaks during non-finality, + /// pre-altair (altair replaces this with + /// `INACTIVITY_PENALTY_QUOTIENT_ALTAIR`). + pub const INACTIVITY_PENALTY_QUOTIENT: u64 = 67_108_864; + + /// Divisor of effective balance burned immediately on slashing, pre-altair. + pub const MIN_SLASHING_PENALTY_QUOTIENT: u64 = 128; + + /// Multiplier scaling the slashing penalty by the proportion of validators + /// slashed in the same slashings-vector window, pre-altair. + pub const PROPORTIONAL_SLASHING_MULTIPLIER: u64 = 1; + + // --- Max operations per block --- + + /// Bounds `BeaconBlockBody.proposer_slashings` + /// (`List`). + pub const MAX_PROPOSER_SLASHINGS: usize = 16; + + /// Bounds `BeaconBlockBody.attester_slashings`, pre-electra + /// (`List`; electra replaces it with + /// `MAX_ATTESTER_SLASHINGS_ELECTRA`). + pub const MAX_ATTESTER_SLASHINGS: usize = 2; + + /// Bounds `BeaconBlockBody.attestations`, pre-electra + /// (`List`; electra replaces it with + /// `MAX_ATTESTATIONS_ELECTRA`). Also a factor of `MAX_PENDING_ATTESTATIONS`. + pub const MAX_ATTESTATIONS: usize = 128; + + /// `MAX_ATTESTATIONS * SLOTS_PER_EPOCH`, the specification's formula for the + /// bound on `BeaconState.previous_epoch_attestations` and + /// `current_epoch_attestations` (`List`), the phase0 + /// per-epoch attestation backlog that altair replaces with participation + /// flags. + pub const MAX_PENDING_ATTESTATIONS: usize = MAX_ATTESTATIONS * SLOTS_PER_EPOCH as usize; + + /// Bounds `BeaconBlockBody.deposits` (`List`). + pub const MAX_DEPOSITS: usize = 16; + + /// Bounds `BeaconBlockBody.voluntary_exits` + /// (`List`). + pub const MAX_VOLUNTARY_EXITS: usize = 16; + + // ================================================================ + // Altair + // ================================================================ + + // --- Rewards and penalties --- + + /// Altair's replacement for `INACTIVITY_PENALTY_QUOTIENT`, retuned for the + /// participation-flag accounting altair introduces. + pub const INACTIVITY_PENALTY_QUOTIENT_ALTAIR: u64 = 50_331_648; + + /// Altair's replacement for `MIN_SLASHING_PENALTY_QUOTIENT`. + pub const MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: u64 = 64; + + /// Altair's replacement for `PROPORTIONAL_SLASHING_MULTIPLIER`. + pub const PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: u64 = 2; + + // --- Sync committee --- + + /// Bounds `SyncCommittee.pubkeys` (`Vector`) + /// and a sync aggregate's `sync_committee_bits` + /// (`Bitvector`). + pub const SYNC_COMMITTEE_SIZE: usize = 512; + + /// Epochs a sync committee serves before the next one rotates in. A factor of + /// `UPDATE_TIMEOUT`; not itself a container bound. + pub const EPOCHS_PER_SYNC_COMMITTEE_PERIOD: u64 = 256; + + // --- Sync protocol --- + + /// Minimum signer count a sync aggregate must have for light-client update + /// validity checks to accept it. + pub const MIN_SYNC_COMMITTEE_PARTICIPANTS: u64 = 1; + + /// Slots since the light client store's finalized header before + /// `process_light_client_store_force_update` force-applies the best pending + /// update. Equal to `SLOTS_PER_EPOCH * EPOCHS_PER_SYNC_COMMITTEE_PERIOD`. + pub const UPDATE_TIMEOUT: u64 = 8192; + + // ================================================================ + // Bellatrix + // ================================================================ + + // --- Rewards and penalties --- + + /// Bellatrix's replacement for `INACTIVITY_PENALTY_QUOTIENT_ALTAIR`. + pub const INACTIVITY_PENALTY_QUOTIENT_BELLATRIX: u64 = 16_777_216; + + /// Bellatrix's replacement for `MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR`. + pub const MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX: u64 = 32; + + /// Bellatrix's replacement for `PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR`. + pub const PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX: u64 = 3; + + // --- Execution --- + + /// Bounds the `Transaction` type itself (`ByteList` + /// is `Transaction`'s SSZ definition). + pub const MAX_BYTES_PER_TRANSACTION: usize = 1_073_741_824; + + /// Bounds `ExecutionPayload.transactions` + /// (`List`). + pub const MAX_TRANSACTIONS_PER_PAYLOAD: usize = 1_048_576; + + /// Bounds `ExecutionPayload(Header).logs_bloom` + /// (`ByteVector`). + pub const BYTES_PER_LOGS_BLOOM: usize = 256; + + /// Bounds `ExecutionPayload(Header).extra_data` + /// (`ByteList`). + pub const MAX_EXTRA_DATA_BYTES: usize = 32; + + // ================================================================ + // Capella + // ================================================================ + + // --- Max operations per block --- + + /// Bounds `BeaconBlockBody.bls_to_execution_changes` + /// (`List`). + pub const MAX_BLS_TO_EXECUTION_CHANGES: usize = 16; + + // --- Execution --- + + /// Bounds `ExecutionPayload(Header).withdrawals` + /// (`List`). + pub const MAX_WITHDRAWALS_PER_PAYLOAD: usize = 16; + + // --- Withdrawals processing --- + + /// Cap on how many validators `get_expected_withdrawals` scans per slot while + /// sweeping the registry for withdrawable balances. A loop bound the + /// withdrawal-sweep algorithm uses, not a container length, so it stays + /// `u64`. + pub const MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP: u64 = 16384; + + // ================================================================ + // Deneb + // ================================================================ + + // --- Execution --- + + /// Bounds `BeaconBlockBody.blob_kzg_commitments` + /// (`List`) and, from fulu, + /// `DataColumnSidecar.column` / `kzg_commitments`. + pub const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize = 4096; + + // --- Networking --- + + /// Bounds `BlobSidecar.kzg_commitment_inclusion_proof` + /// (`Vector`), the merkle proof + /// that a commitment sits at its claimed index in `blob_kzg_commitments`. + pub const KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: usize = 17; + + // --- Blob --- + + /// Bounds a blob's polynomial representation + /// (`Vector`), and is a factor of + /// `BYTES_PER_BLOB` and (doubled) fulu's `FIELD_ELEMENTS_PER_EXT_BLOB`. + pub const FIELD_ELEMENTS_PER_BLOB: usize = 4096; + + /// `BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB`, the specification's + /// formula for the bound on the `Blob` type + /// (`ByteVector`), carried in `BlobSidecar.blob`. + /// + /// Derived rather than transcribed, so the two cannot drift apart. + /// `BYTES_PER_FIELD_ELEMENT` is a fixed spec constant rather than a preset + /// value, so it comes from [`crate::beacon::constants`]. + pub const BYTES_PER_BLOB: usize = + crate::beacon::constants::BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB; + + // ================================================================ + // Electra + // ================================================================ + + // --- Gwei values --- + + /// Minimum balance a validator must reach before it can activate. Electra's + /// deposit-flow counterpart to `MIN_DEPOSIT_AMOUNT`. + pub const MIN_ACTIVATION_BALANCE: u64 = 32_000_000_000; + + /// Electra's raised ceiling on effective balance for validators with a + /// compounding (0x02) withdrawal credential; validators without one still use + /// `MAX_EFFECTIVE_BALANCE`. + pub const MAX_EFFECTIVE_BALANCE_ELECTRA: u64 = 2_048_000_000_000; + + // --- Rewards and penalties --- + + /// Electra's replacement for `MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR`, tightened + /// alongside the higher `MAX_EFFECTIVE_BALANCE_ELECTRA`. + pub const MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: u64 = 4096; + + /// Electra's replacement for `WHISTLEBLOWER_REWARD_QUOTIENT`. + pub const WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: u64 = 4096; + + // --- State list lengths --- + + /// Bounds `BeaconState.pending_deposits` + /// (`List`), electra's queue of + /// deposits not yet processed into the registry. + pub const PENDING_DEPOSITS_LIMIT: usize = 134_217_728; + + /// Bounds `BeaconState.pending_partial_withdrawals` + /// (`List`). + pub const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize = 134_217_728; + + /// Bounds `BeaconState.pending_consolidations` + /// (`List`). + pub const PENDING_CONSOLIDATIONS_LIMIT: usize = 262_144; + + // --- Max operations per block --- + + /// Electra's replacement for `MAX_ATTESTER_SLASHINGS`, bounding + /// `BeaconBlockBody.attester_slashings` now that committee bits move + /// attesting indices out of the slashing itself. + pub const MAX_ATTESTER_SLASHINGS_ELECTRA: usize = 1; + + /// Electra's replacement for `MAX_ATTESTATIONS`, lowered because one electra + /// `Attestation` now covers every committee in a slot instead of one. + pub const MAX_ATTESTATIONS_ELECTRA: usize = 8; + + /// `MAX_COMMITTEES_PER_SLOT * MAX_VALIDATORS_PER_COMMITTEE`, the + /// specification's formula for the bound on `Attestation.aggregation_bits` + /// (`Bitlist`) and + /// `IndexedAttestation.attesting_indices` + /// (`List`) from electra onward, + /// since one attestation's bitfield now spans every committee in the slot + /// rather than one. + pub const MAX_VALIDATORS_PER_SLOT: usize = + MAX_COMMITTEES_PER_SLOT * MAX_VALIDATORS_PER_COMMITTEE; + + // --- Execution --- + + /// Bounds `ExecutionRequests.deposits` + /// (`List`). + pub const MAX_DEPOSIT_REQUESTS_PER_PAYLOAD: usize = 8192; + + /// Bounds `ExecutionRequests.withdrawals` + /// (`List`). + pub const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize = 16; + + /// Bounds `ExecutionRequests.consolidations` + /// (`List`). + pub const MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: usize = 2; + + // --- Withdrawals processing --- + + /// Cap on pending partial withdrawals `get_expected_withdrawals` drains per + /// slot. A loop bound, not a container length, so it stays `u64`. + pub const MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: u64 = 8; + + // --- Pending deposits processing --- + + /// Cap on pending deposits `process_pending_deposits` processes per epoch. A + /// loop bound, not a container length, so it stays `u64`. + pub const MAX_PENDING_DEPOSITS_PER_EPOCH: u64 = 16; + + // ================================================================ + // Fulu + // ================================================================ + + // --- Networking --- + + /// Bounds `DataColumnSidecar.kzg_commitments_inclusion_proof` + /// (`Vector`). Shallower than + /// deneb's `KZG_COMMITMENT_INCLUSION_PROOF_DEPTH` because it proves the root + /// of the whole `blob_kzg_commitments` list rather than one leaf. + pub const KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: usize = 4; + + // --- Blob --- + + /// Bounds a `Cell`'s field-element view + /// (`Vector`), and is a factor of + /// `BYTES_PER_CELL`. + pub const FIELD_ELEMENTS_PER_CELL: usize = 64; + + /// Bounds the Reed-Solomon-extended blob polynomial (`PolynomialCoeff`, a + /// `List`); twice + /// `FIELD_ELEMENTS_PER_BLOB` since the extension doubles the evaluation + /// domain. + pub const FIELD_ELEMENTS_PER_EXT_BLOB: usize = 8192; + + /// Bounds the per-blob cell and proof arrays `compute_cells_and_kzg_proofs` + /// returns (`Vector` and + /// `Vector`). + pub const CELLS_PER_EXT_BLOB: usize = 128; + + /// Bounds `DataColumnsByRootIdentifier.columns` + /// (`List`). One data column corresponds to + /// one index across the extended matrix, so this equals `CELLS_PER_EXT_BLOB`. + pub const NUMBER_OF_COLUMNS: usize = 128; + + /// `FIELD_ELEMENTS_PER_CELL * BYTES_PER_FIELD_ELEMENT`, the specification's + /// formula for the bound on the `Cell` type (`ByteVector`). + /// + /// Derived rather than transcribed, from the same [`crate::beacon::constants`] value + /// `BYTES_PER_BLOB` uses. + pub const BYTES_PER_CELL: usize = + FIELD_ELEMENTS_PER_CELL * crate::beacon::constants::BYTES_PER_FIELD_ELEMENT; + + // --- State list lengths --- + + /// `(MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH`, the specification's formula + /// for the length of `BeaconState.proposer_lookahead` + /// (`Vector`), the vector of + /// precomputed proposer indices fulu adds to the state. + pub const PROPOSER_LOOKAHEAD_LENGTH: usize = + (MIN_SEED_LOOKAHEAD as usize + 1) * SLOTS_PER_EPOCH as usize; +} + +/// The minimal preset: the same shape as [`mainnet`], scaled down so spec test +/// fixtures and local devnets run fast. +/// +/// Sourced from `presets/minimal/{phase0,altair,bellatrix,capella,deneb,electra, +/// fulu}.yaml` in the specification. Several values equal their mainnet +/// counterpart (the specification only "customizes" the ones that matter for +/// making a small network self-consistent); each is still spelled out here rather +/// than reused from [`mainnet`], so the two modules stay independent sources of +/// truth that happen to agree, rather than one silently defining the other. +pub mod minimal { + // ================================================================ + // Phase0 + // ================================================================ + + // --- Misc --- + + /// How many committees a single slot's active validators are split into. + /// Also bounds `Attestation.committee_bits` from electra onward + /// (`Bitvector`), and is a factor of + /// `MAX_VALIDATORS_PER_SLOT`. + pub const MAX_COMMITTEES_PER_SLOT: usize = 4; + + /// The committee size `get_committee_count_per_slot` aims for when splitting a + /// slot's active validators into committees. Not itself a container bound. + pub const TARGET_COMMITTEE_SIZE: u64 = 4; + + /// Bounds `Attestation.aggregation_bits` (a `Bitlist`) and, pre-electra, + /// `IndexedAttestation.attesting_indices` (a `List`). From + /// electra onward it is instead a factor of `MAX_VALIDATORS_PER_SLOT`, which + /// bounds those same fields. + pub const MAX_VALIDATORS_PER_COMMITTEE: usize = 2048; + + /// Number of swap-or-not shuffle rounds `compute_shuffled_index` performs when + /// deriving committee membership from a seed. + pub const SHUFFLE_ROUND_COUNT: u64 = 10; + + /// Denominator of the balance band, centered on a multiple of + /// `EFFECTIVE_BALANCE_INCREMENT`, that a validator's effective balance must + /// leave before `process_effective_balance_updates` moves it. + pub const HYSTERESIS_QUOTIENT: u64 = 4; + + /// Numerator narrowing the downward half of the hysteresis band relative to + /// `HYSTERESIS_QUOTIENT`, so effective balance falls faster than it rises. + pub const HYSTERESIS_DOWNWARD_MULTIPLIER: u64 = 1; + + /// Numerator widening the upward half of the hysteresis band relative to + /// `HYSTERESIS_QUOTIENT`, damping effective balance increases. + pub const HYSTERESIS_UPWARD_MULTIPLIER: u64 = 5; + + // --- Gwei values --- + + /// Smallest deposit amount `process_deposit` accepts onto the validator + /// registry (deposits below this are recorded but never activate a + /// validator). + pub const MIN_DEPOSIT_AMOUNT: u64 = 1_000_000_000; + + /// Ceiling that reward, penalty, and churn-limit math clamps a validator's + /// effective balance to, pre-electra (electra validators with a compounding + /// withdrawal credential instead use `MAX_EFFECTIVE_BALANCE_ELECTRA`). + pub const MAX_EFFECTIVE_BALANCE: u64 = 32_000_000_000; + + /// Rounding granularity effective balance is truncated to, and the unit that + /// base-reward math scales by. + pub const EFFECTIVE_BALANCE_INCREMENT: u64 = 1_000_000_000; + + // --- Time parameters --- + + /// Minimum number of slots `process_attestation` requires between an + /// attestation's slot and the slot it is included in. + pub const MIN_ATTESTATION_INCLUSION_DELAY: u64 = 1; + + /// Slots per epoch. Never bounds a container by itself; it is a factor of + /// several derived bounds below (`SLOTS_PER_ETH1_VOTING_PERIOD`, + /// `MAX_PENDING_ATTESTATIONS`, `PROPOSER_LOOKAHEAD_LENGTH`). + pub const SLOTS_PER_EPOCH: u64 = 8; + + /// Epochs the RANDAO mix used to seed a shuffling lags behind the epoch it + /// shuffles, so the seed is unpredictable before that epoch starts. Also a + /// factor of `PROPOSER_LOOKAHEAD_LENGTH`. + pub const MIN_SEED_LOOKAHEAD: u64 = 1; + + /// Epochs an exiting validator's withdrawable epoch is delayed past its exit + /// epoch, bounding how far in advance the exit queue can be gamed. + pub const MAX_SEED_LOOKAHEAD: u64 = 4; + + /// Epochs a single ETH1 voting period spans. A factor of + /// `SLOTS_PER_ETH1_VOTING_PERIOD`; not itself a container bound. + pub const EPOCHS_PER_ETH1_VOTING_PERIOD: u64 = 4; + + /// `EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH`, the specification's + /// formula for the bound on `BeaconState.eth1_data_votes` + /// (`List`), the votes collected + /// during one ETH1 voting period. + pub const SLOTS_PER_ETH1_VOTING_PERIOD: usize = + EPOCHS_PER_ETH1_VOTING_PERIOD as usize * SLOTS_PER_EPOCH as usize; + + /// Bounds `BeaconState.block_roots` and `state_roots`, both + /// `Vector`. + pub const SLOTS_PER_HISTORICAL_ROOT: usize = 64; + + /// Epochs since the last finality advance before + /// `process_inactivity_updates`-adjacent penalty logic starts leaking an + /// inactive validator's balance. + pub const MIN_EPOCHS_TO_INACTIVITY_PENALTY: u64 = 4; + + // --- State list lengths --- + + /// Bounds `BeaconState.randao_mixes` (`Vector`), the ring buffer of past RANDAO mixes + /// shufflings are seeded from. + pub const EPOCHS_PER_HISTORICAL_VECTOR: usize = 64; + + /// Bounds `BeaconState.slashings` (`Vector`), + /// the ring buffer `process_slashings` sums to scale the correlated slashing + /// penalty. + pub const EPOCHS_PER_SLASHINGS_VECTOR: usize = 64; + + /// Bounds `BeaconState.historical_roots`, and from capella onward + /// `historical_summaries` (both `List<_, HISTORICAL_ROOTS_LIMIT>`). + pub const HISTORICAL_ROOTS_LIMIT: usize = 16_777_216; + + /// Bounds every validator-indexed list in `BeaconState`: `validators`, + /// `balances`, and, from altair, `previous_epoch_participation`, + /// `current_epoch_participation`, and `inactivity_scores`. + pub const VALIDATOR_REGISTRY_LIMIT: usize = 1_099_511_627_776; + + // --- Rewards and penalties --- + + /// Numerator of the base reward per increment of effective balance, before + /// dividing by the integer square root of total active balance. + pub const BASE_REWARD_FACTOR: u64 = 64; + + /// Divisor of a slashed validator's effective balance that sets the combined + /// whistleblower/proposer reward `slash_validator` pays out. + pub const WHISTLEBLOWER_REWARD_QUOTIENT: u64 = 512; + + /// Divisor of the whistleblower reward that the block proposer's share is set + /// to; the remainder goes to whoever reported the slashable offense. + pub const PROPOSER_REWARD_QUOTIENT: u64 = 8; + + /// Divisor controlling how fast effective balance leaks during non-finality, + /// pre-altair (altair replaces this with + /// `INACTIVITY_PENALTY_QUOTIENT_ALTAIR`). + pub const INACTIVITY_PENALTY_QUOTIENT: u64 = 33_554_432; + + /// Divisor of effective balance burned immediately on slashing, pre-altair. + pub const MIN_SLASHING_PENALTY_QUOTIENT: u64 = 64; + + /// Multiplier scaling the slashing penalty by the proportion of validators + /// slashed in the same slashings-vector window, pre-altair. Set lower than + /// mainnet's for a gentler test-network safety margin. + pub const PROPORTIONAL_SLASHING_MULTIPLIER: u64 = 2; + + // --- Max operations per block --- + + /// Bounds `BeaconBlockBody.proposer_slashings` + /// (`List`). + pub const MAX_PROPOSER_SLASHINGS: usize = 16; + + /// Bounds `BeaconBlockBody.attester_slashings`, pre-electra + /// (`List`; electra replaces it with + /// `MAX_ATTESTER_SLASHINGS_ELECTRA`). + pub const MAX_ATTESTER_SLASHINGS: usize = 2; + + /// Bounds `BeaconBlockBody.attestations`, pre-electra + /// (`List`; electra replaces it with + /// `MAX_ATTESTATIONS_ELECTRA`). Also a factor of `MAX_PENDING_ATTESTATIONS`. + pub const MAX_ATTESTATIONS: usize = 128; + + /// `MAX_ATTESTATIONS * SLOTS_PER_EPOCH`, the specification's formula for the + /// bound on `BeaconState.previous_epoch_attestations` and + /// `current_epoch_attestations` (`List`), the phase0 + /// per-epoch attestation backlog that altair replaces with participation + /// flags. + pub const MAX_PENDING_ATTESTATIONS: usize = MAX_ATTESTATIONS * SLOTS_PER_EPOCH as usize; + + /// Bounds `BeaconBlockBody.deposits` (`List`). + pub const MAX_DEPOSITS: usize = 16; + + /// Bounds `BeaconBlockBody.voluntary_exits` + /// (`List`). + pub const MAX_VOLUNTARY_EXITS: usize = 16; + + // ================================================================ + // Altair + // ================================================================ + + // --- Rewards and penalties --- + + /// Altair's replacement for `INACTIVITY_PENALTY_QUOTIENT`, retuned for the + /// participation-flag accounting altair introduces. + pub const INACTIVITY_PENALTY_QUOTIENT_ALTAIR: u64 = 50_331_648; + + /// Altair's replacement for `MIN_SLASHING_PENALTY_QUOTIENT`. + pub const MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: u64 = 64; + + /// Altair's replacement for `PROPORTIONAL_SLASHING_MULTIPLIER`. + pub const PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: u64 = 2; + + // --- Sync committee --- + + /// Bounds `SyncCommittee.pubkeys` (`Vector`) + /// and a sync aggregate's `sync_committee_bits` + /// (`Bitvector`). + pub const SYNC_COMMITTEE_SIZE: usize = 32; + + /// Epochs a sync committee serves before the next one rotates in. A factor of + /// `UPDATE_TIMEOUT`; not itself a container bound. + pub const EPOCHS_PER_SYNC_COMMITTEE_PERIOD: u64 = 8; + + // --- Sync protocol --- + + /// Minimum signer count a sync aggregate must have for light-client update + /// validity checks to accept it. + pub const MIN_SYNC_COMMITTEE_PARTICIPANTS: u64 = 1; + + /// Slots since the light client store's finalized header before + /// `process_light_client_store_force_update` force-applies the best pending + /// update. Equal to `SLOTS_PER_EPOCH * EPOCHS_PER_SYNC_COMMITTEE_PERIOD`. + pub const UPDATE_TIMEOUT: u64 = 64; + + // ================================================================ + // Bellatrix + // ================================================================ + + // --- Rewards and penalties --- + + /// Bellatrix's replacement for `INACTIVITY_PENALTY_QUOTIENT_ALTAIR`. + pub const INACTIVITY_PENALTY_QUOTIENT_BELLATRIX: u64 = 16_777_216; + + /// Bellatrix's replacement for `MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR`. + pub const MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX: u64 = 32; + + /// Bellatrix's replacement for `PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR`. + pub const PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX: u64 = 3; + + // --- Execution --- + + /// Bounds the `Transaction` type itself (`ByteList` + /// is `Transaction`'s SSZ definition). + pub const MAX_BYTES_PER_TRANSACTION: usize = 1_073_741_824; + + /// Bounds `ExecutionPayload.transactions` + /// (`List`). + pub const MAX_TRANSACTIONS_PER_PAYLOAD: usize = 1_048_576; + + /// Bounds `ExecutionPayload(Header).logs_bloom` + /// (`ByteVector`). + pub const BYTES_PER_LOGS_BLOOM: usize = 256; + + /// Bounds `ExecutionPayload(Header).extra_data` + /// (`ByteList`). + pub const MAX_EXTRA_DATA_BYTES: usize = 32; + + // ================================================================ + // Capella + // ================================================================ + + // --- Max operations per block --- + + /// Bounds `BeaconBlockBody.bls_to_execution_changes` + /// (`List`). + pub const MAX_BLS_TO_EXECUTION_CHANGES: usize = 16; + + // --- Execution --- + + /// Bounds `ExecutionPayload(Header).withdrawals` + /// (`List`). + pub const MAX_WITHDRAWALS_PER_PAYLOAD: usize = 4; + + // --- Withdrawals processing --- + + /// Cap on how many validators `get_expected_withdrawals` scans per slot while + /// sweeping the registry for withdrawable balances. A loop bound the + /// withdrawal-sweep algorithm uses, not a container length, so it stays + /// `u64`. + pub const MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP: u64 = 16; + + // ================================================================ + // Deneb + // ================================================================ + + // --- Execution --- + + /// Bounds `BeaconBlockBody.blob_kzg_commitments` + /// (`List`) and, from fulu, + /// `DataColumnSidecar.column` / `kzg_commitments`. + pub const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize = 4096; + + // --- Networking --- + + /// Bounds `BlobSidecar.kzg_commitment_inclusion_proof` + /// (`Vector`), the merkle proof + /// that a commitment sits at its claimed index in `blob_kzg_commitments`. + pub const KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: usize = 17; + + // --- Blob --- + + /// Bounds a blob's polynomial representation + /// (`Vector`), and is a factor of + /// `BYTES_PER_BLOB` and (doubled) fulu's `FIELD_ELEMENTS_PER_EXT_BLOB`. Not + /// customized for minimal: a smaller blob would need a different trusted + /// setup, so this preset keeps mainnet's value. + pub const FIELD_ELEMENTS_PER_BLOB: usize = 4096; + + /// `BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB`, the specification's + /// formula for the bound on the `Blob` type + /// (`ByteVector`), carried in `BlobSidecar.blob`. + /// + /// Derived rather than transcribed, so the two cannot drift apart. + /// `BYTES_PER_FIELD_ELEMENT` is a fixed spec constant rather than a preset + /// value, so it comes from [`crate::beacon::constants`]. + pub const BYTES_PER_BLOB: usize = + crate::beacon::constants::BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB; + + // ================================================================ + // Electra + // ================================================================ + + // --- Gwei values --- + + /// Minimum balance a validator must reach before it can activate. Electra's + /// deposit-flow counterpart to `MIN_DEPOSIT_AMOUNT`. + pub const MIN_ACTIVATION_BALANCE: u64 = 32_000_000_000; + + /// Electra's raised ceiling on effective balance for validators with a + /// compounding (0x02) withdrawal credential; validators without one still use + /// `MAX_EFFECTIVE_BALANCE`. + pub const MAX_EFFECTIVE_BALANCE_ELECTRA: u64 = 2_048_000_000_000; + + // --- Rewards and penalties --- + + /// Electra's replacement for `MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR`, tightened + /// alongside the higher `MAX_EFFECTIVE_BALANCE_ELECTRA`. + pub const MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA: u64 = 4096; + + /// Electra's replacement for `WHISTLEBLOWER_REWARD_QUOTIENT`. + pub const WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA: u64 = 4096; + + // --- State list lengths --- + + /// Bounds `BeaconState.pending_deposits` + /// (`List`), electra's queue of + /// deposits not yet processed into the registry. + pub const PENDING_DEPOSITS_LIMIT: usize = 134_217_728; + + /// Bounds `BeaconState.pending_partial_withdrawals` + /// (`List`). + pub const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize = 64; + + /// Bounds `BeaconState.pending_consolidations` + /// (`List`). + pub const PENDING_CONSOLIDATIONS_LIMIT: usize = 64; + + // --- Max operations per block --- + + /// Electra's replacement for `MAX_ATTESTER_SLASHINGS`, bounding + /// `BeaconBlockBody.attester_slashings` now that committee bits move + /// attesting indices out of the slashing itself. + pub const MAX_ATTESTER_SLASHINGS_ELECTRA: usize = 1; + + /// Electra's replacement for `MAX_ATTESTATIONS`, lowered because one electra + /// `Attestation` now covers every committee in a slot instead of one. + pub const MAX_ATTESTATIONS_ELECTRA: usize = 8; + + /// `MAX_COMMITTEES_PER_SLOT * MAX_VALIDATORS_PER_COMMITTEE`, the + /// specification's formula for the bound on `Attestation.aggregation_bits` + /// (`Bitlist`) and + /// `IndexedAttestation.attesting_indices` + /// (`List`) from electra onward, + /// since one attestation's bitfield now spans every committee in the slot + /// rather than one. + pub const MAX_VALIDATORS_PER_SLOT: usize = + MAX_COMMITTEES_PER_SLOT * MAX_VALIDATORS_PER_COMMITTEE; + + // --- Execution --- + + /// Bounds `ExecutionRequests.deposits` + /// (`List`). + pub const MAX_DEPOSIT_REQUESTS_PER_PAYLOAD: usize = 8192; + + /// Bounds `ExecutionRequests.withdrawals` + /// (`List`). + pub const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize = 16; + + /// Bounds `ExecutionRequests.consolidations` + /// (`List`). + pub const MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: usize = 2; + + // --- Withdrawals processing --- + + /// Cap on pending partial withdrawals `get_expected_withdrawals` drains per + /// slot. A loop bound, not a container length, so it stays `u64`. + pub const MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP: u64 = 2; + + // --- Pending deposits processing --- + + /// Cap on pending deposits `process_pending_deposits` processes per epoch. A + /// loop bound, not a container length, so it stays `u64`. + pub const MAX_PENDING_DEPOSITS_PER_EPOCH: u64 = 16; + + // ================================================================ + // Fulu + // ================================================================ + + // --- Networking --- + + /// Bounds `DataColumnSidecar.kzg_commitments_inclusion_proof` + /// (`Vector`). Shallower than + /// deneb's `KZG_COMMITMENT_INCLUSION_PROOF_DEPTH` because it proves the root + /// of the whole `blob_kzg_commitments` list rather than one leaf. + pub const KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: usize = 4; + + // --- Blob --- + + /// Bounds a `Cell`'s field-element view + /// (`Vector`), and is a factor of + /// `BYTES_PER_CELL`. + pub const FIELD_ELEMENTS_PER_CELL: usize = 64; + + /// Bounds the Reed-Solomon-extended blob polynomial (`PolynomialCoeff`, a + /// `List`); twice + /// `FIELD_ELEMENTS_PER_BLOB` since the extension doubles the evaluation + /// domain. + pub const FIELD_ELEMENTS_PER_EXT_BLOB: usize = 8192; + + /// Bounds the per-blob cell and proof arrays `compute_cells_and_kzg_proofs` + /// returns (`Vector` and + /// `Vector`). + pub const CELLS_PER_EXT_BLOB: usize = 128; + + /// Bounds `DataColumnsByRootIdentifier.columns` + /// (`List`). One data column corresponds to + /// one index across the extended matrix, so this equals `CELLS_PER_EXT_BLOB`. + pub const NUMBER_OF_COLUMNS: usize = 128; + + /// `FIELD_ELEMENTS_PER_CELL * BYTES_PER_FIELD_ELEMENT`, the specification's + /// formula for the bound on the `Cell` type (`ByteVector`). + /// + /// Derived rather than transcribed, from the same [`crate::beacon::constants`] value + /// `BYTES_PER_BLOB` uses. + pub const BYTES_PER_CELL: usize = + FIELD_ELEMENTS_PER_CELL * crate::beacon::constants::BYTES_PER_FIELD_ELEMENT; + + // --- State list lengths --- + + /// `(MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH`, the specification's formula + /// for the length of `BeaconState.proposer_lookahead` + /// (`Vector`), the vector of + /// precomputed proposer indices fulu adds to the state. + pub const PROPOSER_LOOKAHEAD_LENGTH: usize = + (MIN_SEED_LOOKAHEAD as usize + 1) * SLOTS_PER_EPOCH as usize; +} + +#[cfg(not(feature = "preset-minimal"))] +pub use mainnet::*; +#[cfg(feature = "preset-minimal")] +pub use minimal::*; + +/// Preset values that a later fork retunes without changing any container's +/// shape. +/// +/// The specification expresses these as a fresh constant per fork +/// (`MIN_SLASHING_PENALTY_QUOTIENT`, then `..._ALTAIR`, then `..._BELLATRIX`) +/// and redefines the function that reads it, so that each fork's copy of the +/// function reads its own constant. Reproducing that here would mean one copy +/// of `slash_validator` per fork, differing in a single identifier (and, +/// through deneb, one copy of `process_slashings` the same way). Selecting +/// the value by fork instead keeps one copy of each function, and puts the +/// whole fork-to-value mapping in one place where it can be read against the +/// specification's own tables. +/// +/// Electra breaks that pattern for `process_slashings` specifically +/// (EIP-7251): its own copy restructures the division around the constant +/// rather than only swapping the constant in, so from electra on a value +/// selected here is no longer enough on its own to keep one shared copy of +/// that function correct. `ethlambda_beacon::stf::epoch::electra::process_slashings` is +/// a separate function for exactly that reason; see its own doc for the +/// arithmetic. `slash_validator` never breaks the pattern this module +/// describes, so it keeps reading [`retuned::min_slashing_penalty_quotient`] +/// and [`retuned::whistleblower_reward_quotient`] from here through every fork this crate +/// implements. +/// +/// This is the one place in the crate where a preset value is chosen at runtime. +/// It is sound because none of these bound a container: they are divisors and +/// multipliers in balance arithmetic, so nothing about them has to be known at +/// compile time. +/// +/// # The two presets do not agree on the direction of these changes +/// +/// The minimal preset overrides only the *phase0* values and inherits every +/// later fork's from mainnet unchanged. So a value can move one way across a +/// fork boundary under mainnet and the other way under minimal: +/// `INACTIVITY_PENALTY_QUOTIENT` falls from phase0 to altair under mainnet and +/// rises under minimal, and `MIN_SLASHING_PENALTY_QUOTIENT` falls under mainnet +/// but is unchanged under minimal. +/// +/// That is worth knowing before writing anything that assumes these get +/// uniformly harsher over time. They do under mainnet; the tests below therefore +/// pin the fork-to-constant mapping, which holds under both presets, rather than +/// any numeric relationship, which does not. +pub mod retuned { + use crate::beacon::fork::ForkName; + use crate::beacon::lean_fork_unreachable; + + /// How much the summed slashings are scaled by before being capped at the + /// total active balance. + /// + /// Raised at altair and again at bellatrix, so slashing together with a + /// larger fraction of the validator set costs proportionally more than it + /// used to. + pub fn proportional_slashing_multiplier(fork: ForkName) -> u64 { + match fork { + ForkName::Phase0 => super::PROPORTIONAL_SLASHING_MULTIPLIER, + ForkName::Altair => super::PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR, + ForkName::Bellatrix + | ForkName::Capella + | ForkName::Deneb + | ForkName::Electra + | ForkName::Fulu => super::PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX, + ForkName::Lean => lean_fork_unreachable("proportional_slashing_multiplier"), + } + } + + /// The divisor setting the immediate penalty a slashed validator pays, before + /// the epoch boundary's proportional penalty. + /// + /// Lowered through altair and bellatrix, so the immediate penalty grows, and + /// then raised steeply at electra. That reversal is not a relaxation: electra + /// raises the ceiling on a validator's effective balance, so leaving the + /// divisor where bellatrix put it would have made the immediate penalty on a + /// maximally consolidated validator far larger in absolute terms than the + /// penalty bellatrix intended. The divisor grows roughly in step with the + /// balance ceiling. + pub fn min_slashing_penalty_quotient(fork: ForkName) -> u64 { + match fork { + ForkName::Phase0 => super::MIN_SLASHING_PENALTY_QUOTIENT, + ForkName::Altair => super::MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR, + ForkName::Bellatrix | ForkName::Capella | ForkName::Deneb => { + super::MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX + } + ForkName::Electra | ForkName::Fulu => super::MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA, + ForkName::Lean => lean_fork_unreachable("min_slashing_penalty_quotient"), + } + } + + /// The divisor setting the reporter's cut of a slashed validator's effective + /// balance. + /// + /// Electra raises the divisor, which lowers the reward, because the same + /// fork raises the maximum effective balance: leaving the divisor alone would + /// have made reporting a large validator far more lucrative than reporting a + /// small one. + pub fn whistleblower_reward_quotient(fork: ForkName) -> u64 { + match fork { + ForkName::Electra | ForkName::Fulu => super::WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA, + ForkName::Phase0 + | ForkName::Altair + | ForkName::Bellatrix + | ForkName::Capella + | ForkName::Deneb => super::WHISTLEBLOWER_REWARD_QUOTIENT, + ForkName::Lean => lean_fork_unreachable("whistleblower_reward_quotient"), + } + } + + /// The divisor setting how fast an inactive validator's balance leaks while + /// the chain is failing to finalize. + /// + /// Altair and later scale the leak by a validator's own `inactivity_scores` + /// entry rather than reading this directly, so in practice only phase0's + /// inactivity penalty consults it. The later arms exist so that a caller + /// asking for a fork's value gets the right answer rather than phase0's. + pub fn inactivity_penalty_quotient(fork: ForkName) -> u64 { + match fork { + ForkName::Phase0 => super::INACTIVITY_PENALTY_QUOTIENT, + ForkName::Altair => super::INACTIVITY_PENALTY_QUOTIENT_ALTAIR, + ForkName::Bellatrix + | ForkName::Capella + | ForkName::Deneb + | ForkName::Electra + | ForkName::Fulu => super::INACTIVITY_PENALTY_QUOTIENT_BELLATRIX, + ForkName::Lean => lean_fork_unreachable("inactivity_penalty_quotient"), + } + } + + #[cfg(test)] + mod tests { + use super::*; + + use super::super::{ + INACTIVITY_PENALTY_QUOTIENT, INACTIVITY_PENALTY_QUOTIENT_ALTAIR, + INACTIVITY_PENALTY_QUOTIENT_BELLATRIX, MIN_SLASHING_PENALTY_QUOTIENT, + MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR, MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX, + MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA, PROPORTIONAL_SLASHING_MULTIPLIER, + PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR, PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX, + WHISTLEBLOWER_REWARD_QUOTIENT, WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA, + }; + + /// Pins which constant each fork selects. + /// + /// The failure this guards against is a swapped or misplaced match arm, so + /// the assertions name the constants rather than comparing numbers. An + /// earlier version of this test compared values instead, asserting that + /// slashing gets uniformly harsher across the forks. That holds under + /// mainnet and is false under minimal, which overrides only phase0's + /// values and inherits the rest, so phase0 to altair moves the other way + /// there. Naming the constants is the only formulation that is both + /// preset-independent and able to catch a swapped arm. + #[test] + fn every_fork_selects_its_own_constant() { + let bellatrix_onward = [ + ForkName::Bellatrix, + ForkName::Capella, + ForkName::Deneb, + ForkName::Electra, + ForkName::Fulu, + ]; + + assert_eq!( + proportional_slashing_multiplier(ForkName::Phase0), + PROPORTIONAL_SLASHING_MULTIPLIER + ); + assert_eq!( + proportional_slashing_multiplier(ForkName::Altair), + PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR + ); + for fork in bellatrix_onward { + assert_eq!( + proportional_slashing_multiplier(fork), + PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX, + "{fork} must use bellatrix's slashing multiplier", + ); + } + + assert_eq!( + inactivity_penalty_quotient(ForkName::Phase0), + INACTIVITY_PENALTY_QUOTIENT + ); + assert_eq!( + inactivity_penalty_quotient(ForkName::Altair), + INACTIVITY_PENALTY_QUOTIENT_ALTAIR + ); + for fork in bellatrix_onward { + assert_eq!( + inactivity_penalty_quotient(fork), + INACTIVITY_PENALTY_QUOTIENT_BELLATRIX, + "{fork} must use bellatrix's inactivity penalty quotient", + ); + } + + assert_eq!( + min_slashing_penalty_quotient(ForkName::Phase0), + MIN_SLASHING_PENALTY_QUOTIENT + ); + assert_eq!( + min_slashing_penalty_quotient(ForkName::Altair), + MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR + ); + for fork in [ForkName::Bellatrix, ForkName::Capella, ForkName::Deneb] { + assert_eq!( + min_slashing_penalty_quotient(fork), + MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX, + "{fork} must use bellatrix's penalty divisor", + ); + } + for fork in [ForkName::Electra, ForkName::Fulu] { + assert_eq!( + min_slashing_penalty_quotient(fork), + MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA, + "{fork} must use electra's penalty divisor", + ); + } + + for fork in [ + ForkName::Phase0, + ForkName::Altair, + ForkName::Bellatrix, + ForkName::Capella, + ForkName::Deneb, + ] { + assert_eq!( + whistleblower_reward_quotient(fork), + WHISTLEBLOWER_REWARD_QUOTIENT, + "{fork} predates electra's whistleblower reward change", + ); + } + for fork in [ForkName::Electra, ForkName::Fulu] { + assert_eq!( + whistleblower_reward_quotient(fork), + WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA, + "{fork} must use electra's whistleblower reward quotient", + ); + } + } + + /// Every fork must get an answer from every selector. A `match` makes this + /// true by construction today, but the selectors are the kind of code a + /// later edit turns into a lookup with a fallible default. + #[test] + fn no_fork_is_left_without_a_value() { + for fork in ForkName::ALL { + assert_ne!(proportional_slashing_multiplier(fork), 0); + assert_ne!(min_slashing_penalty_quotient(fork), 0); + assert_ne!(whistleblower_reward_quotient(fork), 0); + assert_ne!(inactivity_penalty_quotient(fork), 0); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::{mainnet, minimal}; + + /// Values pinned directly from the specification, so a typo or an accidental + /// edit shows up as a failing test rather than a silent divergence from + /// `presets/{mainnet,minimal}/*.yaml`. + #[test] + fn pinned_values() { + assert_eq!(mainnet::SLOTS_PER_EPOCH, 32); + assert_eq!(minimal::SLOTS_PER_EPOCH, 8); + + assert_eq!(mainnet::SYNC_COMMITTEE_SIZE, 512); + assert_eq!(minimal::SYNC_COMMITTEE_SIZE, 32); + + assert_eq!(mainnet::MAX_COMMITTEES_PER_SLOT, 64); + assert_eq!(minimal::MAX_COMMITTEES_PER_SLOT, 4); + + assert_eq!(mainnet::SLOTS_PER_HISTORICAL_ROOT, 8192); + assert_eq!(minimal::SLOTS_PER_HISTORICAL_ROOT, 64); + + assert_eq!(mainnet::FIELD_ELEMENTS_PER_BLOB, 4096); + assert_eq!(minimal::FIELD_ELEMENTS_PER_BLOB, 4096); + + assert_eq!(mainnet::MAX_VALIDATORS_PER_SLOT, 131_072); + assert_eq!(minimal::MAX_VALIDATORS_PER_SLOT, 8192); + } + + /// Every derived constant computed from more than one preset value, checked + /// against the specification's formula spelled out arithmetically rather than + /// copied as a literal. + #[test] + fn derived_values() { + assert_eq!( + mainnet::MAX_PENDING_ATTESTATIONS, + mainnet::MAX_ATTESTATIONS * mainnet::SLOTS_PER_EPOCH as usize + ); + assert_eq!( + minimal::MAX_PENDING_ATTESTATIONS, + minimal::MAX_ATTESTATIONS * minimal::SLOTS_PER_EPOCH as usize + ); + + assert_eq!( + mainnet::SLOTS_PER_ETH1_VOTING_PERIOD, + mainnet::EPOCHS_PER_ETH1_VOTING_PERIOD as usize * mainnet::SLOTS_PER_EPOCH as usize + ); + assert_eq!( + minimal::SLOTS_PER_ETH1_VOTING_PERIOD, + minimal::EPOCHS_PER_ETH1_VOTING_PERIOD as usize * minimal::SLOTS_PER_EPOCH as usize + ); + + assert_eq!( + mainnet::BYTES_PER_BLOB, + 32 * mainnet::FIELD_ELEMENTS_PER_BLOB + ); + assert_eq!( + minimal::BYTES_PER_BLOB, + 32 * minimal::FIELD_ELEMENTS_PER_BLOB + ); + + assert_eq!( + mainnet::BYTES_PER_CELL, + mainnet::FIELD_ELEMENTS_PER_CELL * crate::beacon::constants::BYTES_PER_FIELD_ELEMENT + ); + assert_eq!( + minimal::BYTES_PER_CELL, + minimal::FIELD_ELEMENTS_PER_CELL * crate::beacon::constants::BYTES_PER_FIELD_ELEMENT + ); + + assert_eq!( + mainnet::PROPOSER_LOOKAHEAD_LENGTH, + (mainnet::MIN_SEED_LOOKAHEAD as usize + 1) * mainnet::SLOTS_PER_EPOCH as usize + ); + assert_eq!( + minimal::PROPOSER_LOOKAHEAD_LENGTH, + (minimal::MIN_SEED_LOOKAHEAD as usize + 1) * minimal::SLOTS_PER_EPOCH as usize + ); + + assert_eq!( + mainnet::MAX_VALIDATORS_PER_SLOT, + mainnet::MAX_COMMITTEES_PER_SLOT * mainnet::MAX_VALIDATORS_PER_COMMITTEE + ); + assert_eq!( + minimal::MAX_VALIDATORS_PER_SLOT, + minimal::MAX_COMMITTEES_PER_SLOT * minimal::MAX_VALIDATORS_PER_COMMITTEE + ); + } + + /// Every name this module defines must resolve, at the same type, through + /// both `mainnet::` and `minimal::`. Referencing every constant through both + /// paths turns a name present in one preset but missing (or misspelled) in + /// the other into a compile error here, rather than a runtime surprise for + /// whichever fork first needs the missing side. + #[test] + fn same_names_in_both_presets() { + /// Names one constant at its type through both presets. The pairing is + /// the point, so the macro takes the name once and writes both paths. + macro_rules! in_both { + ($ty:ty: $($name:ident),+ $(,)?) => { + $( + let _: $ty = mainnet::$name; + let _: $ty = minimal::$name; + )+ + }; + } + + in_both!(usize: MAX_COMMITTEES_PER_SLOT); + in_both!(u64: TARGET_COMMITTEE_SIZE); + in_both!(usize: MAX_VALIDATORS_PER_COMMITTEE); + in_both!(u64: + SHUFFLE_ROUND_COUNT, HYSTERESIS_QUOTIENT, HYSTERESIS_DOWNWARD_MULTIPLIER, + HYSTERESIS_UPWARD_MULTIPLIER, + ); + + in_both!(u64: MIN_DEPOSIT_AMOUNT, MAX_EFFECTIVE_BALANCE, EFFECTIVE_BALANCE_INCREMENT); + + in_both!(u64: + MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH, MIN_SEED_LOOKAHEAD, + MAX_SEED_LOOKAHEAD, EPOCHS_PER_ETH1_VOTING_PERIOD, + ); + in_both!(usize: SLOTS_PER_ETH1_VOTING_PERIOD, SLOTS_PER_HISTORICAL_ROOT); + in_both!(u64: MIN_EPOCHS_TO_INACTIVITY_PENALTY); + + in_both!(usize: + EPOCHS_PER_HISTORICAL_VECTOR, EPOCHS_PER_SLASHINGS_VECTOR, HISTORICAL_ROOTS_LIMIT, + VALIDATOR_REGISTRY_LIMIT, + ); + + in_both!(u64: + BASE_REWARD_FACTOR, WHISTLEBLOWER_REWARD_QUOTIENT, PROPOSER_REWARD_QUOTIENT, + INACTIVITY_PENALTY_QUOTIENT, MIN_SLASHING_PENALTY_QUOTIENT, + PROPORTIONAL_SLASHING_MULTIPLIER, + ); + + in_both!(usize: + MAX_PROPOSER_SLASHINGS, MAX_ATTESTER_SLASHINGS, MAX_ATTESTATIONS, + MAX_PENDING_ATTESTATIONS, MAX_DEPOSITS, MAX_VOLUNTARY_EXITS, + ); + + in_both!(u64: + INACTIVITY_PENALTY_QUOTIENT_ALTAIR, MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR, + PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR, + ); + in_both!(usize: SYNC_COMMITTEE_SIZE); + in_both!(u64: + EPOCHS_PER_SYNC_COMMITTEE_PERIOD, MIN_SYNC_COMMITTEE_PARTICIPANTS, UPDATE_TIMEOUT, + ); + + in_both!(u64: + INACTIVITY_PENALTY_QUOTIENT_BELLATRIX, MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX, + PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX, + ); + in_both!(usize: + MAX_BYTES_PER_TRANSACTION, MAX_TRANSACTIONS_PER_PAYLOAD, BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + ); + + in_both!(usize: MAX_BLS_TO_EXECUTION_CHANGES, MAX_WITHDRAWALS_PER_PAYLOAD); + in_both!(u64: MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP); + + in_both!(usize: + MAX_BLOB_COMMITMENTS_PER_BLOCK, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH, + FIELD_ELEMENTS_PER_BLOB, BYTES_PER_BLOB, + ); + + in_both!(u64: + MIN_ACTIVATION_BALANCE, MAX_EFFECTIVE_BALANCE_ELECTRA, + MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA, WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA, + ); + in_both!(usize: + PENDING_DEPOSITS_LIMIT, PENDING_PARTIAL_WITHDRAWALS_LIMIT, PENDING_CONSOLIDATIONS_LIMIT, + MAX_ATTESTER_SLASHINGS_ELECTRA, MAX_ATTESTATIONS_ELECTRA, MAX_VALIDATORS_PER_SLOT, + MAX_DEPOSIT_REQUESTS_PER_PAYLOAD, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD, + ); + in_both!(u64: MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP, MAX_PENDING_DEPOSITS_PER_EPOCH); + + in_both!(usize: + KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH, FIELD_ELEMENTS_PER_CELL, + FIELD_ELEMENTS_PER_EXT_BLOB, CELLS_PER_EXT_BLOB, NUMBER_OF_COLUMNS, BYTES_PER_CELL, + PROPOSER_LOOKAHEAD_LENGTH, + ); + } +} diff --git a/crates/common/types/src/beacon/primitives.rs b/crates/common/types/src/beacon/primitives.rs new file mode 100644 index 000000000..ed1d56f5a --- /dev/null +++ b/crates/common/types/src/beacon/primitives.rs @@ -0,0 +1,496 @@ +//! The specification's primitive types. +//! +//! Scalar spec types are aliases of `u64` rather than newtypes. The +//! specification does arithmetic on slots, epochs, and balances freely, and +//! wrapping each in its own type would mean either arithmetic trait impls or +//! constant unwrapping, neither of which makes the state transition easier to +//! check against the spec text. +//! +//! Fixed-length byte strings do get newtypes, because confusing a public key +//! with a signature or a commitment is a real mistake that the compiler can +//! catch for free. +//! +//! [`H160`] and [`U256`] are declared here rather than taken from a crate of +//! Ethereum primitives. A Beacon Chain container needs three types of that +//! family: a 32-byte hash, a 20-byte address, and a 256-bit integer. The first +//! is already [`crate::primitives::H256`], so an external crate would save two +//! declarations and cost a second `H256` that every root in the crate has to be +//! converted through. + +use core::{cmp::Ordering, fmt}; + +use libssz_derive::{HashTreeRoot, SszDecode, SszEncode}; + +pub use crate::primitives::{H256, HashTreeRoot}; + +/// A slot number. +pub type Slot = u64; +/// An epoch number. +pub type Epoch = u64; +/// An index into a slot's committees. +pub type CommitteeIndex = u64; +/// An index into the validator registry. +pub type ValidatorIndex = u64; +/// An amount of Gwei. +pub type Gwei = u64; +/// An index into the withdrawal sequence. +pub type WithdrawalIndex = u64; +/// An index into a block's blobs. +pub type BlobIndex = u64; +/// An index into a block's data columns. +pub type ColumnIndex = u64; + +/// A merkle root or any other 32-byte hash. +/// +/// The same [`H256`] the lean types use, so a beacon block root reaching a +/// store lookup needs no conversion. The two chains disagree about nearly +/// everything else, but a 32-byte SSZ hash is a 32-byte SSZ hash. +pub type Root = H256; +/// 32 bytes with no further meaning attached. +pub type Bytes32 = H256; +/// A 256-bit unsigned integer, SSZ-encoded little-endian. +pub type Uint256 = U256; +/// An execution layer address. +pub type ExecutionAddress = H160; +/// An execution layer block hash. +pub type ExecutionBlockHash = H256; + +/// A fork version. +pub type Version = [u8; 4]; +/// The four-byte prefix that separates signature domains. +pub type DomainType = [u8; 4]; +/// A signing domain: a domain type combined with a fork version and the genesis +/// validators root. +pub type Domain = [u8; 32]; +/// The four bytes identifying a fork on the wire. +pub type ForkDigest = [u8; 4]; + +/// A bitfield of participation flags for one validator, one bit per flag index. +pub type ParticipationFlags = u8; + +/// The number of bytes in an execution layer address. +pub const ADDRESS_SIZE: usize = 20; +/// The number of bytes in a BLS12-381 public key. +pub const BLS_PUBKEY_SIZE: usize = 48; +/// The number of bytes in a BLS12-381 signature. +pub const BLS_SIGNATURE_SIZE: usize = 96; +/// The number of bytes in a KZG commitment or proof, both compressed G1 points. +pub const KZG_POINT_SIZE: usize = 48; + +/// Formats a fixed-length byte string as `Name(0xabcd…)`. +/// +/// Shared by the `Debug` implementations below, which are otherwise identical, so +/// that they cannot drift into printing the same kind of value several ways. The +/// name is passed rather than taken from [`core::any::type_name`] so it stays a +/// literal the compiler checks against the type it sits on. +fn debug_byte_vector(f: &mut fmt::Formatter<'_>, name: &str, bytes: &[u8]) -> fmt::Result { + write!(f, "{name}(0x{})", hex::encode(bytes)) +} + +/// An execution layer address: an SSZ `Vector[uint8, 20]`. +/// +/// [`libssz_merkle::HashTreeRoot`] is written out rather than derived because +/// the derive does not carry `is_basic_type` through, and 20 bytes is the width +/// where that answer matters: a list or vector of *basic* elements packs them +/// contiguously into 32-byte chunks, while one of *composite* elements pads each +/// to a leaf of its own. No container holds a collection of addresses, so the +/// two agree everywhere the question is asked today; writing the answer out is +/// what keeps the first container that does hold one from silently merkleizing +/// the other way. Every other type in this module is 32 bytes wide, where +/// packing and padding coincide. +#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, SszEncode, SszDecode)] +#[ssz(transparent)] +pub struct H160(pub [u8; ADDRESS_SIZE]); + +impl H160 { + /// The all-zero address. + pub const ZERO: Self = Self([0; ADDRESS_SIZE]); + + /// Every byte set to `byte`. See [`H256::repeat_byte`]. + pub const fn repeat_byte(byte: u8) -> Self { + Self([byte; ADDRESS_SIZE]) + } + + /// # Panics + /// + /// If `bytes` is not exactly [`ADDRESS_SIZE`] long. + pub fn from_slice(bytes: &[u8]) -> Self { + Self( + bytes + .try_into() + .expect("H160::from_slice requires exactly 20 bytes"), + ) + } + + pub fn as_slice(&self) -> &[u8] { + &self.0 + } +} + +impl libssz_merkle::HashTreeRoot for H160 { + fn hash_tree_root(&self, hasher: &impl libssz_merkle::Sha256Hasher) -> libssz_merkle::Node { + libssz_merkle::HashTreeRoot::hash_tree_root(&self.0, hasher) + } + + fn is_basic_type() -> bool { + <[u8; ADDRESS_SIZE] as libssz_merkle::HashTreeRoot>::is_basic_type() + } +} + +impl From<[u8; ADDRESS_SIZE]> for H160 { + fn from(bytes: [u8; ADDRESS_SIZE]) -> Self { + Self(bytes) + } +} + +impl fmt::Debug for H160 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + debug_byte_vector(f, "H160", &self.0) + } +} + +/// A 256-bit unsigned integer. +/// +/// Held as the 32 little-endian bytes SSZ encodes it as, so encoding, decoding +/// and merkleizing are the inner array's and cannot disagree with the wire. The +/// consequence is that the stored byte order is the reverse of the numeric one, +/// which is why [`Ord`] is written out below instead of derived. +/// +/// No arithmetic, because the specification never computes on one: +/// `terminal_total_difficulty` is only ever compared against a PoW block's +/// accumulated difficulty, and `base_fee_per_gas` is carried through the +/// execution payload header untouched. +#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, SszEncode, SszDecode, HashTreeRoot)] +#[ssz(transparent)] +pub struct U256(pub [u8; 32]); + +impl U256 { + /// Zero. + pub const ZERO: Self = Self([0; 32]); + /// The largest representable value, `2^256 - 1`. + pub const MAX: Self = Self([0xff; 32]); + + /// The integer `value`, widened. + /// + /// `const` so a configuration constant that fits 128 bits can be written as + /// its decimal digits rather than as bytes. + pub const fn from_u128(value: u128) -> Self { + let mut bytes = [0; 32]; + let low = value.to_le_bytes(); + let mut i = 0; + while i < low.len() { + bytes[i] = low[i]; + i += 1; + } + Self(bytes) + } + + /// Parses a decimal string, the form every specification configuration file + /// writes a `uint256` in. + /// + /// Kept even though nothing on the shipping path parses one: the values that + /// *are* hard-coded get pinned against their decimal digits by a test, and + /// reading them back is how a mistranscribed byte is caught. + pub fn from_dec_str(digits: &str) -> Result { + if digits.is_empty() { + return Err(ParseU256Error::Empty); + } + + let mut bytes = [0u8; 32]; + for byte in digits.bytes() { + let digit = match byte { + b'0'..=b'9' => u16::from(byte - b'0'), + _ => return Err(ParseU256Error::InvalidDigit), + }; + + // `value = value * 10 + digit`, low byte first. Each step is at + // most `255 * 10 + 9`, so the running carry fits the same `u16`. + let mut carry = digit; + for limb in &mut bytes { + let widened = u16::from(*limb) * 10 + carry; + *limb = widened as u8; + carry = widened >> 8; + } + if carry != 0 { + return Err(ParseU256Error::Overflow); + } + } + Ok(Self(bytes)) + } +} + +impl From for U256 { + fn from(value: u64) -> Self { + Self::from_u128(u128::from(value)) + } +} + +impl Ord for U256 { + fn cmp(&self, other: &Self) -> Ordering { + // Most significant byte first, the reverse of how the bytes are + // stored. Deriving this would compare the least significant byte first + // and answer nonsense. + self.0.iter().rev().cmp(other.0.iter().rev()) + } +} + +impl PartialOrd for U256 { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl fmt::LowerHex for U256 { + /// Most significant digit first, with leading zeros trimmed, so the output + /// reads as a number rather than as a byte string. + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.0.iter().rposition(|&byte| byte != 0) { + None => f.write_str("0"), + Some(high) => { + write!(f, "{:x}", self.0[high])?; + for &byte in self.0[..high].iter().rev() { + write!(f, "{byte:02x}")?; + } + Ok(()) + } + } + } +} + +impl fmt::Debug for U256 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "U256(0x{self:x})") + } +} + +/// Why a decimal string was not a [`U256`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)] +pub enum ParseU256Error { + #[error("a uint256 needs at least one digit")] + Empty, + #[error("a uint256 is written in decimal digits only")] + InvalidDigit, + #[error("the value does not fit 256 bits")] + Overflow, +} + +// Each of the four types below is an SSZ `Vector[uint8, N]`: it encodes and +// merkleizes as its inner array. `Default` is written out rather than derived +// because the standard library implements it for arrays only up to length 32, +// well short of all four of these, and a derive requires every field's type to +// implement the trait. + +/// A BLS12-381 public key, compressed. +/// +/// Not validated on construction. The specification only requires a key to be a +/// valid curve point where it is used in a signature check, and deposit +/// processing depends on being able to hold a key that never validates. +#[derive(Clone, Copy, PartialEq, Eq, Hash, SszEncode, SszDecode, HashTreeRoot)] +#[ssz(transparent)] +pub struct BlsPubkey(pub [u8; BLS_PUBKEY_SIZE]); + +impl Default for BlsPubkey { + fn default() -> Self { + Self([0; BLS_PUBKEY_SIZE]) + } +} + +impl AsRef<[u8]> for BlsPubkey { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl fmt::Debug for BlsPubkey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + debug_byte_vector(f, "BlsPubkey", &self.0) + } +} + +/// A BLS12-381 signature, compressed. +#[derive(Clone, Copy, PartialEq, Eq, Hash, SszEncode, SszDecode, HashTreeRoot)] +#[ssz(transparent)] +pub struct BlsSignature(pub [u8; BLS_SIGNATURE_SIZE]); + +impl Default for BlsSignature { + fn default() -> Self { + Self([0; BLS_SIGNATURE_SIZE]) + } +} + +impl AsRef<[u8]> for BlsSignature { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl fmt::Debug for BlsSignature { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + debug_byte_vector(f, "BlsSignature", &self.0) + } +} + +/// A KZG commitment to a blob. +/// +/// The same width as [`KzgProof`] and as [`BlsPubkey`], and a separate type from +/// both for that reason: an alias would make all three interchangeable. +#[derive(Clone, Copy, PartialEq, Eq, Hash, SszEncode, SszDecode, HashTreeRoot)] +#[ssz(transparent)] +pub struct KzgCommitment(pub [u8; KZG_POINT_SIZE]); + +impl Default for KzgCommitment { + fn default() -> Self { + Self([0; KZG_POINT_SIZE]) + } +} + +impl AsRef<[u8]> for KzgCommitment { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl fmt::Debug for KzgCommitment { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + debug_byte_vector(f, "KzgCommitment", &self.0) + } +} + +/// A KZG proof. +#[derive(Clone, Copy, PartialEq, Eq, Hash, SszEncode, SszDecode, HashTreeRoot)] +#[ssz(transparent)] +pub struct KzgProof(pub [u8; KZG_POINT_SIZE]); + +impl Default for KzgProof { + fn default() -> Self { + Self([0; KZG_POINT_SIZE]) + } +} + +impl AsRef<[u8]> for KzgProof { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl fmt::Debug for KzgProof { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + debug_byte_vector(f, "KzgProof", &self.0) + } +} + +#[cfg(test)] +mod tests { + use libssz::{SszDecode as _, SszEncode as _}; + use libssz_merkle::Sha2Hasher; + + use super::*; + + /// The two-argument root, spelled out because [`HashTreeRoot`] is in scope + /// here and its own `hash_tree_root` takes no hasher. + fn ssz_root(value: &T) -> libssz_merkle::Node { + libssz_merkle::HashTreeRoot::hash_tree_root(value, &Sha2Hasher) + } + + #[test] + fn byte_vectors_round_trip_through_ssz() { + let key = BlsPubkey([7; BLS_PUBKEY_SIZE]); + let bytes = key.to_ssz(); + assert_eq!(bytes.len(), BLS_PUBKEY_SIZE); + assert_eq!(BlsPubkey::from_ssz_bytes(&bytes).unwrap(), key); + } + + #[test] + fn debug_output_is_hex() { + let proof = KzgProof([0xab; KZG_POINT_SIZE]); + assert!(format!("{proof:?}").starts_with("KzgProof(0xabab")); + } + + #[test] + fn an_address_encodes_as_its_twenty_bytes() { + let address = H160::repeat_byte(0xcd); + assert_eq!(address.to_ssz(), [0xcd; ADDRESS_SIZE]); + assert_eq!(H160::from_ssz_bytes(&address.to_ssz()).unwrap(), address); + } + + /// The property the hand-written [`libssz_merkle::HashTreeRoot`] exists for: + /// a 20-byte value is a basic type, so a collection of them packs rather + /// than padding. Both halves are checked, since the root alone would pass + /// with `is_basic_type` left at its default. + #[test] + fn an_address_is_a_basic_type_rooted_as_its_padded_bytes() { + assert!(::is_basic_type()); + + let address = H160::repeat_byte(0xcd); + let mut expected = [0u8; 32]; + expected[..ADDRESS_SIZE].fill(0xcd); + assert_eq!(ssz_root(&address), expected); + } + + #[test] + fn a_uint256_encodes_little_endian() { + let value = U256::from(258u64); + let bytes = value.to_ssz(); + assert_eq!(bytes.len(), 32); + assert_eq!(&bytes[..3], &[2, 1, 0]); + assert_eq!(U256::from_ssz_bytes(&bytes).unwrap(), value); + } + + /// A `uint256` roots to its own little-endian bytes, unhashed, so the + /// encoding above is also the leaf. + #[test] + fn a_uint256_roots_to_its_encoding() { + let value = U256::from(258u64); + assert_eq!(ssz_root(&value).as_slice(), value.to_ssz().as_slice()); + } + + /// Numeric order, not stored-byte order. `256` and `1` differ only in bytes + /// a derived `Ord` would reach in the wrong order, and would compare the + /// wrong way round: `256`'s low byte is `0` where `1`'s is `1`. + #[test] + fn uint256_compares_numerically() { + assert!(U256::from(256u64) > U256::from(1u64)); + assert!(U256::from(1u64) > U256::ZERO); + assert!(U256::MAX > U256::from(u64::MAX)); + assert_eq!(U256::from(7u64).cmp(&U256::from(7u64)), Ordering::Equal); + } + + #[test] + fn a_decimal_string_parses_to_the_same_value_as_its_digits() { + assert_eq!(U256::from_dec_str("0").unwrap(), U256::ZERO); + assert_eq!(U256::from_dec_str("258").unwrap(), U256::from(258u64)); + assert_eq!( + U256::from_dec_str("340282366920938463463374607431768211455").unwrap(), + U256::from_u128(u128::MAX), + ); + assert_eq!( + U256::from_dec_str( + "115792089237316195423570985008687907853269984665640564039457584007913129639935", + ) + .unwrap(), + U256::MAX, + ); + } + + #[test] + fn a_decimal_string_that_is_not_a_uint256_is_rejected() { + assert_eq!(U256::from_dec_str(""), Err(ParseU256Error::Empty)); + assert_eq!( + U256::from_dec_str("0x10"), + Err(ParseU256Error::InvalidDigit) + ); + assert_eq!( + // 2^256, one past the largest representable value. + U256::from_dec_str( + "115792089237316195423570985008687907853269984665640564039457584007913129639936", + ), + Err(ParseU256Error::Overflow), + ); + } + + #[test] + fn uint256_debug_is_big_endian_hex() { + assert_eq!(format!("{:?}", U256::ZERO), "U256(0x0)"); + assert_eq!(format!("{:?}", U256::from(258u64)), "U256(0x102)"); + } +} diff --git a/crates/common/types/src/lib.rs b/crates/common/types/src/lib.rs index cfb8957b2..f7d9a0ac2 100644 --- a/crates/common/types/src/lib.rs +++ b/crates/common/types/src/lib.rs @@ -1,5 +1,6 @@ pub mod aggregator; pub mod attestation; +pub mod beacon; pub mod block; pub mod chain_config; pub mod checkpoint; diff --git a/crates/common/types/src/primitives.rs b/crates/common/types/src/primitives.rs index 3eda690e7..0e8cf99fe 100644 --- a/crates/common/types/src/primitives.rs +++ b/crates/common/types/src/primitives.rs @@ -21,7 +21,6 @@ pub type ByteList = libssz_types::SszList; /// Encoded as a fixed 32-byte array (transparent SSZ wrapper). /// Serialized as a `"0x..."` hex string. #[derive( - Debug, Clone, Copy, Default, @@ -65,6 +64,15 @@ impl<'de> serde::Deserialize<'de> for H256 { impl H256 { pub const ZERO: Self = Self([0u8; 32]); + /// Every byte set to `byte`. + /// + /// Test fixtures want a hash that is obviously not the zero hash and is + /// obviously not any other fixture's hash, which one repeated byte gives + /// while staying short enough to read at a call site. + pub const fn repeat_byte(byte: u8) -> Self { + Self([byte; 32]) + } + pub fn is_zero(&self) -> bool { self.0 == [0u8; 32] } @@ -108,6 +116,19 @@ impl std::fmt::Display for H256 { } } +/// Same as [`Display`](std::fmt::Display), rather than derived. +/// +/// A derived `Debug` prints the inner array, so a hash comes out as 32 decimal +/// numbers: unreadable on its own, and unreadable in bulk inside the `Debug` of +/// a container holding thousands of roots. Assertion failures in the spec suites +/// print roots this way, so the hex is the whole point. Truncate at a call site +/// that wants it short with [`crate::ShortRoot`]. +impl std::fmt::Debug for H256 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self}") + } +} + #[cfg(test)] mod tests { use super::*; @@ -134,6 +155,16 @@ mod tests { assert_eq!(h, H256([0xcd; 32])); } + /// Not the derived `Debug`, which would print the inner array as 32 decimal + /// numbers. Spec-suite assertion failures print roots through `Debug`, so + /// this is the difference between a readable diff and an unreadable one. + #[test] + fn h256_debug_is_the_same_hex_as_display() { + let h = H256::repeat_byte(0xab); + assert_eq!(format!("{h:?}"), format!("{h}")); + assert_eq!(format!("{h:?}"), format!("0x{}", "ab".repeat(32))); + } + #[test] fn h256_from_slice_exact_32_bytes() { let bytes = [0x42u8; 32]; diff --git a/crates/common/types/src/state.rs b/crates/common/types/src/state.rs index d117151e2..db835e278 100644 --- a/crates/common/types/src/state.rs +++ b/crates/common/types/src/state.rs @@ -12,7 +12,7 @@ use crate::{ use primitives::HashTreeRoot as _; /// The main consensus state object -#[derive(Debug, Clone, SszEncode, SszDecode, HashTreeRoot)] +#[derive(Debug, Clone, PartialEq, SszEncode, SszDecode, HashTreeRoot)] pub struct State { /// The chain's configuration parameters pub config: StateConfig, @@ -66,7 +66,7 @@ pub type JustificationValidators = /// Each validator has two independent XMSS keys: one for signing attestations /// and one for signing block proposals. This allows signing both in the same /// slot without violating OTS (one-time signature) constraints. -#[derive(Debug, Clone, Serialize, SszEncode, SszDecode, HashTreeRoot)] +#[derive(Debug, Clone, PartialEq, Serialize, SszEncode, SszDecode, HashTreeRoot)] pub struct Validator { /// XMSS public key used for attestation signing. #[serde(serialize_with = "serialize_pubkey_hex")] @@ -120,7 +120,7 @@ impl State { /// Merkleized into the state root, so its layout is fixed by the spec and no /// field may be added here. [`crate::chain_config::ChainConfig`] is the node's /// own view: this plus the slot duration. -#[derive(Debug, Clone, Serialize, Deserialize, SszEncode, SszDecode, HashTreeRoot)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SszEncode, SszDecode, HashTreeRoot)] pub struct StateConfig { pub genesis_time: u64, } From bf328c6151541e45e011635cc40e844105e566cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Thu, 3 Sep 2026 18:16:28 -0300 Subject: [PATCH 02/49] Merge pull request #2 from lambdaclass/feat/beacon-chain-stf feat(state-transition): Beacon Chain state transition, phase0 through fulu --- .github/actions/free-disk-space/action.yml | 71 + .github/actions/run-fixture-tests/action.yml | 9 + .github/workflows/ci.yml | 124 +- .github/workflows/daily_ci.yml | 6 + .gitignore | 3 + CLAUDE.md | 86 + Cargo.lock | 16 +- Makefile | 77 +- crates/blockchain/state_transition/Cargo.toml | 69 + .../state_transition/src/beacon/bls.rs | 433 ++++ .../src/beacon/fork_choice.rs | 2028 +++++++++++++++ .../state_transition/src/beacon/genesis.rs | 210 ++ .../state_transition/src/beacon/hash.rs | 40 + .../src/beacon/helpers/accessors.rs | 290 +++ .../src/beacon/helpers/altair.rs | 520 ++++ .../src/beacon/helpers/attestation.rs | 91 + .../src/beacon/helpers/capella.rs | 144 ++ .../src/beacon/helpers/electra.rs | 1409 +++++++++++ .../src/beacon/helpers/finality.rs | 56 + .../src/beacon/helpers/fulu.rs | 279 +++ .../src/beacon/helpers/math.rs | 95 + .../src/beacon/helpers/misc.rs | 199 ++ .../src/beacon/helpers/mod.rs | 27 + .../src/beacon/helpers/mutators.rs | 270 ++ .../src/beacon/helpers/predicates.rs | 167 ++ .../src/beacon/helpers/shuffling.rs | 226 ++ .../src/beacon/helpers/test_state.rs | 509 ++++ .../state_transition/src/beacon/kzg.rs | 968 ++++++++ .../src/beacon/lean_boundary.rs | 49 + .../state_transition/src/beacon/mod.rs | 91 + .../state_transition/src/beacon/stf/altair.rs | 742 ++++++ .../src/beacon/stf/bellatrix.rs | 486 ++++ .../state_transition/src/beacon/stf/block.rs | 313 +++ .../src/beacon/stf/capella.rs | 822 +++++++ .../state_transition/src/beacon/stf/deneb.rs | 734 ++++++ .../src/beacon/stf/electra.rs | 2185 +++++++++++++++++ .../src/beacon/stf/epoch/altair.rs | 498 ++++ .../src/beacon/stf/epoch/capella.rs | 223 ++ .../src/beacon/stf/epoch/electra.rs | 1254 ++++++++++ .../src/beacon/stf/epoch/fulu.rs | 180 ++ .../src/beacon/stf/epoch/justification.rs | 253 ++ .../src/beacon/stf/epoch/mod.rs | 321 +++ .../src/beacon/stf/epoch/registry.rs | 386 +++ .../src/beacon/stf/epoch/rewards.rs | 372 +++ .../state_transition/src/beacon/stf/fulu.rs | 393 +++ .../state_transition/src/beacon/stf/mod.rs | 293 +++ .../src/beacon/stf/operations.rs | 678 +++++ .../state_transition/src/beacon/upgrade.rs | 1173 +++++++++ crates/blockchain/state_transition/src/lib.rs | 9 + .../state_transition/tests/beacon_spec/bls.rs | 175 ++ .../tests/beacon_spec/epoch_processing.rs | 236 ++ .../tests/beacon_spec/fork.rs | 92 + .../tests/beacon_spec/fork_choice.rs | 861 +++++++ .../tests/beacon_spec/genesis.rs | 141 ++ .../tests/beacon_spec/harness.rs | 142 ++ .../state_transition/tests/beacon_spec/kzg.rs | 473 ++++ .../state_transition/tests/beacon_spec/mod.rs | 460 ++++ .../tests/beacon_spec/operations.rs | 500 ++++ .../tests/beacon_spec/rewards.rs | 191 ++ .../tests/beacon_spec/sanity.rs | 93 + .../tests/beacon_spec/shuffling.rs | 70 + .../tests/beacon_spec/ssz_static.rs | 349 +++ .../tests/beacon_spec/transition.rs | 195 ++ .../tests/beacon_spec_tests.rs | 54 + crates/common/types/Cargo.toml | 2 +- crates/common/types/src/beacon/config.rs | 4 +- crates/common/types/src/beacon/constants.rs | 4 +- .../common/types/src/beacon/containers/mod.rs | 14 +- crates/common/types/src/beacon/fork.rs | 2 +- crates/common/types/src/beacon/fork_choice.rs | 12 +- crates/common/types/src/beacon/fork_digest.rs | 8 +- crates/common/types/src/beacon/mod.rs | 3 +- crates/common/types/src/beacon/preset.rs | 5 +- docs/SUMMARY.md | 4 + docs/beacon_stf.md | 496 ++++ 75 files changed, 24422 insertions(+), 41 deletions(-) create mode 100644 .github/actions/free-disk-space/action.yml create mode 100644 crates/blockchain/state_transition/src/beacon/bls.rs create mode 100644 crates/blockchain/state_transition/src/beacon/fork_choice.rs create mode 100644 crates/blockchain/state_transition/src/beacon/genesis.rs create mode 100644 crates/blockchain/state_transition/src/beacon/hash.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/accessors.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/altair.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/attestation.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/capella.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/electra.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/finality.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/fulu.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/math.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/misc.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/mod.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/mutators.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/predicates.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/shuffling.rs create mode 100644 crates/blockchain/state_transition/src/beacon/helpers/test_state.rs create mode 100644 crates/blockchain/state_transition/src/beacon/kzg.rs create mode 100644 crates/blockchain/state_transition/src/beacon/lean_boundary.rs create mode 100644 crates/blockchain/state_transition/src/beacon/mod.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/altair.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/bellatrix.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/block.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/capella.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/deneb.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/electra.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/epoch/altair.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/epoch/capella.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/epoch/electra.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/epoch/fulu.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/epoch/justification.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/epoch/mod.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/epoch/registry.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/epoch/rewards.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/fulu.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/mod.rs create mode 100644 crates/blockchain/state_transition/src/beacon/stf/operations.rs create mode 100644 crates/blockchain/state_transition/src/beacon/upgrade.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/bls.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/epoch_processing.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/fork.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/fork_choice.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/genesis.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/harness.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/kzg.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/mod.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/operations.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/rewards.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/sanity.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/shuffling.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/ssz_static.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec/transition.rs create mode 100644 crates/blockchain/state_transition/tests/beacon_spec_tests.rs create mode 100644 docs/beacon_stf.md diff --git a/.github/actions/free-disk-space/action.yml b/.github/actions/free-disk-space/action.yml new file mode 100644 index 000000000..c93d5c54b --- /dev/null +++ b/.github/actions/free-disk-space/action.yml @@ -0,0 +1,71 @@ +name: "Free runner disk space" +description: >- + Deletes preinstalled toolchains that nothing in this repository builds + against, so a cold `release-fast` build of the whole workspace has room to + link, and reports free space before and after. Callers must not run + containers: this prunes the runner's preinstalled Docker images. + +runs: + using: "composite" + steps: + # A cold `release-fast` build of this workspace no longer fits the runner's + # root filesystem. Two properties of that failure are worth knowing, because + # neither is visible from the error it produces: + # + # `lld` writes its output through `mmap`, so a full disk reaches it when it + # touches a page it cannot back, as SIGBUS rather than ENOSPC. The build + # reports `ld terminated with signal 7 [Bus error]` and refers the reader to + # the LLVM issue tracker, naming neither the disk nor the linker's output + # file. Whoever next sees that error should check this step's numbers first. + # + # And the runner's own diagnostic log shares the filesystem, so once it is + # full the failure can also land in a post-job step, attributed to whatever + # action happened to be unwinding rather than to the build that filled it. + # + # Hence reporting `df` on both sides even when nothing is short, so the + # headroom a run started with is in its log either way. Callers pair this + # with a reading after the build, which is what says how much of that + # headroom the build then used. + - name: Free disk space + shell: bash + run: | + echo "::group::Disk usage before cleanup" + df -h / + echo "::endgroup::" + + # Removal is best-effort. A path that a future runner image drops or + # relocates is not a reason to fail the job: what actually matters is + # whether the build fits, which the build itself reports. `set -e` is + # deliberately absent for the same reason. + # + # Each entry is a toolchain for a language this repository does not + # build, ordered roughly largest first: + sudo rm -rf \ + /usr/local/lib/android \ + /usr/share/dotnet \ + /usr/local/.ghcup \ + /opt/ghc \ + /usr/share/swift \ + /opt/hostedtoolcache/CodeQL \ + || true + + # CodeQL is named on its own rather than clearing + # `/opt/hostedtoolcache` wholesale, because that directory is also where + # `dtolnay/rust-toolchain` and the `setup-*` actions install what later + # steps in the same job then run. + # + # Node is absent from the list for a similar reason. The runner's own + # bundled copy, which is what every `uses:` action here executes, lives + # elsewhere and would survive, but `/usr/local/lib/node_modules` is + # where npm installs itself, so clearing it would leave a caller that + # runs npm with a working `node` and no `npm`. + + # The preinstalled images, which are only ever a cache for jobs that run + # containers. No caller of this action does; see the description. + if command -v docker >/dev/null 2>&1; then + sudo docker image prune --all --force >/dev/null 2>&1 || true + fi + + echo "::group::Disk usage after cleanup" + df -h / + echo "::endgroup::" diff --git a/.github/actions/run-fixture-tests/action.yml b/.github/actions/run-fixture-tests/action.yml index 5d8c81179..38bf1c47b 100644 --- a/.github/actions/run-fixture-tests/action.yml +++ b/.github/actions/run-fixture-tests/action.yml @@ -112,3 +112,12 @@ runs: - name: Run tests shell: bash run: make test + + # What the build actually consumed, which is the number that says how close + # the next run is to the ceiling; `free-disk-space` reports only what was + # available before it. `always()` because the reading matters most on the + # failure this instruments, where the build is the thing that ran out. + - name: Report disk usage after the build + if: always() + shell: bash + run: df -h / diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 284c982bf..decbfc99e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,16 @@ concurrency: env: CARGO_NET_GIT_FETCH_WITH_CLI: "true" CARGO_NET_RETRY: "10" + # Off in CI, on for local rebuilds, which is what the `release-fast` profile's + # `incremental = true` is for. An environment variable overrides the profile + # setting, so this turns it off here without touching the manifest. + # + # Incremental state is pure cost on a runner: `Swatinem/rust-cache` deletes + # `target/*/incremental` before saving, so it is never restored, and every job + # here starts from whatever the cache holds rather than from its own previous + # build. Nothing reads it, and it is comparable in size to the build output + # itself, on a filesystem that a cold workspace build has already outgrown. + CARGO_INCREMENTAL: "0" jobs: lint: @@ -49,19 +59,43 @@ jobs: - name: Clippy run: cargo clippy --locked --workspace --all-targets -- -D warnings - # The beacon containers' SSZ bounds are const-generic arguments, so the - # minimal preset is a whole second compilation of ethlambda-types that - # nothing above reaches: every step so far builds the default (mainnet) - # preset only. Without this the `preset-minimal` feature would rot between - # merges, and the fixture suites that select it live on another branch. + # Two features gate code that no step above reaches, so both would rot + # silently between merges. # - # `--lib`, because this job downloads no fixtures. The crate's other test - # target, `ssz_spectests`, walks `leanSpec/fixtures` and panics outright - # when it is absent, which only the `test` job below fetches. The unit - # tests are what the preset actually changes, and they read nothing from - # disk. + # `beacon-spec-tests` guards the beacon spec-test target, which declares it + # as a required feature so that `cargo test` skips a suite whose fixtures + # are a multi-gigabyte download. `--all-targets` above therefore never + # builds it. The `beacon-spec-tests` job below does download them and run + # the suite for real, so this step is not what proves the runners work; it + # is here because that job is by far the slowest in the workflow, and + # because this is the only place the runners are linted at `-D warnings`. + # + # `preset-minimal` is a whole second compilation, because the beacon + # containers' SSZ bounds are const-generic arguments and every step so far + # builds the default (mainnet) preset only. The fixture-reading unit tests + # stay `ignore`d here, since `beacon-spec-tests` is off. + # + # `--lib` on both: this job downloads no fixtures, and each crate's + # integration targets (`ssz_spectests`, `stf_spectests`) walk the leanSpec + # tree, which only the `test` job below has. The unit tests are what the + # preset actually changes, and they need nothing on disk. + # + # The spec suite is compiled under BOTH presets, not just the default. Its + # `genesis` runner is `#![cfg(feature = "preset-minimal")]`, because the + # release ships genesis fixtures for that preset only, so a mainnet-preset + # build type-checks every runner except that one, and it is the sole + # coverage `beacon::genesis` has. The minimal leg below would catch a break + # there as well, but only after a fixture download and a full release-fast + # build; this catches it in the lint job's already-warm cache. + - name: Check the beacon spec-test suite compiles + run: | + cargo clippy -p ethlambda-state-transition --all-targets --features beacon-spec-tests -- -D warnings + cargo clippy -p ethlambda-state-transition --all-targets --features beacon-spec-tests,preset-minimal -- -D warnings + - name: Check the minimal preset - run: cargo test -p ethlambda-types --lib --features preset-minimal + run: | + cargo test -p ethlambda-types --lib --features preset-minimal + cargo test -p ethlambda-state-transition --lib --features preset-minimal # tooling/event-monitor declares its own [workspace] table, so every step # above stops at the root workspace members and never reaches it. Its @@ -87,6 +121,12 @@ jobs: steps: - uses: actions/checkout@v6 + # This job builds the entire workspace at `release-fast`, which is the + # largest build in the workflow and no longer fits the runner's root + # filesystem unmodified. + - name: Free disk space + uses: ./.github/actions/free-disk-space + - name: Run fixture-based tests uses: ./.github/actions/run-fixture-tests @@ -135,3 +175,65 @@ jobs: fi done exit $status + beacon-spec-tests: + name: Beacon spec tests (${{ matrix.preset }}) + runs-on: ubuntu-latest + # Far and away the longest job here: two full fixture trees to fetch and a + # release-grade build before the first case runs. Bounded well above what a + # healthy run takes, purely so a hang is reaped in tens of minutes rather + # than sitting on a runner for GitHub's six-hour default. + timeout-minutes: 120 + strategy: + # Report both presets rather than cancelling the second the moment the + # first fails. They walk different fixture trees, and whether a failure is + # preset-specific or common to both is most of the triage. + fail-fast: false + matrix: + preset: [mainnet, minimal] + env: + # Read by the Makefile, which declares this `?=` and so defers to the + # environment. A run reads its own preset's tree plus `general` and nothing + # else, so fetching the other preset's would be the largest single download + # in the workflow spent on files no case opens. + CONSENSUS_SPEC_TESTS_CONFIGS: general ${{ matrix.preset }} + steps: + - uses: actions/checkout@v6 + + # Not yet observed to run out, unlike `test` above, but it is the same + # squeeze: a release-grade build plus the largest fixture download in the + # workflow, on the same root filesystem. + - name: Free disk space + uses: ./.github/actions/free-disk-space + + - name: Setup Rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: "1.97.1" + + # Keyed per preset. The preset fixes the beacon containers' SSZ bounds, + # which are const-generic arguments, so the two legs share no artifacts at + # all; on one key they would evict each other on every single run. + - name: Setup cache + uses: Swatinem/rust-cache@v2 + with: + key: beacon-${{ matrix.preset }} + + # Deliberately not cached. The trees expand to several GiB, which against a + # repository-wide 10 GiB cache budget would evict the Rust build caches + # that actually save time here. The assets are pinned to a release and + # served from the same CDN as the runner, so re-fetching is the cheap half + # of that trade. + # + # Its own step rather than leaning on the make prerequisite, so the log + # separates download time from build-and-test time and a fixture outage is + # not reported as a test failure. + - name: Download the consensus spec test fixtures + run: make consensus-spec-tests + + - name: Run the Beacon Chain spec tests + run: make test-beacon-${{ matrix.preset }} + + # See the same step in the run-fixture-tests action. + - name: Report disk usage after the build + if: always() + run: df -h / diff --git a/.github/workflows/daily_ci.yml b/.github/workflows/daily_ci.yml index db1034ae0..61fb24ef0 100644 --- a/.github/workflows/daily_ci.yml +++ b/.github/workflows/daily_ci.yml @@ -26,6 +26,9 @@ permissions: env: CARGO_NET_GIT_FETCH_WITH_CLI: "true" CARGO_NET_RETRY: "10" + # See the same setting in ci.yml. This workflow runs the identical job, so it + # is under the identical disk pressure. + CARGO_INCREMENTAL: "0" jobs: test: @@ -34,6 +37,9 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Free disk space + uses: ./.github/actions/free-disk-space + - name: Run fixture-based tests uses: ./.github/actions/run-fixture-tests diff --git a/.gitignore b/.gitignore index d8ed6cf6f..46c51b320 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,9 @@ target # Used for generating test vectors /leanSpec +# Beacon Chain spec test fixtures, downloaded by `make consensus-spec-tests` +/consensus-spec-tests + # Personal Claude Code overrides (not shared with team) CLAUDE.local.md diff --git a/CLAUDE.md b/CLAUDE.md index c77c9793b..e85c2c8bd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -362,6 +362,92 @@ existing once per chain. consensus-specs v1.6.1 (5705 mainnet / 40009 minimal cases). What runs here is the containers' own round-trip and shape tests. +## Beacon Chain STF (`crates/blockchain/state_transition/src/beacon/`) + +The **Ethereum Beacon Chain** consensus specs (phase0 through fulu), a different +protocol from the Lean consensus the rest of this repo implements, live in the +`beacon` module of `ethlambda-state-transition` beside lean's own state +transition. The module holds the *behavior* (state transition, fork choice, +helpers, BLS and KZG); the containers, presets, configuration and primitives it +transitions are in `ethlambda-types`, per the section above. Nothing above +`beacon` reads anything inside it, and nothing inside it reads lean's modules. + +- **`blst` and `c-kzg` are now on the lean binary's dependency path**, since + `ethlambda-blockchain`, `ethlambda-rpc` and `ethlambda-test-fixtures` all + depend on this crate. That is the cost of one crate holding both chains' + rules; the module is not feature-gated. +- Tests: `make test-beacon` (builds once per preset), or `test-beacon-mainnet` / + `test-beacon-minimal` for one. CI runs the two as a job each, so they build and + run concurrently. `make test` runs the whole + workspace with nothing excluded, and still needs no fixture download: the + `beacon_spec_tests` target declares `required-features = ["beacon-spec-tests"]` + so `cargo test` skips it, and the BLS and KZG fixture vectors, which are unit + tests inside the module, are `#[cfg_attr(not(feature = ...), ignore)]` so they + report as ignored rather than silently absent. Turning the feature on is what + `make test-beacon` does, and it runs `--lib` too so those 15 are not missed. +- Every fixture case is its own test, named `////`, + so a failure names the case and not the suite around it. The spec binary + therefore supplies its own harness (`harness = false`), since a case is only + known once the fixture tree is walked. A substring filter selects a whole + suite or one case: `cargo test -p ethlambda-state-transition --test + beacon_spec_tests --features beacon-spec-tests -- electra/attester_slashing`. +- Fixtures: `make consensus-spec-tests`, pinned to a `consensus-specs` release. + The tree is stamped with the version *and* the configs it holds, so changing + either wipes and re-downloads rather than leaving the old cases in place and + silently green, or marking a partial tree complete. + `CONSENSUS_SPEC_TESTS_CONFIGS` narrows the download: a run reads its own + preset's tree plus `general` and nothing else, which is what each CI job sets. +- Preset is a **compile-time** choice (`preset-minimal` feature) because SSZ + container bounds are const-generic arguments; fork scheduling is runtime + because the `transition` suite moves fork epochs per case. +- Per-fork containers are plain structs behind an enum, so SSZ stays derived. See + [`docs/beacon_stf.md`](docs/beacon_stf.md) for why, including the fork-by-fork + field counts and the merkle depth change at electra. +- The types are re-exported at their old paths (`crate::beacon::containers`, + `crate::beacon::preset`, `crate::beacon::config`, ...), so a use site inside + the module reads as if they were local, and + `ethlambda_state_transition::beacon::containers::X` and + `ethlambda_types::beacon::containers::X` name one type. Two things do move the + other way: `fork_choice` re-exports `LatestMessage` and `PowBlock` from types + (`ethlambda-storage` persists them), and `helpers::misc` re-exports + `compute_fork_data_root` (the networking crate needs the fork digest built on + it). +- **`BeaconState` and `ForkName` carry a `Lean` variant**, so every match on + either needs an arm for it. Nothing here can transition a lean value, so those + arms panic through `lean_state_unreachable`/`lean_fork_unreachable` + (`src/beacon/lean_boundary.rs`, same names and wording as `ethlambda-types`' + own `pub(crate)` pair) rather than widening a signature to a `Result` no + correct caller would see. Functions, not a macro, and `#[cold]` + + `#[track_caller]` so the panic still reports the arm that was reached rather + than `lean_boundary.rs`. In the spec tests the same arms call + `lean_is_not_a_fixture_fork`, which is `#[track_caller]` for the same reason, + since a case's fork is parsed from a directory name and `ForkName::ALL` has no + lean entry. Both are named arms rather than a + catch-all `_`, so a real new fork still breaks every match that must grow one. +- **Needs mutable element access on `SszList`/`SszVector`**, which no published + libssz release has yet. Nothing extra is required here: the workspace already + tracks all four libssz crates from git at `36802dd` for the beacon containers + in `ethlambda-types` (see the section above), and that rev is the `0.3.0` + release plus the single commit adding `DerefMut`/`IndexMut` + (lambdaclass/libssz#33). This module needs that commit for the same reason. +- **Status:** all seven forks (phase0 through fulu) have containers, fork + upgrades, state transitions, and epoch processing. Every fixture case passes + on both presets: mainnet is 5705 cases and minimal 40009. The crate's lib + target holds 200 tests with `beacon-spec-tests` on, 185 plus 15 ignored + without; both figures cover lean's own unit tests as well, since the two + chains now share one lib target. Fork choice is fixture-verified too: 150 mainnet + `fork_choice` cases pass, covering bellatrix's `on_merge_block`/terminal-PoW + validation, `should_override_forkchoice_update`, deneb's blob data + availability, and fulu's column data availability. +- Nothing is ignored for being unimplemented. Ignored cases are the + `LightClient*` containers (a different layer, out of scope) and the `gloas` + and `eip7805` fixture trees. Those two do not parse as a `ForkName`, so + `collect` would skip them silently; `UNMODELED_FORKS` names them and + `fixture_forks/every_directory_is_accounted_for` fails on any fork directory + that is neither parseable nor listed, so a new fork forces a decision. +- A fixture case with no `post` state asserts the input must be **rejected**. That + rule lives in `check_transition`; do not add a runner that ignores it. + ## Configuration Files **Genesis:** `config.yaml` (YAML format, cross-client compatible) diff --git a/Cargo.lock b/Cargo.lock index ddf3abc70..d2448c331 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -730,7 +730,7 @@ dependencies = [ "bitflags", "cexpr", "clang-sys", - "itertools 0.10.5", + "itertools 0.13.0", "proc-macro2", "quote", "regex", @@ -1492,7 +1492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090" dependencies = [ "data-encoding", - "syn 1.0.109", + "syn 2.0.117", ] [[package]] @@ -2066,14 +2066,24 @@ dependencies = [ name = "ethlambda-state-transition" version = "0.1.0" dependencies = [ + "blst", + "c-kzg", "datatest-stable", "ethlambda-metrics", "ethlambda-test-fixtures", "ethlambda-types", "hex", + "libssz 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-derive 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libssz-merkle 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "libssz-types 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", + "libtest-mimic", + "num-bigint", "serde", "serde_json", + "serde_yaml_ng", + "sha2", + "snap", "thiserror 2.0.18", "tracing", ] @@ -5871,7 +5881,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.117", diff --git a/Makefile b/Makefile index a78362871..f3419943a 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help fmt lint bench update cooldown-check docker-build shadow-build shadow-docker-build run-devnet test docs docs-deps docs-serve +.PHONY: help fmt lint bench update cooldown-check docker-build shadow-build shadow-docker-build run-devnet test test-beacon test-beacon-mainnet test-beacon-minimal consensus-spec-tests docs docs-deps docs-serve help: ## 📚 Show help for each of the Makefile recipes @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' @@ -12,8 +12,31 @@ lint: ## 🔍 Run clippy on all workspace crates test: leanSpec/fixtures ## 🧪 Run all tests # release-fast: release-grade opt-level to avoid stack overflows during # signature verification/aggregation, without paying for LTO on every rebuild + # + # The Beacon Chain spec tests have their own target and are not run here: + # their fixtures are a separate multi-gigabyte download, and the suite has to + # be built once per preset. Nothing is excluded to achieve that any more, now + # that they live in ethlambda-state-transition beside lean's own; their test + # target requires the `beacon-spec-tests` feature, so this command skips it. cargo test --locked --workspace --profile release-fast +# --lib as well as the spec target: the BLS and KZG modules keep their fixture +# vectors as unit tests, which are `ignore`d unless this feature is on. +BEACON_TEST=cargo test -p ethlambda-state-transition --lib --test beacon_spec_tests --profile release-fast + +# The preset fixes SSZ container bounds at compile time, so each preset needs its +# own build, and a run walks its own fixture tree plus `general` and nothing else. +# Hence a target per preset rather than one recipe running both: CI gives each its +# own job, so the two build and run concurrently and each downloads only the trees +# its preset reads. +test-beacon: test-beacon-mainnet test-beacon-minimal ## 🧪 Run the Beacon Chain spec tests, both presets + +test-beacon-mainnet: consensus-spec-tests ## 🧪 Run the Beacon Chain spec tests, mainnet preset + $(BEACON_TEST) --features beacon-spec-tests + +test-beacon-minimal: consensus-spec-tests ## 🧪 Run the Beacon Chain spec tests, minimal preset + $(BEACON_TEST) --features beacon-spec-tests,preset-minimal + # Used ONLY to resolve dependency updates: min-publish-age (.cargo/config.toml) # is nightly-only, everything else runs on the stable toolchain pinned in # rust-toolchain.toml. @@ -92,6 +115,58 @@ leanSpec/fixtures: mkdir -p leanSpec/fixtures; \ tar -xzf "$$tmpdir/fixtures-prod-scheme.tar.gz" -C leanSpec/fixtures --strip-components=1 +# Beacon Chain spec test fixtures, for the `beacon` module of +# crates/blockchain/state_transition. +# +# Pinned rather than tracking the latest release: this fixture tree *is* the +# definition of correctness for that module, so it should move only when we choose +# to move it. The release publishes no checksums for these assets, so unlike the +# leanSpec bundle below there is nothing to verify against. +CONSENSUS_SPEC_TESTS_VERSION ?= v1.6.1 +CONSENSUS_SPEC_TESTS_BASE_URL ?= https://github.com/ethereum/consensus-specs/releases/download/$(CONSENSUS_SPEC_TESTS_VERSION) + +# Which fixture trees to fetch. A run reads its own preset's tree plus `general`, +# the preset-independent BLS and KZG vectors, and nothing else, so a CI job pinned +# to one preset narrows this and skips the other preset's tree. That is worth +# doing: the three together are ~1.25 GiB compressed and several times that on +# disk, against a runner that has neither the space nor the time to spare. +CONSENSUS_SPEC_TESTS_CONFIGS ?= general minimal mainnet + +# The stamp is named after the version AND the configs, so changing either names +# a file that does not exist and forces a fresh download. Depending on the +# extracted directories instead would make a bump a silent no-op: they already +# exist, make would consider them up to date, and the suite would go green +# against the old tree while the docs claimed the new version. Nothing in the +# fixtures themselves records which release they came from, so the stamp is the +# only thing that can carry it. +# +# The configs belong in the name for the same reason: the recipe wipes the tree +# before extracting, so a narrowed run leaves the other preset's tree gone, and a +# stamp naming only the version would then mark a partial tree as complete. +# `sort` normalises order and duplicates, so the same set always names one stamp. +empty:= +space:=$(empty) $(empty) +CONSENSUS_SPEC_TESTS_STAMP=consensus-spec-tests/.version-$(CONSENSUS_SPEC_TESTS_VERSION)-$(subst $(space),-,$(sort $(CONSENSUS_SPEC_TESTS_CONFIGS))) + +consensus-spec-tests: $(CONSENSUS_SPEC_TESTS_STAMP) ## ⬇️ Download the Beacon Chain spec test fixtures + +# The old tree goes first, rather than being extracted over: every tarball +# unpacks to `tests//...`, so all three land side by side in one directory, +# and unpacking a new version on top of an old one would merge the two, leaving +# cases a release deleted still present and still passing. +$(CONSENSUS_SPEC_TESTS_STAMP): + @rm -rf consensus-spec-tests + @mkdir -p consensus-spec-tests + @for config in $(CONSENSUS_SPEC_TESTS_CONFIGS); do \ + echo "Downloading $$config spec test fixtures ($(CONSENSUS_SPEC_TESTS_VERSION))"; \ + tmpdir=$$(mktemp -d); \ + trap 'rm -rf "$$tmpdir"' EXIT; \ + curl -L -f -o "$$tmpdir/$$config.tar.gz" "$(CONSENSUS_SPEC_TESTS_BASE_URL)/$$config.tar.gz" || exit 1; \ + tar -xzf "$$tmpdir/$$config.tar.gz" -C consensus-spec-tests || exit 1; \ + rm -rf "$$tmpdir"; \ + done + @touch $@ + lean-quickstart: git clone https://github.com/blockblaz/lean-quickstart.git --depth 1 --single-branch diff --git a/crates/blockchain/state_transition/Cargo.toml b/crates/blockchain/state_transition/Cargo.toml index dc26096eb..9921c0ce7 100644 --- a/crates/blockchain/state_transition/Cargo.toml +++ b/crates/blockchain/state_transition/Cargo.toml @@ -9,6 +9,26 @@ repository.workspace = true rust-version.workspace = true version.workspace = true +[features] +# Compile the Beacon Chain half against the minimal preset instead of mainnet. +# +# Container shapes are compile-time constants (SSZ list and vector bounds), so +# the preset cannot be selected at runtime. Mainnet is the implicit default; +# enabling this feature switches every beacon constant to the minimal preset. +# The beacon spec-test target builds the crate twice, once per preset, and each +# build walks only its own fixture tree. Lean's own state transition reads none +# of these constants, so the feature cannot change lean behavior. +preset-minimal = ["ethlambda-types/preset-minimal"] + +# Builds the beacon spec-test target. Off by default, and it gates only that +# target: the `beacon` module itself always compiles. What it stands for is the +# fixture tree, a multi-gigabyte download the lean workflow has no use for, and +# `beacon_spec::fixture_root` deliberately panics rather than reporting a green +# suite that found nothing to run. So `cargo test --workspace` skips the target +# instead of failing on the missing directory; `make test-beacon` turns it on +# after downloading the fixtures. +beacon-spec-tests = [] + [dependencies] ethlambda-types.workspace = true ethlambda-metrics.workspace = true @@ -16,17 +36,66 @@ ethlambda-metrics.workspace = true thiserror.workspace = true tracing.workspace = true +# -- The `beacon` module's own dependencies --------------------------------- + +hex.workspace = true + +# For `beacon::genesis`, which fills in an `SszList` of validators. The beacon +# containers and their derives live in `ethlambda-types`, so the encoder, the +# derive macros and the merkleizer are reached through them rather than named +# here; the spec-test harness declares its own for the containers it defines. +libssz-types.workspace = true + +# For `beacon::hash::hash`, that module's one SHA-256 entry point. The workspace +# pins the `asm` feature; see the root manifest for what it buys and why +# merkleization cares. `libssz-merkle` depends on `sha2` too and asks for no +# features of its own, and Cargo unifies features across a version, so its copy +# gets the same. +sha2.workspace = true + +# BLS12-381. Assembly-optimized, and the canonical consensus-layer backend. +blst = "0.3.16" + +# KZG, including the EIP-7594 cell and column proofs that fulu needs. Same +# version and feature set ethrex uses, plus the embedded mainnet trusted setup. +c-kzg = { version = "2.1.8", features = ["ethereum_kzg_settings"] } + +# Reduction modulo the BLS field order, for the two Fiat-Shamir challenge +# functions that c-kzg does not export. +num-bigint = "0.4.6" + [dev-dependencies] ethlambda-test-fixtures.workspace = true serde.workspace = true serde_json.workspace = true +serde_yaml_ng.workspace = true hex.workspace = true libssz-types.workspace = true +# The beacon spec-test harness defines its own containers for the fixture-only +# shapes (`meta.yaml` payloads, the rewards suite's delta files), so it needs the +# encoder, the derives and the merkleizer the derives expand into. +libssz.workspace = true +libssz-derive.workspace = true +libssz-merkle.workspace = true +snap = "1.1.1" + datatest-stable = "0.3.3" +# Supplies the beacon spec-test binary's harness. A fixture case is only known +# once the fixture tree is walked, which `#[test]` cannot express, so the tests +# are built at run time instead. See `tests/beacon_spec_tests.rs` for the full +# reasoning. +libtest-mimic = "0.8.2" + [[test]] name = "stf_spectests" path = "tests/stf_spectests.rs" harness = false + +[[test]] +name = "beacon_spec_tests" +path = "tests/beacon_spec_tests.rs" +harness = false +required-features = ["beacon-spec-tests"] diff --git a/crates/blockchain/state_transition/src/beacon/bls.rs b/crates/blockchain/state_transition/src/beacon/bls.rs new file mode 100644 index 000000000..ef3475a15 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/bls.rs @@ -0,0 +1,433 @@ +//! The specification's `bls` module: `bls.Verify`, `bls.Aggregate`, and friends. +//! +//! The state transition never touches `blst` directly; it calls the functions +//! here, named exactly as the spec names them (`specs/phase0/beacon-chain.md`'s +//! "BLS signatures" section, extended by `specs/altair/bls.md`), so a reader can +//! match a call site against the spec line by line. `blst` is the only backend: +//! there is no trait to abstract over another one, since the consensus layer has +//! settled on `blst` as the reference implementation and a second backend would +//! only be dead code here. +//! +//! # Why every function treats its inputs as unvalidated +//! +//! [`crate::beacon::primitives::BlsPubkey`] is deliberately *not* validated on +//! construction: deposit processing has to be able to hold a public key that +//! never validates, because a deposit with a bad key is still a real message +//! that changes the state (it is simply never able to sign anything). Nothing +//! upstream of this module guarantees a `BlsPubkey` or `BlsSignature` is a valid, +//! subgroup-correct curve point, so every function below re-derives that from +//! the raw bytes on every call rather than assuming it. That costs an extra +//! point check per input compared to a backend that validates once at +//! deserialization time and trusts a typed wrapper afterward (the approach +//! Lighthouse's `blst` backend takes, and the approach `blst`'s own +//! `fast_aggregate_verify` helper assumes when it hardcodes its public-key +//! validation flag to skip the check). Here, skipping it would mean a garbage +//! or adversarial byte string could reach a pairing check unchecked. +//! +//! # `bool` versus `Result` +//! +//! The verification functions ([`verify`], [`aggregate_verify`], +//! [`fast_aggregate_verify`], [`eth_fast_aggregate_verify`], [`key_validate`]) +//! return `bool`, matching the spec's own signatures (`bls.Verify(...) -> bool` +//! and so on): they are predicates, and a `false` covers every way a claim can +//! fail to hold, whether the signature does not match, the public key does not +//! decode, or a point is not subgroup-correct. The specification does not +//! distinguish "the key was gibberish" from "the key was valid but the +//! signature was wrong": both mean the check did not pass, so collapsing them +//! into one boolean is what lets a caller use the result directly as a gate +//! (`if !bls::verify(...) { return }`) instead of first deciding which `Err` +//! variants count as "reject" and which count as a bug worth propagating. +//! +//! The aggregation functions ([`aggregate`], [`eth_aggregate_pubkeys`]) return +//! [`crate::beacon::Result`] instead, because there is no boolean predicate to collapse +//! to: aggregation either produces a point or it structurally cannot (an empty +//! input, or an element that is not itself a valid point), and that is a +//! different kind of failure than "verification did not pass". Keeping it a +//! `Result` keeps that distinction visible at the call site instead of forcing +//! an aggregation failure to masquerade as a rejected signature. + +use blst::BLST_ERROR; +use blst::min_pk::{AggregatePublicKey, AggregateSignature, PublicKey, Signature}; + +use crate::beacon::error::Error; +use crate::beacon::primitives::{BLS_SIGNATURE_SIZE, BlsPubkey, BlsSignature, Root}; + +/// The ciphersuite the specification pins BLS signatures to: the IETF BLS +/// draft's proof-of-possession scheme over BLS12-381's G2, using SHA-256 in +/// the XMD hash-to-curve construction. +/// +/// This is the domain separation tag threaded through every hash-to-curve call +/// in this module. Two signatures produced under different DSTs never verify +/// against each other, which is exactly the point: it is what lets the same +/// keys be reused for other purposes (or other chains) without cross-protocol +/// signature reuse. +const DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; + +/// Builds `specs/altair/bls.md`'s `G2_POINT_AT_INFINITY` constant: the +/// compressed encoding of the identity element of G2, which is the +/// specification's sentinel value for "no one signed anything". +/// +/// A `const fn` rather than a byte literal so the encoding rule (the +/// compression flag and infinity flag bits set, every other bit zero) reads as +/// what it is instead of as a string of hex digits to take on faith. +const fn g2_point_at_infinity() -> [u8; BLS_SIGNATURE_SIZE] { + let mut bytes = [0u8; BLS_SIGNATURE_SIZE]; + // The top two bits of the first byte are the compression flag and the + // infinity flag; setting both and leaving every other bit zero is exactly + // the encoding of the point at infinity, compressed. + bytes[0] = 0b1100_0000; + bytes +} + +/// `specs/altair/bls.md`'s `G2_POINT_AT_INFINITY`, the compressed encoding of +/// the identity element of G2. +const G2_POINT_AT_INFINITY: [u8; BLS_SIGNATURE_SIZE] = g2_point_at_infinity(); + +/// The specification's `bls.Verify(pubkey, message, signature) -> bool`. +/// +/// Deserializes and fully validates both inputs (subgroup membership for the +/// signature, subgroup membership and non-identity for the public key) before +/// checking the pairing equation, so a `pubkey` that never passed +/// [`key_validate`] and never will (see the module documentation) simply fails +/// here rather than panicking or returning an error: an unparseable or +/// invalid-point key is treated exactly like a valid key over the wrong +/// signature, since the specification never distinguishes the two. +pub fn verify(pubkey: &BlsPubkey, message: Root, signature: &BlsSignature) -> bool { + let Ok(pubkey) = PublicKey::key_validate(pubkey.as_ref()) else { + return false; + }; + let Ok(signature) = Signature::sig_validate(signature.as_ref(), false) else { + return false; + }; + let result = signature.verify(false, message.as_slice(), DST, &[], &pubkey, false); + result == BLST_ERROR::BLST_SUCCESS +} + +/// The specification's `bls.Aggregate(signatures) -> BLSSignature`. +/// +/// Fails on an empty `signatures`, matching the spec's `Aggregate` (there is no +/// meaningful signature aggregating zero signatures), and fails if any element +/// does not deserialize to a subgroup-correct point in G2. Checking every +/// element here, rather than only the final sum, matters because elliptic +/// curve addition of two points outside the prime-order subgroup can still +/// land back inside it: an invalid share could otherwise cancel against +/// another invalid share and slip past a check performed only on the result. +pub fn aggregate(signatures: &[BlsSignature]) -> crate::beacon::Result { + crate::beacon::verify(!signatures.is_empty(), "len(signatures) > 0")?; + let encoded: Vec<&[u8]> = signatures + .iter() + .map(|signature| signature.as_ref()) + .collect(); + let aggregated = AggregateSignature::aggregate_serialized(&encoded, true) + .map_err(|_| Error::InvalidSignature("aggregate: not a valid, subgroup-correct point"))?; + Ok(BlsSignature(aggregated.to_signature().to_bytes())) +} + +/// The specification's +/// `bls.AggregateVerify(pubkeys, messages, signature) -> bool`. +/// +/// `pubkeys` and `messages` are matched up positionally, one message per +/// signer; an empty `pubkeys`, or a length mismatch between the two, fails +/// immediately rather than vacuously succeeding. As with [`verify`], every +/// public key and the signature are independently deserialized and validated +/// (subgroup membership, non-identity for the keys) before the pairing check +/// runs, so an invalid key or signature simply fails this predicate. +pub fn aggregate_verify( + pubkeys: &[BlsPubkey], + messages: &[Root], + signature: &BlsSignature, +) -> bool { + if pubkeys.is_empty() || pubkeys.len() != messages.len() { + return false; + } + let Ok(signature) = Signature::sig_validate(signature.as_ref(), false) else { + return false; + }; + let mut points = Vec::with_capacity(pubkeys.len()); + for pubkey in pubkeys { + match PublicKey::key_validate(pubkey.as_ref()) { + Ok(point) => points.push(point), + Err(_) => return false, + } + } + let point_refs: Vec<&PublicKey> = points.iter().collect(); + let message_refs: Vec<&[u8]> = messages.iter().map(Root::as_slice).collect(); + let result = signature.aggregate_verify(false, &message_refs, DST, &point_refs, false); + result == BLST_ERROR::BLST_SUCCESS +} + +/// The specification's +/// `bls.FastAggregateVerify(pubkeys, message, signature) -> bool`. +/// +/// The same check as [`aggregate_verify`] specialized to one shared `message`, +/// which is the shape every attestation aggregate takes. An empty `pubkeys` +/// always fails here: this function has no notion of "no one signed, and that +/// is fine", unlike its eth2-specific wrapper [`eth_fast_aggregate_verify`], +/// which is exactly why that wrapper exists. +pub fn fast_aggregate_verify( + pubkeys: &[BlsPubkey], + message: Root, + signature: &BlsSignature, +) -> bool { + if pubkeys.is_empty() { + return false; + } + let Ok(signature) = Signature::sig_validate(signature.as_ref(), false) else { + return false; + }; + let mut points = Vec::with_capacity(pubkeys.len()); + for pubkey in pubkeys { + match PublicKey::key_validate(pubkey.as_ref()) { + Ok(point) => points.push(point), + Err(_) => return false, + } + } + let point_refs: Vec<&PublicKey> = points.iter().collect(); + let result = signature.fast_aggregate_verify(false, message.as_slice(), DST, &point_refs); + result == BLST_ERROR::BLST_SUCCESS +} + +/// `specs/altair/bls.md`'s `eth_aggregate_pubkeys(pubkeys) -> BLSPubkey`. +/// +/// Follows the spec's own pseudocode: `assert len(pubkeys) > 0`, then +/// `assert all(bls.KeyValidate(pubkey) for pubkey in pubkeys)` before summing. +/// The `KeyValidate` step is not optional the way it might look from the name: +/// without it, an all-zero or otherwise invalid `pubkey` would silently +/// contribute nothing (or something unintended) to the sum instead of failing +/// the aggregation outright, which is why this returns [`crate::beacon::Result`] rather +/// than substituting a default. +pub fn eth_aggregate_pubkeys(pubkeys: &[BlsPubkey]) -> crate::beacon::Result { + crate::beacon::verify(!pubkeys.is_empty(), "len(pubkeys) > 0")?; + let encoded: Vec<&[u8]> = pubkeys.iter().map(|pubkey| pubkey.as_ref()).collect(); + let aggregated = AggregatePublicKey::aggregate_serialized(&encoded, true) + .map_err(|_| Error::SpecAssert("all(bls.KeyValidate(pubkey) for pubkey in pubkeys)"))?; + Ok(BlsPubkey(aggregated.to_public_key().to_bytes())) +} + +/// `specs/altair/bls.md`'s +/// `eth_fast_aggregate_verify(pubkeys, message, signature) -> bool`. +/// +/// Identical to [`fast_aggregate_verify`] except for one case: an empty +/// `pubkeys` returns `true` exactly when `signature` is +/// [`G2_POINT_AT_INFINITY`], and `false` for every other signature in that +/// case. This carve-out exists because an +/// empty-committee attestation aggregate is a legitimate value on chain (no +/// validators were assigned, or none of them attested), and its signature is +/// the identity element by convention rather than "no signature was +/// provided"; [`fast_aggregate_verify`] itself has no such case, since the +/// underlying IETF ciphersuite it wraps was never given one. +pub fn eth_fast_aggregate_verify( + pubkeys: &[BlsPubkey], + message: Root, + signature: &BlsSignature, +) -> bool { + if pubkeys.is_empty() { + return signature.as_ref() == G2_POINT_AT_INFINITY; + } + fast_aggregate_verify(pubkeys, message, signature) +} + +/// The specification's `bls.KeyValidate(pubkey) -> bool`. +/// +/// A `pubkey` passes when it deserializes to a point on the curve, that point +/// is in the correct prime-order subgroup, and it is not the identity element. +/// Exposed standalone because the spec calls `KeyValidate` directly in more +/// than one place (deposit processing, [`eth_aggregate_pubkeys`]'s own +/// assertion), not only as a step inside a signature check. +pub fn key_validate(pubkey: &BlsPubkey) -> bool { + PublicKey::key_validate(pubkey.as_ref()).is_ok() +} + +#[cfg(test)] +mod tests { + use std::fs; + use std::path::{Path, PathBuf}; + + use serde::Deserialize; + + use super::*; + + /// The root the two BLS handlers this module tests live under. + /// + /// BLS test vectors are configuration-independent (they do not touch any + /// preset constant), so they live under `general` rather than under a + /// preset name; see `crates/blockchain/state_transition/tests/beacon_spec/mod.rs` for the layout the + /// rest of the crate's spec tests share. This module keeps its own tiny, + /// local copy of just enough of that layout to run these two suites, + /// rather than depending on that harness. + fn handler_root(handler: &str) -> PathBuf { + let root = Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../../../consensus-spec-tests/tests/general/altair/bls") + .join(handler); + assert!( + root.is_dir(), + "BLS spec fixtures are missing from {}; run `make consensus-spec-tests`", + root.display() + ); + root + } + + /// Every case's `data.yaml` under a handler: one directory level for the + /// handler's suite (named `bls` in every release seen so far), one for the + /// case itself. + fn fixture_cases(handler: &str) -> Vec { + let mut cases = Vec::new(); + for suite in fs::read_dir(handler_root(handler)).unwrap() { + let suite_path = suite.unwrap().path(); + if !suite_path.is_dir() { + continue; + } + for case in fs::read_dir(&suite_path).unwrap() { + let case_path = case.unwrap().path(); + let data = case_path.join("data.yaml"); + if data.is_file() { + cases.push(data); + } + } + } + cases + } + + /// Decodes a `0x`-prefixed hex string into a fixed-size array, panicking + /// with the offending file's path on any mismatch. A malformed fixture is a + /// bug in the fixture release, not a condition the functions under test + /// need to handle, so this does not return a `Result`. + fn parse_hex(path: &Path, value: &str) -> [u8; N] { + let digits = value.strip_prefix("0x").unwrap_or(value); + let bytes = hex::decode(digits) + .unwrap_or_else(|err| panic!("{}: invalid hex: {err}", path.display())); + bytes.try_into().unwrap_or_else(|bytes: Vec| { + panic!( + "{}: expected {N} bytes, got {}", + path.display(), + bytes.len() + ) + }) + } + + #[derive(Deserialize)] + struct EthAggregatePubkeysCase { + input: Vec, + output: Option, + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn eth_aggregate_pubkeys_matches_spec_fixtures() { + let mut executed = 0; + for path in fixture_cases("eth_aggregate_pubkeys") { + let text = + fs::read_to_string(&path).unwrap_or_else(|err| panic!("{}: {err}", path.display())); + let case: EthAggregatePubkeysCase = serde_yaml_ng::from_str(&text) + .unwrap_or_else(|err| panic!("{}: {err}", path.display())); + + let pubkeys: Vec = case + .input + .iter() + .map(|hex| BlsPubkey(parse_hex(&path, hex))) + .collect(); + let result = eth_aggregate_pubkeys(&pubkeys); + + match case.output { + Some(expected_hex) => { + let expected = BlsPubkey(parse_hex(&path, &expected_hex)); + let actual = result + .unwrap_or_else(|err| panic!("{}: expected Ok, got {err}", path.display())); + assert_eq!(actual.0, expected.0, "{}", path.display()); + } + None => { + assert!( + result.is_err(), + "{}: expected an error, got {result:?}", + path.display() + ); + } + } + executed += 1; + } + println!("eth_aggregate_pubkeys: {executed} cases executed"); + assert!(executed > 0, "no eth_aggregate_pubkeys cases were executed"); + } + + #[derive(Deserialize)] + struct EthFastAggregateVerifyInput { + pubkeys: Vec, + message: String, + signature: String, + } + + #[derive(Deserialize)] + struct EthFastAggregateVerifyCase { + input: EthFastAggregateVerifyInput, + output: bool, + } + + /// Parses one `eth_fast_aggregate_verify` case's `data.yaml` into the + /// crate's own BLS types. + fn parse_fast_aggregate_verify_case(path: &Path) -> (Vec, Root, BlsSignature, bool) { + let text = + fs::read_to_string(path).unwrap_or_else(|err| panic!("{}: {err}", path.display())); + let case: EthFastAggregateVerifyCase = serde_yaml_ng::from_str(&text) + .unwrap_or_else(|err| panic!("{}: {err}", path.display())); + + let pubkeys: Vec = case + .input + .pubkeys + .iter() + .map(|hex| BlsPubkey(parse_hex(path, hex))) + .collect(); + let message = crate::beacon::primitives::H256(parse_hex(path, &case.input.message)); + let signature = BlsSignature(parse_hex(path, &case.input.signature)); + (pubkeys, message, signature, case.output) + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn eth_fast_aggregate_verify_matches_spec_fixtures() { + let mut executed = 0; + for path in fixture_cases("eth_fast_aggregate_verify") { + let (pubkeys, message, signature, expected) = parse_fast_aggregate_verify_case(&path); + let actual = eth_fast_aggregate_verify(&pubkeys, message, &signature); + assert_eq!(actual, expected, "{}", path.display()); + executed += 1; + } + println!("eth_fast_aggregate_verify: {executed} cases executed"); + assert!( + executed > 0, + "no eth_fast_aggregate_verify cases were executed" + ); + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn verify_accepts_a_known_good_vector_from_the_fixtures() { + // `eth_fast_aggregate_verify_valid_0` has exactly one signer. A + // FastAggregateVerify over a single signer is mathematically the same + // check as a plain Verify, so this fixture vector doubles as a + // known-good input for `verify` without this module needing its own + // signing function to produce one. + let path = handler_root("eth_fast_aggregate_verify") + .join("bls") + .join("eth_fast_aggregate_verify_valid_0") + .join("data.yaml"); + let (pubkeys, message, signature, expected) = parse_fast_aggregate_verify_case(&path); + assert_eq!(pubkeys.len(), 1, "fixture assumption: a single signer"); + assert!(expected, "fixture assumption: a valid signature"); + + assert!(verify(&pubkeys[0], message, &signature)); + } + + #[test] + fn key_validate_rejects_the_all_zero_pubkey() { + assert!(!key_validate(&BlsPubkey::default())); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/fork_choice.rs b/crates/blockchain/state_transition/src/beacon/fork_choice.rs new file mode 100644 index 000000000..b007c2702 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/fork_choice.rs @@ -0,0 +1,2028 @@ +//! The fork choice store: LMD GHOST, with FFG-derived justification and +//! finalization gating which branches are even eligible to be head. +//! +//! Implements `specs/phase0/fork-choice.md`, which is also every later fork's +//! fork choice through at least altair: none of them change anything here. +//! `Store` therefore accepts a block from any fork this module implements (see +//! [`Store::blocks`]), even though the algorithm applied to it is +//! unconditionally phase0's. `Store` tracks the block tree, +//! attester votes, and the checkpoints fork choice reasons about; the four +//! handlers at the bottom of this file ([`on_tick`], [`on_block`], +//! [`on_attestation`], [`on_attester_slashing`]) are the only supported ways to +//! change it, matching the specification's own framing: "Invalid calls to +//! handlers must not modify `store`." Accordingly, every helper here takes +//! `&Store`, and only a handler takes `&mut Store`. +//! +//! # Units: one seconds-granularity clock, read out in milliseconds at the edges +//! +//! `Store.time` and `Store.genesis_time` are Unix seconds, exactly like +//! `BeaconState.genesis_time`: both [`on_tick`] and [`on_tick_per_slot`] take a +//! `time: u64` in seconds, and every slot computation on the store +//! (`get_slots_since_genesis`, `get_current_slot`) divides a seconds +//! difference by `Config::seconds_per_slot`. There is no separate +//! millisecond-granularity clock in `Store` itself. +//! +//! Milliseconds only appear where a handler needs to place a moment *within* +//! the current slot against the basis-point deadlines +//! (`get_attestation_due_ms` and friends, fractions of +//! `Config::slot_duration_ms`): [`seconds_to_milliseconds`] converts the +//! coarse seconds-since-genesis value at exactly that point, and nowhere else. +//! So this is not two clocks running at different rates; it is one +//! seconds-resolution clock with a millisecond-resolution read-out computed on +//! demand, purely for comparing against the sub-slot deadlines. +//! +//! # Why some maps here are not the spec's `Dict` +//! +//! [`Checkpoint`] derives neither `Hash` nor `Ord` in [`crate::beacon::containers`], +//! and this file cannot add either without editing that module. So +//! `checkpoint_states` is keyed on `(Epoch, Root)` instead of `Checkpoint` +//! itself; [`Store::checkpoint_state`], [`Store::has_checkpoint_state`], and +//! [`Store::insert_checkpoint_state`] hide that from every caller in this +//! file. Every other `Dict` becomes a [`std::collections::HashMap`] keyed on +//! its own spec type directly: [`Root`] and [`ValidatorIndex`] both hash the +//! way this file needs. +//! +//! # Why the hash maps here never need to be a `BTreeMap` +//! +//! The one place the specification iterates a whole `Dict`'s keys is +//! `filter_block_tree`'s scan of `store.blocks` for a block's children, and +//! [`get_head`]'s equivalent scan of the filtered tree. Both immediately +//! reduce that scan to a single winner via an explicit, fully-ordered sort key +//! (`(weight, root)`, with `root` breaking ties the same way Python compares +//! two `bytes` values, since [`Root`]'s `Ord` compares its bytes in the same +//! order). Two distinct blocks never share a root, so that key never actually +//! ties, and the winner is the same regardless of which order the underlying +//! map happened to yield its entries in. Nothing else in this file examines a +//! map's keys as a whole, so no map here needs an order of its own. +//! +//! # `Store::blocks` holds signed blocks, not the specification's unsigned ones +//! +//! The specification's `store.blocks: Dict[Root, BeaconBlock]` holds the +//! unsigned message. This file holds [`SignedBeaconBlock`] instead: it is +//! what every caller already has in hand (a fixture case, a gossiped block, a +//! `BlocksByRoot` response), the extra signature is small next to a full +//! body, and the map stays keyed on the *unsigned* message's root +//! ([`SignedBeaconBlock::message_hash_tree_root`]), so nothing about lookup or +//! ancestry changes. [`get_forkchoice_store`]'s `anchor_block` is signed for +//! the same reason, even though a trusted anchor's own signature is never +//! actually checked. +//! +//! Holding the fork-generic enum here, rather than a concrete per-fork +//! struct, is what lets [`on_block`] accept a block from any fork this module +//! implements: every place in this file that reads a field off a stored block +//! goes through the enum's shared accessors (`slot()`, `parent_root()`, and +//! so on) rather than a phase0-specific field. +//! +//! # `on_block`'s execution engine +//! +//! [`stf::state_transition`] takes an [`stf::ExecutionEngine`] from bellatrix +//! on, for the one call a real client would route to its execution layer. +//! [`on_block`] always passes [`stf::ExecutionEngine::valid`]: no released +//! `fork_choice` fixture, at any fork or preset, ships an `execution.yaml` or +//! an `on_payload_info` step, so there is nothing yet for a caller to supply +//! a different answer for. `on_payload_info` is also a standing registry +//! keyed by block hash and updated over the course of a case, not a single +//! value fixed at construction time, so when a fixture exercising it does +//! arrive, threading it through will need more than a parameter on this +//! function. +//! +//! # [`Attestation`] and [`AttesterSlashing`]: a second fork-generic enum +//! +//! [`phase0::Attestation`] and [`phase0::AttesterSlashing`] keep the same +//! shape from phase0 through deneb, so [`on_attestation`] and +//! [`on_attester_slashing`] could stay phase0-typed through every fork this +//! crate implemented before electra. EIP-7549 breaks that: electra widens +//! `aggregation_bits` from one committee's worth to a whole slot's and adds +//! `committee_bits`, so [`electra::Attestation`] (and, following from it, +//! [`electra::IndexedAttestation`] and [`electra::AttesterSlashing`]) is a +//! different concrete type, not just a wider bound on the same one. +//! +//! [`Attestation`] and [`AttesterSlashing`] mirror [`SignedBeaconBlock`]'s own +//! answer to that problem: an enum over the two shapes, with two variants +//! rather than one per fork for the same reason `SignedBeaconBlock` has only +//! seven, not one per fork through fulu. But fork choice reads far less out +//! of an attestation than a block: `data.slot`, `data.target`, +//! `data.beacon_block_root`, and the attesting indices, per the module +//! documentation above. `AttestationData` (`crate::beacon::containers::shared`) is +//! already fork-invariant, so every function below except the two enums' +//! own methods reads it directly rather than matching on a fork tag it does +//! not need: [`validate_on_attestation`] and [`update_latest_messages`] take +//! `AttestationData` and a resolved `&[ValidatorIndex]`, not an +//! [`Attestation`]. The one place a fork's own shape actually matters is +//! resolving an [`Attestation`] into the attesters it names and checking +//! their aggregate signature, which needs the fork-specific +//! `get_indexed_attestation`/`is_valid_indexed_attestation` pair +//! ([`crate::beacon::helpers::attestation`] for phase0, [`crate::beacon::helpers::electra`] +//! for electra); [`Attestation::verified_attesting_indices`] and +//! [`AttesterSlashing::verified_attesting_indices`] are where that dispatch +//! happens, once, so [`on_attestation`] and [`on_attester_slashing`] +//! themselves never match on a fork at all. +//! +//! # Bellatrix's merge check, and data availability from deneb on +//! +//! [`on_block`] gains two more fork-conditional steps beyond `phase0/fork- +//! choice.md`, both because a later fork's own `fork-choice.md` modifies +//! `on_block` directly rather than leaving it to state transition: +//! +//! - Bellatrix requires a transitioning block's parent execution payload to +//! sit on a valid terminal PoW block ([`validate_merge_block`]), checked +//! against [`Store::pow_blocks`] rather than a real execution client, the +//! same way [`stf::ExecutionEngine`] stands in for one elsewhere in this +//! crate. Capella's own `fork-choice.md` removes this check outright +//! ("deletion of the verification of merge transition block conditions"), +//! so it applies to bellatrix alone. +//! - Deneb, electra, and fulu each require `is_data_available` to hold +//! before a block with blob commitments is even considered +//! ([`is_data_available_blobs`] for deneb/electra's blob-and-proof shape, +//! [`is_data_available_columns`] for fulu's column-sidecar shape). Both +//! read `retrieve_blobs_and_proofs`/`retrieve_column_sidecars`'s answer out +//! of [`DataAvailability`], a parameter on [`on_block`] rather than a +//! `Store` field: unlike a PoW block, this evidence is scoped to the one +//! block being considered right now, not a registry looked up by hash +//! later. Both helpers are also "implementation and context dependent" in +//! the specification's own words, exactly the class of thing +//! [`stf::ExecutionEngine`] already collapses to whatever the fixture +//! suites supply directly. + +use std::collections::{HashMap, HashSet}; + +use crate::beacon::config::Config; +use crate::beacon::constants; +use crate::beacon::containers::{AttestationData, BeaconState, Checkpoint, SignedBeaconBlock}; +use crate::beacon::containers::{bellatrix, deneb, electra, fulu, phase0}; +use crate::beacon::error::{Error, Result, verify}; +use crate::beacon::helpers::accessors::{ + get_active_validator_indices, get_beacon_proposer_index, get_current_epoch, + get_total_active_balance, +}; +use crate::beacon::helpers::attestation as phase0_attestation; +use crate::beacon::helpers::electra as electra_helpers; +use crate::beacon::helpers::misc::{compute_epoch_at_slot, compute_start_slot_at_epoch}; +use crate::beacon::helpers::predicates::is_slashable_attestation_data; +use crate::beacon::kzg; +use crate::beacon::preset; +use crate::beacon::primitives::{Epoch, Gwei, KzgCommitment, KzgProof, Root, Slot, ValidatorIndex}; +use crate::beacon::stf; + +// --------------------------------------------------------------------------- +// LatestMessage, PowBlock +// --------------------------------------------------------------------------- + +// Both live in `ethlambda-types` rather than here, because `ethlambda-storage` +// persists them and cannot depend on this crate. Re-exported at the paths they +// had when they were defined here, so [`Store`] and its callers are unchanged. +pub use ethlambda_types::beacon::fork_choice::{LatestMessage, PowBlock}; + +// --------------------------------------------------------------------------- +// Attestation, AttesterSlashing +// --------------------------------------------------------------------------- + +/// An attestation, in whichever fork's shape it currently has. See the module +/// documentation for why this exists and what it lets the rest of this file +/// stay generic over. +/// +/// Two variants, not one per fork: every fork through deneb shares +/// [`phase0::Attestation`] outright, and fulu shares [`electra::Attestation`] +/// the same way [`SignedBeaconBlock::Fulu`] shares +/// [`electra::SignedBeaconBlock`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Attestation { + Phase0(phase0::Attestation), + Electra(electra::Attestation), +} + +impl Attestation { + /// The fork-invariant half of an attestation: everything + /// [`validate_on_attestation`] and [`update_latest_messages`] need, which + /// is why neither of them takes an [`Attestation`] at all. + pub fn data(&self) -> AttestationData { + match self { + Attestation::Phase0(attestation) => attestation.data, + Attestation::Electra(attestation) => attestation.data, + } + } + + /// The attesters this attestation names, once its aggregate signature and + /// index ordering have both been checked against `state`. + /// + /// The one place this enum's two shapes actually matter: building the + /// indexed form and checking it needs the fork-specific + /// `get_indexed_attestation`/`is_valid_indexed_attestation` pair, so this + /// dispatches once here rather than leaving that match to every caller. + pub fn verified_attesting_indices(&self, state: &BeaconState) -> Result> { + match self { + Attestation::Phase0(attestation) => { + let indexed = phase0_attestation::get_indexed_attestation(state, attestation)?; + verify( + phase0_attestation::is_valid_indexed_attestation(state, &indexed), + "is_valid_indexed_attestation(target_state, indexed_attestation)", + )?; + Ok(indexed.attesting_indices.into_inner()) + } + Attestation::Electra(attestation) => { + let indexed = electra_helpers::get_indexed_attestation(state, attestation)?; + verify( + electra_helpers::is_valid_indexed_attestation(state, &indexed), + "is_valid_indexed_attestation(target_state, indexed_attestation)", + )?; + Ok(indexed.attesting_indices.into_inner()) + } + } + } +} + +/// Evidence that a set of validators made two conflicting attestations, in +/// whichever fork's shape it currently has. See [`Attestation`] for why this +/// has the same two variants and no more. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum AttesterSlashing { + Phase0(phase0::AttesterSlashing), + Electra(electra::AttesterSlashing), +} + +impl AttesterSlashing { + /// The fork-invariant half of both attestations `self` accuses of + /// equivocating: what [`on_attester_slashing`] needs to check + /// [`is_slashable_attestation_data`] before it looks at either half's + /// attesters at all. + pub fn data(&self) -> (AttestationData, AttestationData) { + match self { + AttesterSlashing::Phase0(slashing) => { + (slashing.attestation_1.data, slashing.attestation_2.data) + } + AttesterSlashing::Electra(slashing) => { + (slashing.attestation_1.data, slashing.attestation_2.data) + } + } + } + + /// The attesting indices of both halves, once each has been checked as + /// an individually valid indexed attestation against `state`. See + /// [`Attestation::verified_attesting_indices`] for why this is where the + /// fork-specific dispatch happens. + pub fn verified_attesting_indices( + &self, + state: &BeaconState, + ) -> Result<(Vec, Vec)> { + match self { + AttesterSlashing::Phase0(slashing) => { + verify( + phase0_attestation::is_valid_indexed_attestation( + state, + &slashing.attestation_1, + ), + "is_valid_indexed_attestation(state, attestation_1)", + )?; + verify( + phase0_attestation::is_valid_indexed_attestation( + state, + &slashing.attestation_2, + ), + "is_valid_indexed_attestation(state, attestation_2)", + )?; + Ok(( + slashing + .attestation_1 + .attesting_indices + .iter() + .copied() + .collect(), + slashing + .attestation_2 + .attesting_indices + .iter() + .copied() + .collect(), + )) + } + AttesterSlashing::Electra(slashing) => { + verify( + electra_helpers::is_valid_indexed_attestation(state, &slashing.attestation_1), + "is_valid_indexed_attestation(state, attestation_1)", + )?; + verify( + electra_helpers::is_valid_indexed_attestation(state, &slashing.attestation_2), + "is_valid_indexed_attestation(state, attestation_2)", + )?; + Ok(( + slashing + .attestation_1 + .attesting_indices + .iter() + .copied() + .collect(), + slashing + .attestation_2 + .attesting_indices + .iter() + .copied() + .collect(), + )) + } + } + } +} + +// --------------------------------------------------------------------------- +// DataAvailability +// --------------------------------------------------------------------------- + +/// What [`on_block`] needs from `retrieve_blobs_and_proofs` (deneb, electra) +/// or `retrieve_column_sidecars` (fulu) to decide `is_data_available`. +/// +/// Both are "implementation and context dependent" in the specification's +/// own words, exactly like [`stf::ExecutionEngine`]'s execution-payload +/// validity call; this collapses the same way, to whatever the fixture +/// suites supply directly for the one block being considered right now. A +/// `Store` field would be the wrong shape for that: unlike [`PowBlock`], +/// this evidence is never looked up again by some other hash later, so +/// [`on_block`] takes it as a parameter instead. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum DataAvailability { + /// The block carries no blob commitments, or predates deneb: nothing for + /// [`on_block`]'s data-availability check to do. + NotRequired, + /// Deneb and electra's shape: every blob and its proof, in + /// `block.body.blob_kzg_commitments`'s own order. A length mismatch + /// against the block's own commitments is not checked here; it is + /// exactly what [`is_data_available_blobs`] rejects. + Blobs { + blobs: Vec, + proofs: Vec, + }, + /// Fulu's shape: the column sidecars sampled for this block. + Columns(Vec), +} + +// --------------------------------------------------------------------------- +// Store +// --------------------------------------------------------------------------- + +/// The fork choice store. +/// +/// Constructed once, at genesis or at a checkpoint-sync anchor, by +/// [`get_forkchoice_store`], and after that changed only by the four handlers +/// at the bottom of this file. The specification requires that an invalid +/// call to any of them leave `store` untouched; the `Result`-returning +/// handlers below uphold that by validating before mutating, rather than by +/// rolling a partial mutation back. +/// +/// Does not implement `Clone`. `block_states` and `checkpoint_states` each +/// hold a full [`BeaconState`] per entry, and the store keeps one for every +/// block still within the unfinalized window, so a whole-store clone would +/// silently duplicate an unbounded amount of state on every call. Nothing in +/// this file, or in the specification, ever needs a copy of the whole store. +#[derive(Debug)] +pub struct Store { + /// The current time, as Unix seconds. See the module documentation for how + /// this relates to the millisecond deadlines the reorg helpers compute. + pub time: u64, + pub genesis_time: u64, + pub justified_checkpoint: Checkpoint, + pub finalized_checkpoint: Checkpoint, + /// The highest justified checkpoint observed in any block's post-state, + /// whether or not that block's *own* chain has an on-chain epoch boundary + /// that has caught up to reflect it yet. + pub unrealized_justified_checkpoint: Checkpoint, + /// The finalized-checkpoint counterpart to + /// [`Store::unrealized_justified_checkpoint`]. + pub unrealized_finalized_checkpoint: Checkpoint, + /// The most recent timely, uncontested block seen this slot, or the zero + /// root if none has arrived yet or a new slot has reset it. While set, + /// [`get_weight`] adds [`get_proposer_score`]'s boost to this block and + /// every ancestor of it. + pub proposer_boost_root: Root, + /// Validators caught attesting to two conflicting things, via + /// [`on_attester_slashing`]. [`get_weight`] excludes their vote entirely, + /// rather than letting an equivocator's [`LatestMessage`] count for either + /// side of the fork it created. + pub equivocating_indices: HashSet, + /// Keyed on the unsigned message's root, matching the specification's own + /// `store.blocks`, even though the value held here is signed. See the + /// module documentation for why. + pub blocks: HashMap, + /// The post-state resulting from applying each block in + /// [`Store::blocks`]. + pub block_states: HashMap, + /// Whether each block in [`Store::blocks`] arrived before the attestation + /// deadline of the slot fork choice was in when it was imported. Feeds + /// [`is_head_late`], one of the inputs to a same-slot proposer reorg. + pub block_timeliness: HashMap, + /// The state advanced to the first slot of each checkpoint's epoch, cached + /// so that [`on_attestation`] does not replay [`stf::process_slots`] for + /// every attestation that shares a target. + /// + /// Keyed on `(Epoch, Root)` rather than [`Checkpoint`] itself; see the + /// module documentation. Read and write through + /// [`Store::checkpoint_state`], [`Store::has_checkpoint_state`], and + /// [`Store::insert_checkpoint_state`] rather than this field. + checkpoint_states: HashMap<(Epoch, Root), BeaconState>, + pub latest_messages: HashMap, + /// The unrealized justified checkpoint observed in each block's own + /// post-state, kept up to date by [`compute_pulled_up_tip`] so that + /// [`get_voting_source`] can "pull up" an older block's effective vote + /// without replaying epoch processing on every lookup. + pub unrealized_justifications: HashMap, + /// PoW blocks known to this store, keyed by [`PowBlock::block_hash`]. See + /// [`PowBlock`]'s documentation for why this stands in for + /// `get_pow_block` rather than this file calling out to a real execution + /// client. Read through [`get_pow_block`], written through + /// [`insert_pow_block`]. + pub pow_blocks: HashMap, +} + +impl Store { + /// The cached state at `checkpoint`, if [`store_target_checkpoint_state`] + /// (or [`get_forkchoice_store`], for the anchor checkpoint) has already + /// computed one. + pub fn checkpoint_state(&self, checkpoint: &Checkpoint) -> Option<&BeaconState> { + self.checkpoint_states + .get(&(checkpoint.epoch, checkpoint.root)) + } + + /// Whether [`Store::checkpoint_state`] would return `Some` for + /// `checkpoint`. + pub fn has_checkpoint_state(&self, checkpoint: &Checkpoint) -> bool { + self.checkpoint_states + .contains_key(&(checkpoint.epoch, checkpoint.root)) + } + + /// Caches `state` as the state at `checkpoint`. + pub fn insert_checkpoint_state(&mut self, checkpoint: Checkpoint, state: BeaconState) { + self.checkpoint_states + .insert((checkpoint.epoch, checkpoint.root), state); + } +} + +// --------------------------------------------------------------------------- +// get_forkchoice_store +// --------------------------------------------------------------------------- + +/// Builds the initial store from a trusted anchor state and block. +/// +/// "Trusted" means fork choice will never roll back past this point: a full +/// client anchors at genesis, and a checkpoint-syncing client anchors at +/// whatever finalized state and block it fetched instead. +pub fn get_forkchoice_store( + anchor_state: BeaconState, + anchor_block: SignedBeaconBlock, + config: &Config, +) -> Result { + // The specification's `BeaconState` and `BeaconBlock` are already one + // fork's own types, so a mismatch between them cannot even be expressed + // there; here both are enums, so this module has to enforce the invariant + // by hand, the same way `stf::state_transition` does for every later + // block. + verify( + anchor_block.fork_name() == anchor_state.fork_name(), + "anchor_block's fork matches anchor_state's", + )?; + verify( + anchor_block.state_root() == anchor_state.hash_tree_root(), + "anchor_block.state_root == hash_tree_root(anchor_state)", + )?; + + let anchor_root = anchor_block.message_hash_tree_root(); + let anchor_epoch = get_current_epoch(&anchor_state); + let justified_checkpoint = Checkpoint { + epoch: anchor_epoch, + root: anchor_root, + }; + // The specification gives finality the same starting value as + // justification: a trusted anchor is finalized by fiat, not by having + // actually gone through the FFG rules. + let finalized_checkpoint = justified_checkpoint; + + // `SECONDS_PER_SLOT * anchor_state.slot` is arithmetic over values that + // ultimately come from an externally supplied anchor, so this fails + // loudly on overflow rather than silently wrapping the store's clock. + let time = config + .seconds_per_slot + .checked_mul(anchor_state.slot()) + .and_then(|slot_seconds| slot_seconds.checked_add(anchor_state.genesis_time())) + .ok_or(Error::ArithmeticOverflow( + "anchor_state.genesis_time + SECONDS_PER_SLOT * anchor_state.slot", + ))?; + let genesis_time = anchor_state.genesis_time(); + + let mut blocks = HashMap::new(); + blocks.insert(anchor_root, anchor_block); + + let mut block_states = HashMap::new(); + // The specification stores the anchor state under both `block_states` and + // `checkpoint_states` (`copy(anchor_state)` in each). This is the only + // place in this file that clones a whole `BeaconState` outright: genesis + // happens once, and the two maps each need their own entry to + // independently advance from here on. + block_states.insert(anchor_root, anchor_state.clone()); + + let mut checkpoint_states = HashMap::new(); + checkpoint_states.insert( + (justified_checkpoint.epoch, justified_checkpoint.root), + anchor_state, + ); + + let mut unrealized_justifications = HashMap::new(); + unrealized_justifications.insert(anchor_root, justified_checkpoint); + + Ok(Store { + time, + genesis_time, + justified_checkpoint, + finalized_checkpoint, + unrealized_justified_checkpoint: justified_checkpoint, + unrealized_finalized_checkpoint: finalized_checkpoint, + proposer_boost_root: Root::ZERO, + equivocating_indices: HashSet::new(), + blocks, + block_states, + block_timeliness: HashMap::new(), + checkpoint_states, + latest_messages: HashMap::new(), + unrealized_justifications, + pow_blocks: HashMap::new(), + }) +} + +// --------------------------------------------------------------------------- +// Time and slot helpers +// --------------------------------------------------------------------------- + +/// How many whole slots have elapsed since genesis, as of `store.time`. +pub fn get_slots_since_genesis(store: &Store, config: &Config) -> u64 { + store.time.saturating_sub(store.genesis_time) / config.seconds_per_slot +} + +/// The slot `store.time` currently falls in. +pub fn get_current_slot(store: &Store, config: &Config) -> Slot { + constants::GENESIS_SLOT + get_slots_since_genesis(store, config) +} + +/// The epoch `store.time` currently falls in. +pub fn get_current_store_epoch(store: &Store, config: &Config) -> Epoch { + compute_epoch_at_slot(get_current_slot(store, config)) +} + +/// How many slots into its epoch `slot` is, `0` for the epoch's first slot. +pub fn compute_slots_since_epoch_start(slot: Slot) -> Slot { + slot - compute_start_slot_at_epoch(compute_epoch_at_slot(slot)) +} + +/// The ancestor of `root` at `slot`: the block on `root`'s chain whose own +/// slot is at or before `slot`, found by walking parent links. +/// +/// The specification defines this recursively; implemented here as a loop +/// instead, so that a long unfinalized suffix cannot risk a stack overflow. +/// An unknown `root` is exactly the "unhandled exception" case the +/// specification calls out as invalid (`store.blocks[root]` would raise +/// `KeyError` in the reference implementation), so it becomes a `SpecAssert` +/// here rather than a panic. +pub fn get_ancestor(store: &Store, root: Root, slot: Slot) -> Result { + let mut root = root; + loop { + let block = store + .blocks + .get(&root) + .ok_or(Error::SpecAssert("root in store.blocks"))?; + if block.slot() > slot { + root = block.parent_root(); + } else { + return Ok(root); + } + } +} + +// --------------------------------------------------------------------------- +// Committee-relative weight helpers +// --------------------------------------------------------------------------- + +/// A committee's share of `state`'s total active balance, scaled by +/// `committee_percent` out of one hundred. +/// +/// `committee_percent` is a plain percentage, not basis points: unlike the +/// `*_due_bps` configuration values (fractions of [`Config::slot_duration_ms`] +/// out of [`constants::BASIS_POINTS`]), the specification writes this +/// divisor as a bare `100` with no name of its own, since +/// [`Config::proposer_score_boost`] and the two `Config::reorg_*_threshold` +/// values it is called with are themselves already expressed on a 0-100 +/// scale. +pub fn calculate_committee_fraction(state: &BeaconState, committee_percent: u64) -> Result { + let committee_weight = get_total_active_balance(state)? / preset::SLOTS_PER_EPOCH; + Ok(committee_weight.saturating_mul(committee_percent) / 100) +} + +/// The checkpoint block for `epoch`, on `root`'s chain: the ancestor of `root` +/// at that epoch's first slot. +pub fn get_checkpoint_block(store: &Store, root: Root, epoch: Epoch) -> Result { + get_ancestor(store, root, compute_start_slot_at_epoch(epoch)) +} + +/// The extra weight a timely, uncontested block gets over its competitors, +/// scaled to deter a "balancing" attack that splits votes right at a slot +/// boundary. +/// +/// See [`calculate_committee_fraction`] for why this divides by a bare +/// `100` rather than [`constants::BASIS_POINTS`]. +pub fn get_proposer_score(store: &Store, config: &Config) -> Result { + let justified_state = + store + .checkpoint_state(&store.justified_checkpoint) + .ok_or(Error::SpecAssert( + "store.justified_checkpoint in store.checkpoint_states", + ))?; + let committee_weight = get_total_active_balance(justified_state)? / preset::SLOTS_PER_EPOCH; + Ok(committee_weight.saturating_mul(config.proposer_score_boost) / 100) +} + +/// The LMD GHOST weight of `root`: the effective balance of every +/// non-equivocating, active, unslashed validator whose latest vote descends +/// through `root`, plus the proposer boost if it applies. +pub fn get_weight(store: &Store, root: Root, config: &Config) -> Result { + let state = store + .checkpoint_state(&store.justified_checkpoint) + .ok_or(Error::SpecAssert( + "store.justified_checkpoint in store.checkpoint_states", + ))?; + let current_epoch = get_current_epoch(state); + let block_slot = store + .blocks + .get(&root) + .ok_or(Error::SpecAssert("root in store.blocks"))? + .slot(); + + let mut attestation_score: Gwei = 0; + for index in get_active_validator_indices(state, current_epoch) { + let validator = state.validator(index)?; + if validator.slashed || store.equivocating_indices.contains(&index) { + continue; + } + let Some(message) = store.latest_messages.get(&index) else { + continue; + }; + if get_ancestor(store, message.root, block_slot)? == root { + attestation_score = attestation_score.saturating_add(validator.effective_balance); + } + } + + if store.proposer_boost_root.is_zero() { + return Ok(attestation_score); + } + + let mut proposer_score: Gwei = 0; + if get_ancestor(store, store.proposer_boost_root, block_slot)? == root { + proposer_score = get_proposer_score(store, config)?; + } + Ok(attestation_score.saturating_add(proposer_score)) +} + +/// The checkpoint a block would cast as its FFG source if it were canonical +/// head right now. +/// +/// A block from a strictly earlier epoch than the store's current one has its +/// vote "pulled up" to the unrealized justification [`compute_pulled_up_tip`] +/// computed for it, rather than to whatever its own post-state's +/// `current_justified_checkpoint` happened to be at the time it was +/// processed; a block from the current epoch has no unrealized value to pull +/// up to yet, so its own post-state's checkpoint is used directly. +pub fn get_voting_source(store: &Store, block_root: Root, config: &Config) -> Result { + let block_slot = store + .blocks + .get(&block_root) + .ok_or(Error::SpecAssert("block_root in store.blocks"))? + .slot(); + let current_epoch = get_current_store_epoch(store, config); + let block_epoch = compute_epoch_at_slot(block_slot); + + if current_epoch > block_epoch { + store + .unrealized_justifications + .get(&block_root) + .copied() + .ok_or(Error::SpecAssert( + "block_root in store.unrealized_justifications", + )) + } else { + let head_state = store + .block_states + .get(&block_root) + .ok_or(Error::SpecAssert("block_root in store.block_states"))?; + Ok(head_state.current_justified_checkpoint()) + } +} + +// --------------------------------------------------------------------------- +// Filtering the block tree +// --------------------------------------------------------------------------- + +/// Walks `block_root`'s subtree, adding every block on a viable branch to +/// `blocks`, and reporting whether `block_root` itself sits on one. +/// +/// *Note*: external callers must pass `store.justified_checkpoint.root` for +/// `block_root`; only the recursive calls below pass anything else. +/// +/// Recursive, following the specification directly rather than an explicit +/// stack: the subtree walked here is the unfinalized suffix since the +/// justified checkpoint, which stays shallow in ordinary operation. +/// +/// Borrows `blocks` for the whole walk instead of the specification's owned +/// output dict, so this never clones a [`SignedBeaconBlock`] just to hand a +/// second reference to it to the caller. +pub fn filter_block_tree<'store>( + store: &'store Store, + block_root: Root, + blocks: &mut HashMap, + config: &Config, +) -> Result { + let block = store + .blocks + .get(&block_root) + .ok_or(Error::SpecAssert("block_root in store.blocks"))?; + + let children: Vec = store + .blocks + .iter() + .filter(|(_, candidate)| candidate.parent_root() == block_root) + .map(|(root, _)| *root) + .collect(); + + // If any children branches contain expected finalized/justified + // checkpoints, add to filtered block-tree and signal viability to parent. + if !children.is_empty() { + let mut any_viable = false; + for child in children { + if filter_block_tree(store, child, blocks, config)? { + any_viable = true; + } + } + if any_viable { + blocks.insert(block_root, block); + return Ok(true); + } + return Ok(false); + } + + let current_epoch = get_current_store_epoch(store, config); + let voting_source = get_voting_source(store, block_root, config)?; + + // The voting source should be either at the same height as the store's + // justified checkpoint or not more than two epochs ago. + let correct_justified = store.justified_checkpoint.epoch == constants::GENESIS_EPOCH + || voting_source.epoch == store.justified_checkpoint.epoch + || voting_source.epoch.saturating_add(2) >= current_epoch; + + let finalized_checkpoint_block = + get_checkpoint_block(store, block_root, store.finalized_checkpoint.epoch)?; + + let correct_finalized = store.finalized_checkpoint.epoch == constants::GENESIS_EPOCH + || store.finalized_checkpoint.root == finalized_checkpoint_block; + + // If expected finalized/justified, add to viable block-tree and signal + // viability to parent. + if correct_justified && correct_finalized { + blocks.insert(block_root, block); + return Ok(true); + } + + Ok(false) +} + +/// The filtered block tree: every block, from the justified checkpoint down, +/// whose leaf state's justified/finalized info agrees with `store`'s own. +pub fn get_filtered_block_tree<'store>( + store: &'store Store, + config: &Config, +) -> Result> { + let base = store.justified_checkpoint.root; + let mut blocks = HashMap::new(); + filter_block_tree(store, base, &mut blocks, config)?; + Ok(blocks) +} + +/// The LMD GHOST head: starting from the justified checkpoint, repeatedly +/// step to the child with the greatest weight until a leaf is reached. +pub fn get_head(store: &Store, config: &Config) -> Result { + let blocks = get_filtered_block_tree(store, config)?; + let mut head = store.justified_checkpoint.root; + loop { + let children: Vec = blocks + .iter() + .filter(|(_, block)| block.parent_root() == head) + .map(|(root, _)| *root) + .collect(); + if children.is_empty() { + return Ok(head); + } + + // Sort by latest attesting balance with ties broken lexicographically, + // favoring the higher root: pairing the weight with the root itself as + // the sort key gives exactly that, and `Root`'s derived `Ord` compares + // its bytes in order, matching Python's default comparison of a + // `bytes` root. + let mut ranked = Vec::with_capacity(children.len()); + for root in children { + ranked.push((get_weight(store, root, config)?, root)); + } + head = ranked + .into_iter() + .max() + .expect("children is non-empty, checked above") + .1; + } +} + +// --------------------------------------------------------------------------- +// Checkpoint bookkeeping +// --------------------------------------------------------------------------- + +/// Advances `store`'s justified and finalized checkpoints to `justified` and +/// `finalized`, if each is more recent than what is already recorded. +/// +/// Justification and finalization only ever move forward: a lower-epoch +/// checkpoint arriving later (as can happen while replaying blocks out of +/// order) must not roll a more advanced view back. +pub fn update_checkpoints(store: &mut Store, justified: Checkpoint, finalized: Checkpoint) { + if justified.epoch > store.justified_checkpoint.epoch { + store.justified_checkpoint = justified; + } + if finalized.epoch > store.finalized_checkpoint.epoch { + store.finalized_checkpoint = finalized; + } +} + +/// The unrealized-checkpoint counterpart to [`update_checkpoints`]. +pub fn update_unrealized_checkpoints( + store: &mut Store, + unrealized_justified: Checkpoint, + unrealized_finalized: Checkpoint, +) { + if unrealized_justified.epoch > store.unrealized_justified_checkpoint.epoch { + store.unrealized_justified_checkpoint = unrealized_justified; + } + if unrealized_finalized.epoch > store.unrealized_finalized_checkpoint.epoch { + store.unrealized_finalized_checkpoint = unrealized_finalized; + } +} + +// --------------------------------------------------------------------------- +// Millisecond time helpers +// --------------------------------------------------------------------------- +// +// See the module documentation for how these relate to `Store.time`, which +// stays in seconds throughout. + +/// Converts `seconds` to milliseconds, saturating at [`constants::UINT64_MAX`] +/// instead of wrapping. +pub fn seconds_to_milliseconds(seconds: u64) -> u64 { + seconds.checked_mul(1000).unwrap_or(constants::UINT64_MAX) +} + +/// The duration, in milliseconds, that `basis_points` out of +/// [`constants::BASIS_POINTS`] of a slot spans. +pub fn get_slot_component_duration_ms(basis_points: u64, config: &Config) -> u64 { + basis_points.saturating_mul(config.slot_duration_ms) / constants::BASIS_POINTS +} + +/// How far into a slot, in milliseconds, an attestation is due. +/// +/// `epoch` is accepted, matching the specification's signature, but not read: +/// the deadline is a fixed fraction of the slot in every epoch this module +/// implements. +pub fn get_attestation_due_ms(_epoch: Epoch, config: &Config) -> u64 { + get_slot_component_duration_ms(config.attestation_due_bps, config) +} + +/// How far into a slot, in milliseconds, a proposer must stop attempting a +/// late-block reorg. See [`get_attestation_due_ms`] for why `epoch` is unused. +pub fn get_proposer_reorg_cutoff_ms(_epoch: Epoch, config: &Config) -> u64 { + get_slot_component_duration_ms(config.proposer_reorg_cutoff_bps, config) +} + +/// How far into a slot, in milliseconds, an aggregate attestation is due. See +/// [`get_attestation_due_ms`] for why `epoch` is unused. +pub fn get_aggregate_due_ms(_epoch: Epoch, config: &Config) -> u64 { + get_slot_component_duration_ms(config.aggregate_due_bps, config) +} + +// --------------------------------------------------------------------------- +// Proposer head and reorg helpers +// --------------------------------------------------------------------------- +// +// The specification marks implementing these as optional, but a proposer +// that skips them simply always builds on `get_head`'s result rather than +// ever reorging out a late block; this module implements them so a validator +// client built on it can make that choice instead of having it made for it. + +/// Whether `head_root`'s block arrived after the attestation deadline of the +/// slot it was imported in. +pub fn is_head_late(store: &Store, head_root: Root) -> Result { + let timely = store + .block_timeliness + .get(&head_root) + .copied() + .ok_or(Error::SpecAssert("head_root in store.block_timeliness"))?; + Ok(!timely) +} + +/// Whether `slot` is not the first slot of its epoch, i.e. the proposer +/// shuffling in effect for it cannot change from reorging one slot. +pub fn is_shuffling_stable(slot: Slot) -> bool { + !slot.is_multiple_of(preset::SLOTS_PER_EPOCH) +} + +/// Whether `head_root` and `parent_root` would cast the same FFG vote if +/// either were head, so that reorging one for the other costs nothing on the +/// justification side. +pub fn is_ffg_competitive(store: &Store, head_root: Root, parent_root: Root) -> Result { + let head = store + .unrealized_justifications + .get(&head_root) + .ok_or(Error::SpecAssert( + "head_root in store.unrealized_justifications", + ))?; + let parent = store + .unrealized_justifications + .get(&parent_root) + .ok_or(Error::SpecAssert( + "parent_root in store.unrealized_justifications", + ))?; + Ok(head == parent) +} + +/// Whether the chain has finalized recently enough that a reorg is still +/// worth risking: reorgs are a liveness optimization, and this bounds how +/// much finality progress they may put at stake to pursue it. +pub fn is_finalization_ok(store: &Store, slot: Slot, config: &Config) -> bool { + let epochs_since_finalization = + compute_epoch_at_slot(slot).saturating_sub(store.finalized_checkpoint.epoch); + epochs_since_finalization <= config.reorg_max_epochs_since_finalization +} + +/// Whether `store.time` is early enough in the current slot that a proposer +/// building now still counts as on time. +pub fn is_proposing_on_time(store: &Store, config: &Config) -> bool { + let seconds_since_genesis = store.time.saturating_sub(store.genesis_time); + let time_into_slot_ms = + seconds_to_milliseconds(seconds_since_genesis) % config.slot_duration_ms; + let epoch = get_current_store_epoch(store, config); + time_into_slot_ms <= get_proposer_reorg_cutoff_ms(epoch, config) +} + +/// Whether `head_root` has few enough votes to be overpowered by the +/// proposer's own boost, i.e. reorging it out would not be fighting an +/// already-decisive lead. +pub fn is_head_weak(store: &Store, head_root: Root, config: &Config) -> Result { + let justified_state = + store + .checkpoint_state(&store.justified_checkpoint) + .ok_or(Error::SpecAssert( + "store.justified_checkpoint in store.checkpoint_states", + ))?; + let reorg_threshold = + calculate_committee_fraction(justified_state, config.reorg_head_weight_threshold)?; + Ok(get_weight(store, head_root, config)? < reorg_threshold) +} + +/// Whether `parent_root` already has enough votes of its own that the missing +/// votes are assigned to it rather than being hoarded elsewhere. +pub fn is_parent_strong(store: &Store, parent_root: Root, config: &Config) -> Result { + let justified_state = + store + .checkpoint_state(&store.justified_checkpoint) + .ok_or(Error::SpecAssert( + "store.justified_checkpoint in store.checkpoint_states", + ))?; + let parent_threshold = + calculate_committee_fraction(justified_state, config.reorg_parent_weight_threshold)?; + Ok(get_weight(store, parent_root, config)? > parent_threshold) +} + +/// The block a proposer at `slot` should build on: `head_root`'s parent +/// instead of `head_root` itself, if every reorg condition holds, and +/// `head_root` otherwise. +/// +/// *Note*: the ordering of conditions here is the specification's suggested +/// order, not a requirement; an implementation may reorder or short-circuit +/// for performance. +pub fn get_proposer_head( + store: &Store, + head_root: Root, + slot: Slot, + config: &Config, +) -> Result { + let head_block = store + .blocks + .get(&head_root) + .ok_or(Error::SpecAssert("head_root in store.blocks"))?; + let parent_root = head_block.parent_root(); + let head_slot = head_block.slot(); + let parent_block = store + .blocks + .get(&parent_root) + .ok_or(Error::SpecAssert("parent_root in store.blocks"))?; + let parent_slot = parent_block.slot(); + + // Only re-org the head block if it arrived later than the attestation + // deadline. + let head_late = is_head_late(store, head_root)?; + // Do not re-org on an epoch boundary where the proposer shuffling could + // change. + let shuffling_stable = is_shuffling_stable(slot); + // Ensure that the FFG information of the new head will be competitive + // with the current head. + let ffg_competitive = is_ffg_competitive(store, head_root, parent_root)?; + // Do not re-org if the chain is not finalizing with acceptable frequency. + let finalization_ok = is_finalization_ok(store, slot, config); + // Only re-org if we are proposing on-time. + let proposing_on_time = is_proposing_on_time(store, config); + + // Only re-org a single slot at most. + let parent_slot_ok = parent_slot.checked_add(1) == Some(head_slot); + let current_time_ok = head_slot.checked_add(1) == Some(slot); + let single_slot_reorg = parent_slot_ok && current_time_ok; + + // Check that the head has few enough votes to be overpowered by our + // proposer boost. + verify( + store.proposer_boost_root != head_root, + "store.proposer_boost_root != head_root", + )?; + let head_weak = is_head_weak(store, head_root, config)?; + + // Check that the missing votes are assigned to the parent and not being + // hoarded. + let parent_strong = is_parent_strong(store, parent_root, config)?; + + if head_late + && shuffling_stable + && ffg_competitive + && finalization_ok + && proposing_on_time + && single_slot_reorg + && head_weak + && parent_strong + { + // We can re-org the current head by building upon its parent block. + Ok(parent_root) + } else { + Ok(head_root) + } +} + +/// Whether a proposer confident it will build the next block should ask its +/// execution engine to build on `head_root`'s parent instead of `head_root` +/// itself, suppressing the `notify_forkchoice_updated` call bellatrix's +/// `ExecutionEngine` protocol would otherwise make right away. +/// +/// `validator_is_connected` stands in for the specification's own +/// `validator_is_connected(validator_index: ValidatorIndex) -> bool`, "a +/// function that indicates whether the validator ... is connected to the +/// node (e.g. has sent an unexpired proposer preparation message)" +/// (`specs/bellatrix/fork-choice.md`). Every real answer is +/// implementation-specific, so a caller supplies its own policy here rather +/// than this module guessing at one; the fixture suites that exercise this +/// supply a fixed answer directly, the same way [`stf::ExecutionEngine`] +/// stands in for a real execution client elsewhere in this module. +/// +/// Shares [`get_proposer_head`]'s own reorg conditions +/// (`is_head_late`/`is_shuffling_stable`/`is_ffg_competitive`/`is_finalization_ok`), +/// but evaluated against `proposal_slot` (`head_root`'s slot plus one) +/// rather than the caller's own current slot: this asks about the block a +/// confident proposer is *about* to build, one slot ahead of `head_root`, +/// not about reorging a block already received. +pub fn should_override_forkchoice_update( + store: &Store, + head_root: Root, + validator_is_connected: impl Fn(ValidatorIndex) -> bool, + config: &Config, +) -> Result { + let head_block = store + .blocks + .get(&head_root) + .ok_or(Error::SpecAssert("head_root in store.blocks"))?; + let parent_root = head_block.parent_root(); + let head_slot = head_block.slot(); + let parent_block = store + .blocks + .get(&parent_root) + .ok_or(Error::SpecAssert("parent_root in store.blocks"))?; + let parent_slot = parent_block.slot(); + let current_slot = get_current_slot(store, config); + let proposal_slot = head_slot.saturating_add(1); + + // Only re-org the head block if it arrived later than the attestation + // deadline. + let head_late = is_head_late(store, head_root)?; + // Shuffling stable. + let shuffling_stable = is_shuffling_stable(proposal_slot); + // FFG information of the new head block will be competitive with the + // current head. + let ffg_competitive = is_ffg_competitive(store, head_root, parent_root)?; + // Do not re-org if the chain is not finalizing with acceptable frequency. + let finalization_ok = is_finalization_ok(store, proposal_slot, config); + + // Only suppress the fork choice update if we are confident that we will + // propose the next block. A clone, matching the specification's own + // `.copy()`: advancing it to `proposal_slot` is only how this samples the + // proposer that slot would draw, not a change + // `store.block_states[parent_root]` should keep. + let mut parent_state_advanced = store + .block_states + .get(&parent_root) + .ok_or(Error::SpecAssert("parent_root in store.block_states"))? + .clone(); + stf::process_slots(&mut parent_state_advanced, proposal_slot, config)?; + let proposer_index = get_beacon_proposer_index(&parent_state_advanced)?; + let proposing_reorg_slot = validator_is_connected(proposer_index); + + // Single slot re-org. + let parent_slot_ok = parent_slot.checked_add(1) == Some(head_slot); + let proposing_on_time = is_proposing_on_time(store, config); + // Note that this condition is different from `get_proposer_head`. + let current_time_ok = + head_slot == current_slot || (proposal_slot == current_slot && proposing_on_time); + let single_slot_reorg = parent_slot_ok && current_time_ok; + + // Check the head weight only if the attestations from the head slot have + // already been applied; before then, both conditions default to true + // rather than judging the head on attestations that have not arrived + // yet. + let (head_weak, parent_strong) = if current_slot > head_slot { + ( + is_head_weak(store, head_root, config)?, + is_parent_strong(store, parent_root, config)?, + ) + } else { + (true, true) + }; + + Ok(head_late + && shuffling_stable + && ffg_competitive + && finalization_ok + && proposing_reorg_slot + && single_slot_reorg + && head_weak + && parent_strong) +} + +// --------------------------------------------------------------------------- +// Merge transition helpers (bellatrix) +// --------------------------------------------------------------------------- + +/// Looks up a PoW block by hash, matching the specification's own +/// `get_pow_block`. See [`PowBlock`]'s documentation for why this reads +/// [`Store::pow_blocks`] rather than calling out to a real execution client. +pub fn get_pow_block(store: &Store, hash: Root) -> Option { + store.pow_blocks.get(&hash).copied() +} + +/// Records `pow_block` so later [`get_pow_block`] lookups by its own hash can +/// find it. Not one of the four handlers at the bottom of this file: there is +/// no validity condition to check first, since this only ever adds data a +/// fixture suite's `on_merge_block` step already trusts. +pub fn insert_pow_block(store: &mut Store, pow_block: PowBlock) { + store.pow_blocks.insert(pow_block.block_hash, pow_block); +} + +/// Whether `block` is the one PoW block where this chain's proof-of-work +/// history ends and its proof-of-stake history begins: its own total +/// difficulty has crossed [`Config::terminal_total_difficulty`], but its +/// parent's had not yet. +pub fn is_valid_terminal_pow_block(block: &PowBlock, parent: &PowBlock, config: &Config) -> bool { + let is_total_difficulty_reached = block.total_difficulty >= config.terminal_total_difficulty; + let is_parent_total_difficulty_valid = + parent.total_difficulty < config.terminal_total_difficulty; + is_total_difficulty_reached && is_parent_total_difficulty_valid +} + +/// Checks that a bellatrix block's parent execution payload really does sit +/// on a valid terminal PoW block, the one condition [`on_block`] adds for +/// bellatrix and never again afterward: capella's own `fork-choice.md` drops +/// it outright ("deletion of the verification of merge transition block +/// conditions"). +/// +/// [`Config::terminal_block_hash`] is an emergency override that, if ever +/// set, replaces the PoW-chain lookup with a direct hash comparison; every +/// network that shipped the Merge left it unset, so the common path is the +/// `get_pow_block` chain below. +pub fn validate_merge_block( + store: &Store, + block: &bellatrix::BeaconBlock, + config: &Config, +) -> Result<()> { + let parent_hash = block.body.execution_payload.parent_hash; + + if !config.terminal_block_hash.is_zero() { + verify( + compute_epoch_at_slot(block.slot) >= config.terminal_block_hash_activation_epoch, + "compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH", + )?; + verify( + parent_hash == config.terminal_block_hash, + "block.body.execution_payload.parent_hash == TERMINAL_BLOCK_HASH", + )?; + return Ok(()); + } + + let pow_block = get_pow_block(store, parent_hash).ok_or(Error::SpecAssert( + "get_pow_block(block.body.execution_payload.parent_hash) is not None", + ))?; + let pow_parent = get_pow_block(store, pow_block.parent_hash).ok_or(Error::SpecAssert( + "get_pow_block(pow_block.parent_hash) is not None", + ))?; + verify( + is_valid_terminal_pow_block(&pow_block, &pow_parent, config), + "is_valid_terminal_pow_block(pow_block, pow_parent)", + ) +} + +// --------------------------------------------------------------------------- +// Data availability helpers (deneb, electra, fulu) +// --------------------------------------------------------------------------- + +/// The specification's `is_data_available` for deneb and electra +/// (`specs/deneb/fork-choice.md`): every commitment the block claims must +/// come with a blob and a proof that verify against it. +/// +/// `retrieve_blobs_and_proofs` is "implementation and context dependent" +/// there; [`DataAvailability::Blobs`] is what a caller supplies in its place. +/// A length mismatch between `commitments` and the evidence's own blobs or +/// proofs is not checked separately here: `kzg::verify_blob_kzg_proof_batch` +/// already rejects it, which is exactly what deneb's own +/// `invalid_wrong_blobs_length`/`invalid_wrong_proofs_length` fixture cases +/// exercise. +pub fn is_data_available_blobs( + commitments: &[KzgCommitment], + evidence: &DataAvailability, +) -> Result { + let (blobs, proofs) = match evidence { + DataAvailability::Blobs { blobs, proofs } => (blobs.as_slice(), proofs.as_slice()), + _ => (&[][..], &[][..]), + }; + let blob_slices: Vec<&[u8]> = blobs.iter().map(|blob| &blob[..]).collect(); + kzg::verify_blob_kzg_proof_batch(&blob_slices, commitments, proofs) +} + +/// The specification's `verify_data_column_sidecar` +/// (`specs/fulu/p2p-interface.md`): the structural checks a column sidecar +/// must pass before its KZG proofs are even worth checking. +pub fn verify_data_column_sidecar(sidecar: &fulu::DataColumnSidecar, config: &Config) -> bool { + // The sidecar index must be within the valid range. + if sidecar.index as usize >= preset::NUMBER_OF_COLUMNS { + return false; + } + // A sidecar for zero blobs is invalid. + if sidecar.kzg_commitments.is_empty() { + return false; + } + // Check that the sidecar respects the blob limit. + let epoch = compute_epoch_at_slot(sidecar.signed_block_header.message.slot); + if sidecar.kzg_commitments.len() as u64 > config.max_blobs_per_block(epoch) { + return false; + } + // The column length must be equal to the number of commitments/proofs. + sidecar.column.len() == sidecar.kzg_commitments.len() + && sidecar.column.len() == sidecar.kzg_proofs.len() +} + +/// The specification's `verify_data_column_sidecar_kzg_proofs` +/// (`specs/fulu/p2p-interface.md`): batch-verifies every cell in `sidecar`'s +/// column against its own commitment and proof. Every cell shares +/// `sidecar.index` as its cell index, since a column names one cell position +/// across every blob in the block. +pub fn verify_data_column_sidecar_kzg_proofs(sidecar: &fulu::DataColumnSidecar) -> Result { + let cell_indices = vec![sidecar.index; sidecar.column.len()]; + let mut cells = Vec::with_capacity(sidecar.column.len()); + for cell in sidecar.column.iter() { + cells.push( + c_kzg::Cell::from_bytes(&cell[..]) + .map_err(|_| Error::SpecAssert("len(cell) == BYTES_PER_CELL"))?, + ); + } + kzg::verify_cell_kzg_proof_batch( + &sidecar.kzg_commitments, + &cell_indices, + &cells, + &sidecar.kzg_proofs, + ) +} + +/// The specification's `is_data_available` for fulu +/// (`specs/fulu/fork-choice.md`): every column sidecar sampled for this +/// block must be individually valid. +/// +/// Unlike deneb's version, this takes no commitments of its own: fulu's +/// `is_data_available` does not either, since sampling checks each sidecar +/// against the commitment list it itself carries +/// ([`verify_data_column_sidecar`]) rather than the caller cross-checking a +/// separate list. An evidence value with no sidecars is vacuously +/// available, matching the specification's `all(... for ... in +/// column_sidecars)` over an empty sequence; a caller simulating "not all +/// required columns have been sampled" must reject the block itself rather +/// than relying on this to do it, since nothing about an empty list is +/// distinguishable here from "this block needed no sampling at all". +pub fn is_data_available_columns(evidence: &DataAvailability, config: &Config) -> Result { + let DataAvailability::Columns(sidecars) = evidence else { + return Ok(true); + }; + for sidecar in sidecars { + if !(verify_data_column_sidecar(sidecar, config) + && verify_data_column_sidecar_kzg_proofs(sidecar)?) + { + return Ok(false); + } + } + Ok(true) +} + +// --------------------------------------------------------------------------- +// Pull-up tip helper +// --------------------------------------------------------------------------- + +/// Eagerly computes what `block_root`'s post-state's justification and +/// finality *would* become at the next epoch boundary, without waiting for an +/// actual block at that boundary to realize it on-chain. +/// +/// This is what lets [`get_voting_source`] treat a block from a prior epoch as +/// already having the checkpoint its own chain is clearly heading towards, +/// rather than being stuck with whatever its post-state's +/// `current_justified_checkpoint` was at the moment it was imported. +pub fn compute_pulled_up_tip(store: &mut Store, block_root: Root, config: &Config) -> Result<()> { + // A clone, matching the specification's own `.copy()`: this advances a + // throwaway copy of the block's post-state to the next epoch boundary, and + // `store.block_states[block_root]` must be left exactly as the block + // itself produced it. + let mut state = store + .block_states + .get(&block_root) + .ok_or(Error::SpecAssert("block_root in store.block_states"))? + .clone(); + + // Through the fork-dispatching wrapper rather than phase0's version + // directly. Altair rewrote this step to read participation flags instead of + // replaying stored attestations, so calling phase0's against an altair or + // later state fails outright, which is what made every `fork_choice` case + // that crosses an epoch boundary fail. + stf::epoch::process_justification_and_finalization(&mut state, config)?; + + let current_justified = state.current_justified_checkpoint(); + let finalized = state.finalized_checkpoint(); + + store + .unrealized_justifications + .insert(block_root, current_justified); + update_unrealized_checkpoints(store, current_justified, finalized); + + // If the block is from a prior epoch, apply the realized values. + let block_slot = store + .blocks + .get(&block_root) + .ok_or(Error::SpecAssert("block_root in store.blocks"))? + .slot(); + let block_epoch = compute_epoch_at_slot(block_slot); + let current_epoch = get_current_store_epoch(store, config); + if block_epoch < current_epoch { + update_checkpoints(store, current_justified, finalized); + } + Ok(()) +} + +// --------------------------------------------------------------------------- +// on_tick helpers +// --------------------------------------------------------------------------- + +/// Advances `store` to `time`, one slot boundary at a time from where it was. +/// +/// `on_tick` is what actually calls this in a loop to catch up more than one +/// slot at once; called directly, `time` must already be at most one slot +/// ahead of `store`'s current slot for the "new slot" resets below to fire at +/// the right boundary. +pub fn on_tick_per_slot(store: &mut Store, time: u64, config: &Config) { + let previous_slot = get_current_slot(store, config); + + store.time = time; + + let current_slot = get_current_slot(store, config); + + // If this is a new slot, reset store.proposer_boost_root. + if current_slot > previous_slot { + store.proposer_boost_root = Root::ZERO; + } + + // If a new epoch, pull-up justification and finalization from previous + // epoch. + if current_slot > previous_slot && compute_slots_since_epoch_start(current_slot) == 0 { + update_checkpoints( + store, + store.unrealized_justified_checkpoint, + store.unrealized_finalized_checkpoint, + ); + } +} + +// --------------------------------------------------------------------------- +// on_attestation helpers +// --------------------------------------------------------------------------- + +/// Rejects an attestation whose target is not the current or previous epoch, +/// relative to `store`'s own clock. +/// +/// Only checked for attestations arriving directly (not inside a block): +/// a block-borne attestation may target an epoch that has since passed, since +/// the block itself is being processed after the fact. +/// +/// Takes `data` directly rather than an [`Attestation`]: this and +/// [`validate_on_attestation`] read nothing from an attestation besides its +/// fork-invariant `data`, so neither needs to know which of +/// [`Attestation`]'s two shapes the caller actually has. See the module +/// documentation. +pub fn validate_target_epoch_against_current_time( + store: &Store, + data: AttestationData, + config: &Config, +) -> Result<()> { + let target = data.target; + let current_epoch = get_current_store_epoch(store, config); + // Use GENESIS_EPOCH for previous when genesis to avoid underflow. + let previous_epoch = if current_epoch > constants::GENESIS_EPOCH { + current_epoch - 1 + } else { + constants::GENESIS_EPOCH + }; + verify( + target.epoch == current_epoch || target.epoch == previous_epoch, + "target.epoch in [current_epoch, previous_epoch]", + ) +} + +/// Every check `on_attestation` requires before it may look up or update +/// anything in `store`. See [`validate_target_epoch_against_current_time`] +/// for why this takes `data` rather than an [`Attestation`]. +pub fn validate_on_attestation( + store: &Store, + data: AttestationData, + is_from_block: bool, + config: &Config, +) -> Result<()> { + let target = data.target; + + // If the given attestation is not from a beacon block message, we have to + // check the target epoch scope. + if !is_from_block { + validate_target_epoch_against_current_time(store, data, config)?; + } + + // Check that the epoch number and slot number are matching. + verify( + target.epoch == compute_epoch_at_slot(data.slot), + "target.epoch == compute_epoch_at_slot(attestation.data.slot)", + )?; + + // Attestation target must be for a known block. If target block is + // unknown, delay consideration until block is found. + verify( + store.blocks.contains_key(&target.root), + "target.root in store.blocks", + )?; + + // Attestations must be for a known block. If block is unknown, delay + // consideration until the block is found. + let head_block_slot = store + .blocks + .get(&data.beacon_block_root) + .ok_or(Error::SpecAssert( + "attestation.data.beacon_block_root in store.blocks", + ))? + .slot(); + // Attestations must not be for blocks in the future. If not, the + // attestation should not be considered. + verify( + head_block_slot <= data.slot, + "store.blocks[attestation.data.beacon_block_root].slot <= attestation.data.slot", + )?; + + // LMD vote must be consistent with FFG vote target. + let checkpoint_block = get_checkpoint_block(store, data.beacon_block_root, target.epoch)?; + verify( + target.root == checkpoint_block, + "target.root == get_checkpoint_block(store, attestation.data.beacon_block_root, target.epoch)", + )?; + + // Attestations can only affect the fork choice of subsequent slots. Delay + // consideration in the fork choice until their slot is in the past. + verify( + get_current_slot(store, config) >= data.slot.saturating_add(1), + "get_current_slot(store) >= attestation.data.slot + 1", + )?; + + Ok(()) +} + +/// Caches the state at `target`'s epoch boundary if [`Store::checkpoint_state`] +/// does not already have one. +pub fn store_target_checkpoint_state( + store: &mut Store, + target: Checkpoint, + config: &Config, +) -> Result<()> { + if store.has_checkpoint_state(&target) { + return Ok(()); + } + + // A clone, matching the specification's own `copy(store.block_states[...])`: + // `process_slots` below advances this copy toward the checkpoint's epoch + // boundary in place, and `store.block_states[target.root]` must be left as + // the block itself produced it, for whatever else still reads it at its + // own slot. + let mut base_state = store + .block_states + .get(&target.root) + .ok_or(Error::SpecAssert("target.root in store.block_states"))? + .clone(); + + let target_slot = compute_start_slot_at_epoch(target.epoch); + if base_state.slot() < target_slot { + stf::process_slots(&mut base_state, target_slot, config)?; + } + + store.insert_checkpoint_state(target, base_state); + Ok(()) +} + +/// Records an attestation as each attester's latest message, for every +/// attesting index that is not a known equivocator. +/// +/// An attester's latest message only ever moves to a later target epoch: an +/// attestation for an epoch already superseded by that attester's own later +/// vote is simply not the freshest thing known about them anymore. +/// +/// Takes `attesting_indices` and `data` rather than an [`Attestation`]: by +/// the time [`on_attestation`] calls this, [`Attestation::verified_attesting_indices`] +/// has already resolved the one fork-specific fact this needed out of it. +pub fn update_latest_messages( + store: &mut Store, + attesting_indices: &[ValidatorIndex], + data: AttestationData, +) { + let target = data.target; + let beacon_block_root = data.beacon_block_root; + + for &index in attesting_indices { + if store.equivocating_indices.contains(&index) { + continue; + } + let should_update = match store.latest_messages.get(&index) { + None => true, + Some(existing) => target.epoch > existing.epoch, + }; + if should_update { + store.latest_messages.insert( + index, + LatestMessage { + epoch: target.epoch, + root: beacon_block_root, + }, + ); + } + } +} + +// --------------------------------------------------------------------------- +// Handlers +// --------------------------------------------------------------------------- +// +// These four are the only functions in this file that take `&mut Store`. +// Each validates before it mutates anything, so a rejected call leaves +// `store` exactly as it found it, matching the specification's requirement +// that "invalid calls to handlers must not modify store". + +/// Advances `store` to `time` (Unix seconds), running [`on_tick_per_slot`] +/// once per slot boundary crossed so that none of them are skipped even if +/// `time` jumps forward by more than one slot since the last call. +pub fn on_tick(store: &mut Store, time: u64, config: &Config) { + let tick_slot = time.saturating_sub(store.genesis_time) / config.seconds_per_slot; + while get_current_slot(store, config) < tick_slot { + let next_slot = get_current_slot(store, config).saturating_add(1); + let previous_time = store + .genesis_time + .saturating_add(next_slot.saturating_mul(config.seconds_per_slot)); + on_tick_per_slot(store, previous_time, config); + } + on_tick_per_slot(store, time, config); +} + +/// Validates and applies `signed_block`, adding it and its resulting +/// post-state to `store`. +/// +/// Takes `signed_block` by value rather than by reference (a departure from +/// the specification's own signature, which makes no such distinction in +/// Python): every fork's block carries its whole body, and taking ownership +/// lets it move directly into [`Store::blocks`] on success instead of being +/// cloned there. A caller that still needs its own copy afterward clones +/// before calling, same as [`Store::block_states`]'s entries do explicitly +/// inside this function. +/// +/// `blob_evidence` is this module's own addition, beyond the specification's +/// two-argument `on_block(store, signed_block)`: see [`DataAvailability`]'s +/// documentation for why deneb, electra, and fulu's data-availability check +/// needs one. A pre-deneb block, or one with no blob commitments, never +/// reads it; [`DataAvailability::NotRequired`] is the right value to pass in +/// that case. +pub fn on_block( + store: &mut Store, + signed_block: SignedBeaconBlock, + config: &Config, + blob_evidence: &DataAvailability, +) -> Result<()> { + let block_root = signed_block.message_hash_tree_root(); + let parent_root = signed_block.parent_root(); + + // Parent block must be known. + verify( + store.block_states.contains_key(&parent_root), + "block.parent_root in store.block_states", + )?; + // Make a copy of the state to avoid mutability issues: `state_transition` + // below must not be able to corrupt the parent's own post-state if this + // block turns out to be invalid partway through applying it. + let mut state = store + .block_states + .get(&parent_root) + .expect("just checked above") + .clone(); + + // Blocks cannot be in the future. If they are, their consideration must + // be delayed until they are in the past. + verify( + get_current_slot(store, config) >= signed_block.slot(), + "get_current_slot(store) >= block.slot", + )?; + + // Check that block is later than the finalized epoch slot (optimization + // to reduce calls to get_ancestor). + let finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch); + verify( + signed_block.slot() > finalized_slot, + "block.slot > finalized_slot", + )?; + // Check block is a descendant of the finalized block at the checkpoint + // finalized slot. + let finalized_checkpoint_block = + get_checkpoint_block(store, parent_root, store.finalized_checkpoint.epoch)?; + verify( + store.finalized_checkpoint.root == finalized_checkpoint_block, + "store.finalized_checkpoint.root == finalized_checkpoint_block", + )?; + + // [New in Deneb/Electra] Check if blob data is available. [New in Fulu] + // The same check, over column sidecars instead of blobs. Both run before + // `state_transition`, matching the specification's own ordering: an + // unavailable block is not even worth transitioning. + match &signed_block { + SignedBeaconBlock::Deneb(block) => { + verify( + is_data_available_blobs(&block.message.body.blob_kzg_commitments, blob_evidence)?, + "is_data_available(hash_tree_root(block), block.body.blob_kzg_commitments)", + )?; + } + SignedBeaconBlock::Electra(block) => { + verify( + is_data_available_blobs(&block.message.body.blob_kzg_commitments, blob_evidence)?, + "is_data_available(hash_tree_root(block), block.body.blob_kzg_commitments)", + )?; + } + SignedBeaconBlock::Fulu(_) => { + verify( + is_data_available_columns(blob_evidence, config)?, + "is_data_available(hash_tree_root(block))", + )?; + } + _ => {} + } + + // Check the block is valid and compute the post-state. See the module + // documentation for why this always passes `ExecutionEngine::valid`. + stf::state_transition( + &mut state, + &signed_block, + true, + config, + &stf::ExecutionEngine::valid(), + )?; + + // [New in Bellatrix] Check the merge transition block conditions. + // Capella's own `fork-choice.md` removes this check outright, so it + // applies to bellatrix alone. Reads `store.block_states[parent_root]` + // rather than `state`: that entry is still exactly the parent's own + // post-state, since `state_transition` above mutated the *clone* this + // function made of it, not the store's own copy. + if let SignedBeaconBlock::Bellatrix(block) = &signed_block { + let pre_state = store.block_states.get(&parent_root).expect("checked above"); + if stf::bellatrix::is_merge_transition_block( + pre_state, + &block.message.body.execution_payload, + )? { + validate_merge_block(store, &block.message, config)?; + } + } + + // Add new block to the store, and the new state for this block to the + // store. `block_slot` is copied out first since `signed_block` moves into + // `store.blocks` next. + let block_slot = signed_block.slot(); + store.blocks.insert(block_root, signed_block); + store.block_states.insert(block_root, state); + + // Add block timeliness to the store. + let seconds_since_genesis = store.time.saturating_sub(store.genesis_time); + let time_into_slot_ms = + seconds_to_milliseconds(seconds_since_genesis) % config.slot_duration_ms; + let epoch = get_current_store_epoch(store, config); + let attestation_threshold_ms = get_attestation_due_ms(epoch, config); + let is_before_attesting_interval = time_into_slot_ms < attestation_threshold_ms; + let is_timely = get_current_slot(store, config) == block_slot && is_before_attesting_interval; + store.block_timeliness.insert(block_root, is_timely); + + // Add proposer score boost if the block is timely and not conflicting + // with an existing block. + let is_first_block = store.proposer_boost_root.is_zero(); + if is_timely && is_first_block { + store.proposer_boost_root = block_root; + } + + // Update checkpoints in store if necessary. Read out of the post-state + // before calling `update_checkpoints`, rather than while still borrowing + // it from `store.block_states`, since that call needs `store` mutably. + let (current_justified, finalized) = { + let post_state = store + .block_states + .get(&block_root) + .expect("just inserted above"); + ( + post_state.current_justified_checkpoint(), + post_state.finalized_checkpoint(), + ) + }; + update_checkpoints(store, current_justified, finalized); + + // Eagerly compute unrealized justification and finality. + compute_pulled_up_tip(store, block_root, config)?; + + Ok(()) +} + +/// Validates `attestation` and, if valid, records it as each attester's +/// latest message. +/// +/// `is_from_block` marks an attestation carried inside a block rather than +/// received directly over gossip: [`validate_on_attestation`] skips the +/// current/previous-epoch target check for those, since a block can carry an +/// attestation for an epoch that has since passed. +pub fn on_attestation( + store: &mut Store, + attestation: &Attestation, + is_from_block: bool, + config: &Config, +) -> Result<()> { + let data = attestation.data(); + validate_on_attestation(store, data, is_from_block, config)?; + + store_target_checkpoint_state(store, data.target, config)?; + + // Get state at the `target` to fully validate attestation. The attesting + // indices are collected into an owned `Vec` before the block ends, so the + // borrow of `store.checkpoint_states` (via `target_state`) is released + // before `update_latest_messages` needs `store` mutably. + let attesting_indices = { + let target_state = store + .checkpoint_state(&data.target) + .ok_or(Error::SpecAssert( + "attestation.data.target in store.checkpoint_states", + ))?; + attestation.verified_attesting_indices(target_state)? + }; + + // Update latest messages for attesting indices. + update_latest_messages(store, &attesting_indices, data); + + Ok(()) +} + +/// Records every validator common to both halves of `attester_slashing` as +/// equivocating, once both halves are confirmed to actually be slashable and +/// individually valid. +/// +/// *Note*: the specification calls for maintaining the equivocation set from +/// at least the latest finalized checkpoint onward while syncing, which this +/// function does not enforce on its own; a caller replaying history is +/// responsible for calling this for every attester slashing it encounters +/// rather than only recent ones. +pub fn on_attester_slashing(store: &mut Store, attester_slashing: &AttesterSlashing) -> Result<()> { + let (data_1, data_2) = attester_slashing.data(); + + verify( + is_slashable_attestation_data(&data_1, &data_2), + "is_slashable_attestation_data(attestation_1.data, attestation_2.data)", + )?; + + // The attesting indices are collected into owned `Vec`s before the block + // ends, so the borrow of `store.block_states` (via `state`) is released + // before `store.equivocating_indices` needs to be mutated below. + let (indices_1, indices_2) = { + let state = store + .block_states + .get(&store.justified_checkpoint.root) + .ok_or(Error::SpecAssert( + "store.justified_checkpoint.root in store.block_states", + ))?; + attester_slashing.verified_attesting_indices(state)? + }; + + let indices_1: HashSet = indices_1.into_iter().collect(); + for index in indices_2 { + if indices_1.contains(&index) { + store.equivocating_indices.insert(index); + } + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + /// A store with every collection empty and every checkpoint at its + /// default (genesis) value. Tests fill in only the fields the function + /// under test actually reads. + fn empty_store() -> Store { + Store { + time: 0, + genesis_time: 0, + justified_checkpoint: Checkpoint::default(), + finalized_checkpoint: Checkpoint::default(), + unrealized_justified_checkpoint: Checkpoint::default(), + unrealized_finalized_checkpoint: Checkpoint::default(), + proposer_boost_root: Root::ZERO, + equivocating_indices: HashSet::new(), + blocks: HashMap::new(), + block_states: HashMap::new(), + block_timeliness: HashMap::new(), + checkpoint_states: HashMap::new(), + latest_messages: HashMap::new(), + unrealized_justifications: HashMap::new(), + pow_blocks: HashMap::new(), + } + } + + /// A signed block with an empty body and a zero signature, for tests that + /// only care about `slot` and `parent_root`. Phase0-shaped since nothing + /// under test here reads anything fork-specific. + fn block(slot: Slot, parent_root: Root) -> SignedBeaconBlock { + SignedBeaconBlock::Phase0(phase0::SignedBeaconBlock { + message: phase0::BeaconBlock { + slot, + proposer_index: 0, + parent_root, + state_root: Root::ZERO, + body: phase0::BeaconBlockBody { + randao_reveal: Default::default(), + eth1_data: Default::default(), + graffiti: Root::ZERO, + proposer_slashings: Default::default(), + attester_slashings: Default::default(), + attestations: Default::default(), + deposits: Default::default(), + voluntary_exits: Default::default(), + }, + }, + signature: Default::default(), + }) + } + + #[test] + fn get_ancestor_walks_past_an_empty_slot_gap() { + let mut store = empty_store(); + let genesis_root = Root::repeat_byte(1); + let a_root = Root::repeat_byte(2); + let b_root = Root::repeat_byte(3); + + store.blocks.insert(genesis_root, block(0, Root::ZERO)); + store.blocks.insert(a_root, block(1, genesis_root)); + // Slot 2 is empty: b's parent is a, two slots later. + store.blocks.insert(b_root, block(3, a_root)); + + // At b's own slot, b is its own ancestor. + assert_eq!(get_ancestor(&store, b_root, 3).unwrap(), b_root); + // Querying the empty slot, or a's own slot, must land on a rather + // than on b, since b's slot is strictly after both. + assert_eq!(get_ancestor(&store, b_root, 2).unwrap(), a_root); + assert_eq!(get_ancestor(&store, b_root, 1).unwrap(), a_root); + // Querying before a's slot must walk one hop further, to genesis. + assert_eq!(get_ancestor(&store, b_root, 0).unwrap(), genesis_root); + } + + #[test] + fn get_ancestor_rejects_an_unknown_root() { + let store = empty_store(); + // The specification's own KeyError-on-unknown-root is exactly the + // "unhandled exception" case it calls invalid, so this must be an + // error rather than a panic. + assert!(get_ancestor(&store, Root::repeat_byte(9), 0).is_err()); + } + + #[test] + fn compute_slots_since_epoch_start_counts_from_the_epoch_boundary() { + let epoch_start = compute_start_slot_at_epoch(3); + assert_eq!(compute_slots_since_epoch_start(epoch_start), 0); + assert_eq!(compute_slots_since_epoch_start(epoch_start + 1), 1); + assert_eq!( + compute_slots_since_epoch_start(epoch_start + preset::SLOTS_PER_EPOCH - 1), + preset::SLOTS_PER_EPOCH - 1 + ); + } + + #[test] + fn get_head_breaks_equal_weight_ties_by_higher_root() { + let config = Config::active(); + let mut store = empty_store(); + + let genesis_root = Root::repeat_byte(1); + let low_root = Root::repeat_byte(2); + let high_root = Root::repeat_byte(3); + + // Both checkpoints sit at the genesis epoch, which is what makes + // `filter_block_tree` accept any leaf unconditionally (both of its + // "correct_justified"/"correct_finalized" checks have a + // `== GENESIS_EPOCH` escape hatch): the point of this test is the + // weight tie-break in `get_head`, not the filtering rules. + store.justified_checkpoint = Checkpoint { + epoch: constants::GENESIS_EPOCH, + root: genesis_root, + }; + store.finalized_checkpoint = store.justified_checkpoint; + + store.blocks.insert(genesis_root, block(0, Root::ZERO)); + store.blocks.insert(low_root, block(1, genesis_root)); + store.blocks.insert(high_root, block(1, genesis_root)); + + // `get_weight` reads the justified checkpoint's cached state only to + // enumerate active validators; with `latest_messages` left empty, + // neither child gets any attesting balance, so both are weight zero + // and the root comparison is all that can decide between them. + let state = crate::beacon::helpers::test_state::with_validators(1); + store.insert_checkpoint_state(store.justified_checkpoint, state.clone()); + // `get_voting_source` needs a post-state for each leaf, since both + // children are in the store's current epoch (its clock is left at + // the default of slot zero) and so take the "not pulled up" branch. + store.block_states.insert(low_root, state.clone()); + store.block_states.insert(high_root, state); + + let head = get_head(&store, &config).unwrap(); + assert_eq!( + head, high_root, + "a weight tie must be broken by the lexicographically higher root" + ); + } + + #[test] + fn get_voting_source_pulls_up_a_prior_epoch_blocks_vote() { + let config = Config::active(); + let mut store = empty_store(); + // Put the store's clock two epochs ahead of the block below, so + // `get_voting_source` takes the pulled-up branch + // (`current_epoch > block_epoch`) rather than reading the block's own + // post-state directly. + store.time = config.seconds_per_slot * preset::SLOTS_PER_EPOCH * 2; + + let block_root = Root::repeat_byte(5); + store.blocks.insert(block_root, block(0, Root::ZERO)); + + let unrealized = Checkpoint { + epoch: 1, + root: Root::repeat_byte(6), + }; + let realized = Checkpoint { + epoch: 0, + root: Root::repeat_byte(7), + }; + assert_ne!( + unrealized, realized, + "the test must exercise two different values" + ); + + store + .unrealized_justifications + .insert(block_root, unrealized); + + let mut state = crate::beacon::helpers::test_state::with_validators(1); + *state.current_justified_checkpoint_mut() = realized; + store.block_states.insert(block_root, state); + + let voting_source = get_voting_source(&store, block_root, &config).unwrap(); + assert_eq!( + voting_source, unrealized, + "a block from a prior epoch must vote its pulled-up (unrealized) checkpoint" + ); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/genesis.rs b/crates/blockchain/state_transition/src/beacon/genesis.rs new file mode 100644 index 000000000..c48f444ae --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/genesis.rs @@ -0,0 +1,210 @@ +//! Genesis: building the first `BeaconState` from Eth1 deposit history, and +//! deciding when a candidate built that way is allowed to become the real +//! genesis. +//! +//! Two functions, matching the specification's own split. Building a +//! candidate never fails because the chain is not ready yet: every deposit +//! given to it is replayed exactly as the deposit contract received it, so +//! this can only produce *a* state, not necessarily one old enough or with +//! enough validators to actually start a chain. Whether it may start is +//! [`is_valid_genesis_state`]'s job, checked separately (in practice, against +//! every candidate as new Eth1 blocks arrive) so the same construction logic +//! runs whether or not this particular candidate turns out to be the one that +//! finally crosses the threshold. + +use libssz_types::SszList; + +use crate::beacon::config::Config; +use crate::beacon::constants; +use crate::beacon::containers::shared::{BeaconBlockHeader, Deposit, DepositData, Eth1Data, Fork}; +use crate::beacon::containers::{BeaconState, phase0}; +use crate::beacon::error::Result; +use crate::beacon::helpers::accessors::get_active_validator_indices; +use crate::beacon::preset; +use crate::beacon::primitives::{HashTreeRoot as _, Root, ValidatorIndex}; +use crate::beacon::stf::operations::process_deposit; + +/// The deposit data list [`initialize_beacon_state_from_eth1`] rebuilds one +/// leaf larger at every step while replaying Eth1 deposit history, so that +/// each deposit's merkle proof can be checked against the root as it stood +/// right after the deposit before it, exactly as the deposit contract's own +/// incremental tree would have it. +/// +/// Bounded by two to the power of `DEPOSIT_CONTRACT_TREE_DEPTH`, the deposit +/// contract's own tree capacity: this list can never need to hold more leaves +/// than the tree has room for. Not a preset value: the specification gives +/// this bound as an inline formula on this one list rather than as a named +/// preset entry, so it is defined here rather than in `crate::beacon::preset`. +type GenesisDepositDataList = + SszList; + +/// Builds a candidate genesis state from Eth1 deposit history. +/// +/// `deposits` must be every deposit up to and including `eth1_block_hash`, in +/// the order the deposit contract received them: each one is checked against +/// the merkle root of every deposit before it, so an out-of-order or +/// truncated history fails a later deposit's proof rather than silently +/// producing a different, still internally consistent, state. +/// +/// The result is a candidate only. Call [`is_valid_genesis_state`] on it, with +/// the same configuration, to find out whether the chain may actually start +/// from it. +pub fn initialize_beacon_state_from_eth1( + eth1_block_hash: Root, + eth1_timestamp: u64, + deposits: &[Deposit], + config: &Config, +) -> Result { + let fork = Fork { + previous_version: config.genesis_fork_version, + current_version: config.genesis_fork_version, + epoch: constants::GENESIS_EPOCH, + }; + + let empty_body_root = phase0::BeaconBlockBody { + randao_reveal: Default::default(), + eth1_data: Default::default(), + graffiti: Default::default(), + proposer_slashings: Default::default(), + attester_slashings: Default::default(), + attestations: Default::default(), + deposits: Default::default(), + voluntary_exits: Default::default(), + } + .hash_tree_root(); + + let mut state = BeaconState::Phase0(phase0::BeaconState { + // `eth1_timestamp` comes from outside the chain, so it is treated the + // same as any other externally supplied value: saturating rather than + // wrapping past `u64::MAX`. + genesis_time: eth1_timestamp.saturating_add(config.genesis_delay), + genesis_validators_root: Root::ZERO, + slot: constants::GENESIS_SLOT, + fork, + latest_block_header: BeaconBlockHeader { + body_root: empty_body_root, + ..Default::default() + }, + // The rolling root windows start zeroed: nothing has been processed + // yet for `process_slot` to have filled them with. + block_roots: vec![Root::ZERO; preset::SLOTS_PER_HISTORICAL_ROOT] + .try_into() + .expect("the vector is built at its exact length"), + state_roots: vec![Root::ZERO; preset::SLOTS_PER_HISTORICAL_ROOT] + .try_into() + .expect("the vector is built at its exact length"), + historical_roots: Default::default(), + eth1_data: Eth1Data { + deposit_root: Root::ZERO, + deposit_count: deposits.len() as u64, + block_hash: eth1_block_hash, + }, + eth1_data_votes: Default::default(), + eth1_deposit_index: 0, + validators: Default::default(), + balances: Default::default(), + // Seeded with the Eth1 block hash in every position, not only the + // first. This is deliberate: it is what makes the very first epoch's + // shuffling unpredictable before any validator has produced a randao + // reveal of its own. + randao_mixes: vec![eth1_block_hash; preset::EPOCHS_PER_HISTORICAL_VECTOR] + .try_into() + .expect("the vector is built at its exact length"), + slashings: vec![0; preset::EPOCHS_PER_SLASHINGS_VECTOR] + .try_into() + .expect("the vector is built at its exact length"), + previous_epoch_attestations: Default::default(), + current_epoch_attestations: Default::default(), + justification_bits: Default::default(), + previous_justified_checkpoint: Default::default(), + current_justified_checkpoint: Default::default(), + finalized_checkpoint: Default::default(), + }); + + // Replay deposit history, growing the merkle tree one leaf at a time so + // that `process_deposit` checks each deposit's proof against the root as + // it stood right after the deposit before it, not the final root every + // deposit would otherwise be checked against. + let mut deposit_data_list = GenesisDepositDataList::default(); + for deposit in deposits { + deposit_data_list.push(deposit.data.clone())?; + let deposit_root = deposit_data_list.hash_tree_root(); + state.eth1_data_mut().deposit_root = deposit_root; + process_deposit(&mut state, deposit, config)?; + } + + // Activate every validator whose deposits reached the cap. Genesis is the + // one moment effective balance is set directly from the raw balance + // rather than eased toward it over time: there is no previous effective + // balance yet for hysteresis to protect. + for index in 0..state.validators().len() as ValidatorIndex { + let balance = state.balance(index)?; + let effective_balance = (balance - balance % preset::EFFECTIVE_BALANCE_INCREMENT) + .min(preset::MAX_EFFECTIVE_BALANCE); + + let validator = state.validator_mut(index)?; + validator.effective_balance = effective_balance; + if effective_balance == preset::MAX_EFFECTIVE_BALANCE { + validator.activation_eligibility_epoch = constants::GENESIS_EPOCH; + validator.activation_epoch = constants::GENESIS_EPOCH; + } + } + + // Last, not first: everything above can still change which validators + // exist and what their keys are, and this root is what permanently + // separates this chain, and every signature made on it, from any other + // network that happens to run the same fork schedule. + let genesis_validators_root = state.validators().hash_tree_root(); + *state.genesis_validators_root_mut() = genesis_validators_root; + + Ok(state) +} + +/// Whether a candidate genesis state may actually become the chain's genesis. +/// +/// Checked against every candidate as Eth1 deposit history grows; the first +/// one for which this returns `true` is genesis. Both conditions are about +/// the chain being old enough and big enough to be worth starting, not about +/// the candidate being internally well-formed, which +/// [`initialize_beacon_state_from_eth1`] already guarantees by construction. +pub fn is_valid_genesis_state(state: &BeaconState, config: &Config) -> bool { + if state.genesis_time() < config.min_genesis_time { + return false; + } + let active_validator_count = + get_active_validator_indices(state, constants::GENESIS_EPOCH).len() as u64; + if active_validator_count < config.min_genesis_active_validator_count { + return false; + } + true +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn genesis_state_is_invalid_before_the_configured_genesis_time() { + let config = Config::minimal(); + let mut state = crate::beacon::helpers::test_state::with_validators( + config.min_genesis_active_validator_count as usize, + ); + + *state.genesis_time_mut() = config.min_genesis_time - 1; + assert!(!is_valid_genesis_state(&state, &config)); + + *state.genesis_time_mut() = config.min_genesis_time; + assert!(is_valid_genesis_state(&state, &config)); + } + + #[test] + fn genesis_state_is_invalid_with_too_few_active_validators() { + let config = Config::minimal(); + let mut state = crate::beacon::helpers::test_state::with_validators( + config.min_genesis_active_validator_count as usize - 1, + ); + *state.genesis_time_mut() = config.min_genesis_time; + + assert!(!is_valid_genesis_state(&state, &config)); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/hash.rs b/crates/blockchain/state_transition/src/beacon/hash.rs new file mode 100644 index 000000000..8e135994a --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/hash.rs @@ -0,0 +1,40 @@ +//! SHA-256, the specification's `hash` function. + +use sha2::{Digest, Sha256}; + +use crate::beacon::primitives::{Bytes32, H256}; + +/// The specification's `hash(data)`. +pub fn hash(data: &[u8]) -> Bytes32 { + H256(Sha256::digest(data).into()) +} + +/// Hashes the concatenation of two byte strings. +/// +/// The specification writes this as `hash(a + b)`, which appears in seed +/// derivation, the shuffling, and merkle proof verification. +pub fn hash_concat(a: &[u8], b: &[u8]) -> Bytes32 { + let mut hasher = Sha256::new(); + hasher.update(a); + hasher.update(b); + H256(hasher.finalize().into()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn matches_known_digest() { + // The SHA-256 of the empty string. + assert_eq!( + hex::encode(hash(&[]).0), + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ); + } + + #[test] + fn concat_matches_hashing_the_joined_bytes() { + assert_eq!(hash_concat(b"ab", b"cd"), hash(b"abcd")); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/helpers/accessors.rs b/crates/blockchain/state_transition/src/beacon/helpers/accessors.rs new file mode 100644 index 000000000..ef2d90dbb --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/accessors.rs @@ -0,0 +1,290 @@ +//! Beacon state accessors. +//! +//! The specification reads its constants from global scope. Here the preset +//! values are compile-time constants, but the configuration values are not, so +//! any accessor needing one takes a [`Config`]. That is the only systematic +//! difference between these signatures and the spec's. + +use crate::beacon::config::Config; +use crate::beacon::constants; +use crate::beacon::containers::BeaconState; +use crate::beacon::error::Result; +use crate::beacon::fork::ForkName; +use crate::beacon::hash::hash; +use crate::beacon::preset; +use crate::beacon::primitives::{ + Bytes32, CommitteeIndex, Domain, DomainType, Epoch, Gwei, Root, Slot, ValidatorIndex, +}; + +use super::misc::{ + compute_domain, compute_epoch_at_slot, compute_start_slot_at_epoch, fork_version_at_epoch, +}; +use super::predicates::is_active_validator; +use super::shuffling::compute_committee; + +/// The epoch the state is currently in. +pub fn get_current_epoch(state: &BeaconState) -> Epoch { + compute_epoch_at_slot(state.slot()) +} + +/// The epoch before the current one, clamped at genesis. +/// +/// Clamped rather than allowed to underflow, since the genesis epoch has no +/// predecessor but the reward and justification logic still asks for one. +pub fn get_previous_epoch(state: &BeaconState) -> Epoch { + let current = get_current_epoch(state); + if current == constants::GENESIS_EPOCH { + constants::GENESIS_EPOCH + } else { + current - 1 + } +} + +/// The block root at a recent slot. +/// +/// Fails outside the retained window: the state keeps only +/// `SLOTS_PER_HISTORICAL_ROOT` roots, so asking for an older slot is a fault +/// rather than a miss. +pub fn get_block_root_at_slot(state: &BeaconState, slot: Slot) -> Result { + crate::beacon::verify( + slot < state.slot() && state.slot() <= slot + preset::SLOTS_PER_HISTORICAL_ROOT as u64, + "slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT", + )?; + Ok(state.block_roots()[slot as usize % preset::SLOTS_PER_HISTORICAL_ROOT]) +} + +/// The block root at the start of a recent epoch, which is what a checkpoint +/// names. +pub fn get_block_root(state: &BeaconState, epoch: Epoch) -> Result { + get_block_root_at_slot(state, compute_start_slot_at_epoch(epoch)) +} + +/// The randao mix at a recent epoch. +pub fn get_randao_mix(state: &BeaconState, epoch: Epoch) -> Bytes32 { + state.randao_mix(epoch) +} + +/// The validators active at `epoch`. +pub fn get_active_validator_indices(state: &BeaconState, epoch: Epoch) -> Vec { + state + .validators() + .iter() + .enumerate() + .filter(|(_, validator)| is_active_validator(validator, epoch)) + .map(|(index, _)| index as ValidatorIndex) + .collect() +} + +/// How many validators may enter or leave per epoch. +/// +/// Proportional to the active set, with a floor, so that a small chain still +/// makes progress and a large one cannot be turned over quickly enough to +/// threaten finality. +pub fn get_validator_churn_limit(state: &BeaconState, config: &Config) -> u64 { + let active = get_active_validator_indices(state, get_current_epoch(state)).len() as u64; + config + .min_per_epoch_churn_limit + .max(active / config.churn_limit_quotient) +} + +/// The seed for `epoch` and `domain_type`. +/// +/// The mix is read from far enough back that the seed for an epoch is fixed +/// before that epoch's committees matter, which is what makes shuffling +/// unpredictable but not manipulable. The specification adds +/// `EPOCHS_PER_HISTORICAL_VECTOR` before subtracting to avoid underflowing near +/// genesis, and this keeps that form. +pub fn get_seed(state: &BeaconState, epoch: Epoch, domain_type: DomainType) -> Bytes32 { + let lookback = + epoch + preset::EPOCHS_PER_HISTORICAL_VECTOR as u64 - preset::MIN_SEED_LOOKAHEAD - 1; + let mix = get_randao_mix(state, lookback); + + let mut input = Vec::with_capacity(4 + 8 + 32); + input.extend_from_slice(&domain_type); + input.extend_from_slice(&epoch.to_le_bytes()); + input.extend_from_slice(&mix.0); + hash(&input) +} + +/// How many committees each slot of `epoch` has. +/// +/// At least one, so a small chain still produces committees, and at most +/// `MAX_COMMITTEES_PER_SLOT`. +pub fn get_committee_count_per_slot(state: &BeaconState, epoch: Epoch) -> u64 { + let active = get_active_validator_indices(state, epoch).len() as u64; + let ideal = active / preset::SLOTS_PER_EPOCH / preset::TARGET_COMMITTEE_SIZE; + ideal.clamp(1, preset::MAX_COMMITTEES_PER_SLOT as u64) +} + +/// The committee at `slot` with index `index`. +/// +/// One epoch's active set is shuffled once and then split across every slot and +/// committee of that epoch, so the committee index is a position within that +/// single split rather than an independent draw. +pub fn get_beacon_committee( + state: &BeaconState, + slot: Slot, + index: CommitteeIndex, +) -> Result> { + let epoch = compute_epoch_at_slot(slot); + let committees_per_slot = get_committee_count_per_slot(state, epoch); + let indices = get_active_validator_indices(state, epoch); + let seed = get_seed(state, epoch, constants::DOMAIN_BEACON_ATTESTER); + + compute_committee( + &indices, + seed, + (slot % preset::SLOTS_PER_EPOCH) * committees_per_slot + index, + committees_per_slot * preset::SLOTS_PER_EPOCH, + ) +} + +/// The proposer for the state's current slot, dispatching on fork for the +/// two places `compute_proposer_index` (`beacon-chain.md`'s "Misc" section) +/// changes: the acceptance test electra widens (EIP-7251), and fulu's move to +/// a precomputed lookahead window instead of a shuffle run on demand +/// (EIP-7917). +/// +/// Every fork-invariant caller in this module (block header validation, +/// RANDAO, slashing's proposer reward, and every driver in [`crate::beacon::stf`] +/// that reads a block's proposer) reaches this function unconditionally, with +/// no fork of its own to dispatch on, so the dispatch has to live here rather +/// than at each of those call sites. That is also why this cannot simply stay +/// [`super::shuffling::compute_proposer_index`] called with a different +/// `max_effective_balance`: electra's own version +/// ([`super::electra::compute_proposer_index`]) changes the width of the +/// random draw itself, not only the ceiling it is weighed against, and fulu's +/// version ([`super::fulu::get_beacon_proposer_index`]) does not shuffle at +/// all. +pub fn get_beacon_proposer_index(state: &BeaconState) -> Result { + // Fulu moves this off the read path entirely: `process_proposer_lookahead` + // (an epoch-processing step, not implemented in this module) precomputes + // the whole window ahead of time, so this becomes a lookup into it rather + // than a shuffle run now. See `crate::beacon::helpers::fulu`'s own module docs for + // why a seed, and therefore a proposer, is only ever knowable that far + // ahead of time in the first place. + if state.fork_name() == ForkName::Fulu { + return super::fulu::get_beacon_proposer_index(state); + } + + let epoch = get_current_epoch(state); + + let seed_base = get_seed(state, epoch, constants::DOMAIN_BEACON_PROPOSER); + let mut input = Vec::with_capacity(40); + input.extend_from_slice(&seed_base.0); + input.extend_from_slice(&state.slot().to_le_bytes()); + let seed = hash(&input); + + let indices = get_active_validator_indices(state, epoch); + if state.fork_name() == ForkName::Electra { + super::electra::compute_proposer_index(&indices, seed, |index| { + Ok(state.validator(index)?.effective_balance) + }) + } else { + super::shuffling::compute_proposer_index( + &indices, + seed, + preset::MAX_EFFECTIVE_BALANCE, + |index| Ok(state.validator(index)?.effective_balance), + ) + } +} + +/// The combined effective balance of `indices`. +/// +/// Floored at one increment so that callers dividing by it cannot divide by zero, +/// which is why the specification defines it this way rather than as a plain sum. +pub fn get_total_balance(state: &BeaconState, indices: &[ValidatorIndex]) -> Result { + let mut total: Gwei = 0; + for index in indices { + total = total.saturating_add(state.validator(*index)?.effective_balance); + } + Ok(total.max(preset::EFFECTIVE_BALANCE_INCREMENT)) +} + +/// The combined effective balance of the currently active validators. +pub fn get_total_active_balance(state: &BeaconState) -> Result { + let indices = get_active_validator_indices(state, get_current_epoch(state)); + get_total_balance(state, &indices) +} + +/// The signing domain for `domain_type` at `epoch`, or at the current epoch when +/// none is given. +pub fn get_domain(state: &BeaconState, domain_type: DomainType, epoch: Option) -> Domain { + let epoch = epoch.unwrap_or_else(|| get_current_epoch(state)); + let fork_version = fork_version_at_epoch(state.fork(), epoch); + compute_domain(domain_type, fork_version, state.genesis_validators_root()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn previous_epoch_is_clamped_at_genesis() { + let mut state = crate::beacon::helpers::test_state::with_validators(4); + *state.slot_mut() = 0; + assert_eq!(get_previous_epoch(&state), constants::GENESIS_EPOCH); + + *state.slot_mut() = preset::SLOTS_PER_EPOCH * 3; + assert_eq!(get_previous_epoch(&state), 2); + } + + #[test] + fn block_root_outside_the_window_is_an_error() { + let state = crate::beacon::helpers::test_state::with_validators(4); + // The current slot itself is not retained: the window is strictly past. + assert!(get_block_root_at_slot(&state, state.slot()).is_err()); + assert!(get_block_root_at_slot(&state, state.slot() - 1).is_ok()); + } + + #[test] + fn committees_cover_every_active_validator_once_per_epoch() { + // Across a whole epoch, every active validator must be assigned exactly + // one committee slot, since the epoch's committees are one permutation + // split up. + let count = 64; + let state = crate::beacon::helpers::test_state::with_validators(count); + let epoch = get_current_epoch(&state); + let per_slot = get_committee_count_per_slot(&state, epoch); + + let mut all = Vec::new(); + for slot_offset in 0..preset::SLOTS_PER_EPOCH { + let slot = compute_start_slot_at_epoch(epoch) + slot_offset; + for index in 0..per_slot { + all.extend(get_beacon_committee(&state, slot, index).unwrap()); + } + } + all.sort_unstable(); + assert_eq!(all, (0..count as u64).collect::>()); + } + + #[test] + fn total_balance_is_floored_at_one_increment() { + // An empty set must not yield zero, since callers divide by this. + let state = crate::beacon::helpers::test_state::with_validators(4); + assert_eq!( + get_total_balance(&state, &[]).unwrap(), + preset::EFFECTIVE_BALANCE_INCREMENT + ); + } + + #[test] + fn proposer_is_drawn_from_the_active_set() { + let state = crate::beacon::helpers::test_state::with_validators(32); + let proposer = get_beacon_proposer_index(&state).unwrap(); + assert!(proposer < 32); + } + + #[test] + fn churn_limit_respects_its_floor() { + let config = Config::mainnet(); + // A tiny validator set falls below the proportional limit, so the floor + // is what applies. + let state = crate::beacon::helpers::test_state::with_validators(4); + assert_eq!( + get_validator_churn_limit(&state, &config), + config.min_per_epoch_churn_limit + ); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/helpers/altair.rs b/crates/blockchain/state_transition/src/beacon/helpers/altair.rs new file mode 100644 index 000000000..d327a3d10 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/altair.rs @@ -0,0 +1,520 @@ +//! Altair's helper functions. +//! +//! Altair's two headline changes are sync committees and a rewrite of how +//! attestations earn a reward. [`get_next_sync_committee_indices`] and +//! [`get_next_sync_committee`] draw the rotating committee that lets a light +//! client follow the chain's head from a single aggregate signature rather +//! than replaying the whole state transition. Everything else here replaces +//! phase0's accumulate-then-replay `PendingAttestation`s with three +//! per-validator, per-epoch bits (a [`ParticipationFlags`]): [`add_flag`] and +//! [`has_flag`] are the bit operations, [`get_attestation_participation_flag_indices`] +//! is where an attestation earns its flags at processing time instead of +//! waiting for the epoch boundary the way phase0 does, and +//! [`get_unslashed_participating_indices`], [`get_flag_index_deltas`], and +//! [`get_inactivity_penalty_deltas`] are the epoch-boundary reward and penalty +//! accounting that reads those flags back. +//! +//! [`get_eligible_validator_indices`](super::finality::get_eligible_validator_indices) +//! and [`is_in_inactivity_leak`](super::finality::is_in_inactivity_leak) +//! are reused from phase0's rewards module rather than redefined here: the +//! specification does not modify either of them in altair, and both are +//! already written against `BeaconState`'s fork-invariant accessors rather +//! than phase0's concrete struct, so nothing about them is phase0-specific. +//! +//! # Why some functions take `config` and others do not +//! +//! Every quantity these functions read is either a specification constant, a +//! preset value, or (for [`get_inactivity_penalty_deltas`]'s +//! `INACTIVITY_SCORE_BIAS`) a configuration value: the altair specification's +//! own tables list it under "Configuration" rather than "Preset", since a +//! network is free to retune how fast an inactive validator's score rises +//! without changing the shape of any SSZ container. That is the only function +//! below that takes a [`Config`]; the rest need nothing a network could vary. + +use super::finality::{get_eligible_validator_indices, is_in_inactivity_leak}; +use crate::beacon::bls; +use crate::beacon::config::Config; +use crate::beacon::constants; +use crate::beacon::containers::shared::AttestationData; +use crate::beacon::containers::{BeaconState, altair}; +use crate::beacon::error::{Error, Result}; +use crate::beacon::fork::ForkName; +use crate::beacon::hash::hash; +use crate::beacon::preset; +use crate::beacon::primitives::{Epoch, Gwei, ParticipationFlags, ValidatorIndex}; + +use super::accessors::{ + get_active_validator_indices, get_block_root, get_block_root_at_slot, get_current_epoch, + get_previous_epoch, get_seed, get_total_active_balance, get_total_balance, +}; +use super::math::integer_squareroot; +use super::shuffling::compute_shuffled_index; + +// --------------------------------------------------------------------------- +// Misc +// --------------------------------------------------------------------------- + +/// Sets `flag_index`'s bit in `flags`, leaving every other bit as it was. +pub fn add_flag(flags: ParticipationFlags, flag_index: usize) -> ParticipationFlags { + let flag = 1u8 << flag_index; + flags | flag +} + +/// Whether `flag_index`'s bit is set in `flags`. +pub fn has_flag(flags: ParticipationFlags, flag_index: usize) -> bool { + let flag = 1u8 << flag_index; + flags & flag == flag +} + +// --------------------------------------------------------------------------- +// Beacon state accessors +// --------------------------------------------------------------------------- + +/// The sync committee indices, with possible duplicates, for the sync +/// committee period starting next epoch. +/// +/// Rejection sampling weighted by effective balance, the same shape as +/// [`super::shuffling::compute_proposer_index`]: a candidate is drawn +/// uniformly from the shuffled active set and accepted with probability +/// proportional to its effective balance. The difference is that this keeps +/// drawing until it has accepted `SYNC_COMMITTEE_SIZE` candidates rather than +/// stopping at the first one, and it never deduplicates, so the same +/// validator can end up holding more than one of the committee's seats. Both +/// of those are load-bearing: a committee member's voting weight is meant to +/// scale with effective balance, and giving a heavy validator more than one +/// seat (in expectation) is how that happens without the committee itself +/// tracking per-seat weights. +/// +/// Altair's own version of the draw, unmodified through deneb. +/// [`get_next_sync_committee`] is what chooses between this and electra's +/// widened draw, so nothing here needs to know that a later fork changes it. +pub fn get_next_sync_committee_indices(state: &BeaconState) -> Result> { + let epoch = get_current_epoch(state) + 1; + + // `2**8 - 1`, the largest value a single random byte can take. Named + // rather than left as a literal, matching `compute_proposer_index`'s + // identical rejection-sampling shape. + const MAX_RANDOM_BYTE: u64 = u8::MAX as u64; + + let active_validator_indices = get_active_validator_indices(state, epoch); + let active_validator_count = active_validator_indices.len() as u64; + crate::beacon::verify( + active_validator_count > 0, + "len(active_validator_indices) > 0", + )?; + let seed = get_seed(state, epoch, constants::DOMAIN_SYNC_COMMITTEE); + + let mut i: u64 = 0; + let mut sync_committee_indices = Vec::with_capacity(preset::SYNC_COMMITTEE_SIZE); + while sync_committee_indices.len() < preset::SYNC_COMMITTEE_SIZE { + let shuffled_index = + compute_shuffled_index(i % active_validator_count, active_validator_count, seed)?; + // `shuffled_index` is mathematically guaranteed to be within + // `active_validator_indices`, since `compute_shuffled_index` returns a + // permutation of `0..active_validator_count`; indexed directly here + // rather than defensively, the same way `compute_proposer_index` reads + // its own shuffled candidate. + let candidate_index = active_validator_indices[shuffled_index as usize]; + + let mut random_input = Vec::with_capacity(32 + 8); + random_input.extend_from_slice(&seed.0); + random_input.extend_from_slice(&(i / 32).to_le_bytes()); + let random_byte = hash(&random_input).0[(i % 32) as usize] as u64; + + let effective_balance = state.validator(candidate_index)?.effective_balance; + if effective_balance * MAX_RANDOM_BYTE >= preset::MAX_EFFECTIVE_BALANCE * random_byte { + sync_committee_indices.push(candidate_index); + } + i += 1; + } + Ok(sync_committee_indices) +} + +/// The sync committee for the period starting next epoch, with possible +/// pubkey duplicates. +/// +/// Only meant to be called at a sync committee period boundary (or when +/// upgrading a state to altair): calling it at any other slot still returns +/// an answer, but not one anything reads, since `current_sync_committee` and +/// `next_sync_committee` only change at that boundary. +/// +/// Electra's specification modifies the indices draw itself (widening the +/// acceptance test's random value from one byte to two, and swapping in +/// [`preset::MAX_EFFECTIVE_BALANCE_ELECTRA`]) rather than anything in this +/// function, so [`crate::beacon::helpers::electra::get_next_sync_committee_indices`] +/// coexists with this file's own version instead of replacing it, the same +/// way `crate::beacon::helpers::accessors::get_beacon_proposer_index` is where +/// [`crate::beacon::helpers::shuffling::compute_proposer_index`] and +/// [`crate::beacon::helpers::electra::compute_proposer_index`] are chosen between. +/// This function is that dispatch point for the sync committee draw: it is +/// the one caller every fork reaches unconditionally at the period boundary +/// (see [`crate::beacon::stf::epoch::altair::process_sync_committee_updates`]), so +/// picking the fork-appropriate indices function here, rather than in that +/// caller, is what lets fulu (which reuses this whole function) draw a +/// correctly weighted committee too. +pub fn get_next_sync_committee(state: &BeaconState) -> Result { + let indices = match state.fork_name() { + ForkName::Electra | ForkName::Fulu => { + crate::beacon::helpers::electra::get_next_sync_committee_indices(state)? + } + _ => get_next_sync_committee_indices(state)?, + }; + let mut pubkeys = Vec::with_capacity(indices.len()); + for index in &indices { + pubkeys.push(state.validator(*index)?.pubkey); + } + let aggregate_pubkey = bls::eth_aggregate_pubkeys(&pubkeys)?; + Ok(altair::SyncCommittee { + pubkeys: pubkeys.try_into()?, + aggregate_pubkey, + }) +} + +/// The reward every one-increment slice of a validator's effective balance +/// earns for a single timely, correct component of its attestation. +/// +/// Phase0 computes a reward proportional to the validator's whole effective +/// balance and divides the result by `BASE_REWARDS_PER_EPOCH` to split it +/// across the source, target, and head components. Altair instead scales +/// from this smaller, per-increment unit and multiplies back up by the +/// validator's own increment count in [`get_base_reward`], which is what lets +/// [`get_flag_index_deltas`] weight a flag's reward by how many increments of +/// stake actually earned it rather than assuming every attestation splits the +/// same fixed fraction. +pub fn get_base_reward_per_increment(state: &BeaconState) -> Result { + let total_active_balance = get_total_active_balance(state)?; + Ok( + preset::EFFECTIVE_BALANCE_INCREMENT * preset::BASE_REWARD_FACTOR + / integer_squareroot(total_active_balance), + ) +} + +/// The base reward for the validator at `index`. +/// +/// Altair's version of this function: it drops phase0's division by +/// `BASE_REWARDS_PER_EPOCH` (there is no fixed four-way split of a fixed +/// reward any more, since [`get_flag_index_deltas`] weighs each flag by +/// [`crate::beacon::constants::PARTICIPATION_FLAG_WEIGHTS`] instead) and reads +/// [`get_base_reward_per_increment`] rather than the total active balance +/// directly. See [`crate::beacon::stf::epoch::rewards::get_base_reward`] for phase0's +/// version; the two coexist in different modules rather than one replacing +/// the other, since fork dispatch happens at the call site, not here. +pub fn get_base_reward(state: &BeaconState, index: ValidatorIndex) -> Result { + let effective_balance = state.validator(index)?.effective_balance; + let increments = effective_balance / preset::EFFECTIVE_BALANCE_INCREMENT; + Ok(increments * get_base_reward_per_increment(state)?) +} + +/// The active, unslashed validators that had `flag_index` set for `epoch`. +/// +/// `epoch` must be the current or previous epoch, since those are the only +/// two altair keeps a participation record for (`current_epoch_participation` +/// and `previous_epoch_participation`, mirroring the two-epoch window phase0 +/// keeps for `PendingAttestation`s). +/// +/// Ascending and duplicate-free: it is built by filtering +/// [`get_active_validator_indices`], which already returns indices in that +/// order, so callers may binary-search it the way +/// [`get_flag_index_deltas`] does. +pub fn get_unslashed_participating_indices( + state: &BeaconState, + flag_index: usize, + epoch: Epoch, +) -> Result> { + crate::beacon::verify( + epoch == get_previous_epoch(state) || epoch == get_current_epoch(state), + "epoch in (get_previous_epoch(state), get_current_epoch(state))", + )?; + + let (previous_epoch_participation, current_epoch_participation, _) = + state.altair_validator_lists()?; + let epoch_participation = if epoch == get_current_epoch(state) { + current_epoch_participation + } else { + previous_epoch_participation + }; + + let mut participating_indices = Vec::new(); + for index in get_active_validator_indices(state, epoch) { + let flags = + epoch_participation + .get(index as usize) + .copied() + .ok_or(Error::IndexOutOfBounds { + index: index as usize, + len: epoch_participation.len(), + })?; + if has_flag(flags, flag_index) && !state.validator(index)?.slashed { + participating_indices.push(index); + } + } + Ok(participating_indices) +} + +/// Which of the three participation flags an attestation with `data`, +/// included after `inclusion_delay` slots, satisfies. +/// +/// The three checks nest: a target vote can only be timely-and-correct if the +/// source vote already was, and a head vote can only be timely-and-correct if +/// the target vote already was. That nesting is what `is_matching_target` +/// and `is_matching_head` encode by including the previous check in their own +/// condition, rather than the three being independent. +/// +/// Fails if the source does not match the justified checkpoint the target's +/// epoch should have voted from: the specification asserts this +/// unconditionally, so a caller (`process_attestation`, not implemented in +/// this file) is expected to have already rejected such an attestation before +/// this runs. +pub fn get_attestation_participation_flag_indices( + state: &BeaconState, + data: &AttestationData, + inclusion_delay: u64, +) -> Result> { + // Matching source. + let justified_checkpoint = if data.target.epoch == get_current_epoch(state) { + state.current_justified_checkpoint() + } else { + state.previous_justified_checkpoint() + }; + let is_matching_source = data.source == justified_checkpoint; + + // Matching target. + let target_root = get_block_root(state, data.target.epoch)?; + let target_root_matches = data.target.root == target_root; + let is_matching_target = is_matching_source && target_root_matches; + + // Matching head. + let head_root = get_block_root_at_slot(state, data.slot)?; + let head_root_matches = data.beacon_block_root == head_root; + let is_matching_head = is_matching_target && head_root_matches; + + crate::beacon::verify(is_matching_source, "is_matching_source")?; + + let mut participation_flag_indices = Vec::new(); + if is_matching_source && inclusion_delay <= integer_squareroot(preset::SLOTS_PER_EPOCH) { + participation_flag_indices.push(constants::TIMELY_SOURCE_FLAG_INDEX); + } + if is_matching_target && inclusion_delay <= preset::SLOTS_PER_EPOCH { + participation_flag_indices.push(constants::TIMELY_TARGET_FLAG_INDEX); + } + if is_matching_head && inclusion_delay == preset::MIN_ATTESTATION_INCLUSION_DELAY { + participation_flag_indices.push(constants::TIMELY_HEAD_FLAG_INDEX); + } + + Ok(participation_flag_indices) +} + +/// The reward and penalty for one participation flag, for every validator. +/// +/// Reuses [`get_eligible_validator_indices`] and [`is_in_inactivity_leak`] +/// from phase0's rewards module unchanged, since the specification does not +/// touch either of them in altair. +/// +/// During an inactivity leak, a matching validator earns nothing here for +/// this flag rather than the balance-weighted share the non-leaking branch +/// computes: unlike phase0 (which pays the full base reward during a leak +/// and lets [`get_inactivity_penalty_deltas`] claw an equivalent amount back), +/// altair simply withholds the reward outright, so there is nothing to claw +/// back and [`get_inactivity_penalty_deltas`] only ever penalizes. +pub fn get_flag_index_deltas( + state: &BeaconState, + flag_index: usize, +) -> Result<(Vec, Vec)> { + let validator_count = state.validators().len(); + let mut rewards = vec![0; validator_count]; + let mut penalties = vec![0; validator_count]; + + let previous_epoch = get_previous_epoch(state); + let unslashed_participating_indices = + get_unslashed_participating_indices(state, flag_index, previous_epoch)?; + let weight = constants::PARTICIPATION_FLAG_WEIGHTS[flag_index]; + let unslashed_participating_balance = + get_total_balance(state, &unslashed_participating_indices)?; + let unslashed_participating_increments = + unslashed_participating_balance / preset::EFFECTIVE_BALANCE_INCREMENT; + let active_increments = get_total_active_balance(state)? / preset::EFFECTIVE_BALANCE_INCREMENT; + + for index in get_eligible_validator_indices(state) { + let base_reward = get_base_reward(state, index)?; + if unslashed_participating_indices + .binary_search(&index) + .is_ok() + { + if !is_in_inactivity_leak(state) { + let reward_numerator = base_reward * weight * unslashed_participating_increments; + rewards[index as usize] += + reward_numerator / (active_increments * constants::WEIGHT_DENOMINATOR); + } + } else if flag_index != constants::TIMELY_HEAD_FLAG_INDEX { + penalties[index as usize] += base_reward * weight / constants::WEIGHT_DENOMINATOR; + } + } + Ok((rewards, penalties)) +} + +/// The inactivity penalty for every validator; altair pays no reward for +/// this, only a penalty, so the reward side of the pair is always zero. +/// +/// Unlike phase0's version, this does not gate on [`is_in_inactivity_leak`] +/// at all: every eligible validator missing a timely target vote pays a +/// penalty regardless of whether the chain is currently leaking. That is +/// consistent with [`get_flag_index_deltas`] no longer paying (and needing to +/// claw back) a reward during a leak; there is no cancellation left to +/// arrange here. +/// +/// Scales with `inactivity_scores`, which only the epoch-processing side of +/// altair (not implemented in this file) updates. A validator's score rises +/// without bound the longer it stays offline through a leak, so the balance +/// scaling below is checked rather than left to wrap. +/// +/// The quotient in the penalty's denominator is retuned once more after +/// altair: bellatrix's own specification modifies this exact function to +/// swap in `INACTIVITY_PENALTY_QUOTIENT_BELLATRIX`, and no fork after +/// bellatrix retunes it again, so [`preset::retuned::inactivity_penalty_quotient`] +/// is what tells altair's own value apart from every later fork's. +pub fn get_inactivity_penalty_deltas( + state: &BeaconState, + config: &Config, +) -> Result<(Vec, Vec)> { + let validator_count = state.validators().len(); + let rewards = vec![0; validator_count]; + let mut penalties = vec![0; validator_count]; + + let previous_epoch = get_previous_epoch(state); + let matching_target_indices = get_unslashed_participating_indices( + state, + constants::TIMELY_TARGET_FLAG_INDEX, + previous_epoch, + )?; + + let (_, _, inactivity_scores) = state.altair_validator_lists()?; + + for index in get_eligible_validator_indices(state) { + if matching_target_indices.binary_search(&index).is_err() { + let effective_balance = state.validator(index)?.effective_balance; + let inactivity_score = + inactivity_scores + .get(index as usize) + .copied() + .ok_or(Error::IndexOutOfBounds { + index: index as usize, + len: inactivity_scores.len(), + })?; + + let penalty_numerator = effective_balance.checked_mul(inactivity_score).ok_or( + Error::ArithmeticOverflow("effective_balance * inactivity_scores[index]"), + )?; + let inactivity_penalty_quotient = + preset::retuned::inactivity_penalty_quotient(state.fork_name()); + let penalty_denominator = config.inactivity_score_bias * inactivity_penalty_quotient; + penalties[index as usize] += penalty_numerator / penalty_denominator; + } + } + + Ok((rewards, penalties)) +} + +// --------------------------------------------------------------------------- +// Fork projection +// --------------------------------------------------------------------------- + +/// The altair state, immutably, or an error naming the function that needs one. +/// +/// There is no mutable sibling, and the reason is worth recording, because it +/// was a real bug and a tempting one. The fields altair introduces +/// (`previous_epoch_participation`, `current_epoch_participation`, +/// `inactivity_scores`, and the two sync committees) exist unchanged through +/// fulu, so a projection to a concrete `altair::BeaconState` rejects every one +/// of bellatrix through fulu with [`Error::UnsupportedForFork`]: precisely the +/// states that matter. Every reader of those fields goes through +/// [`BeaconState::altair_validator_lists`] or [`BeaconState::sync_committees`] +/// instead, which answer for every fork that carries them. +/// +/// This immutable one survives for a genuinely different reason: +/// [`crate::beacon::upgrade::upgrade_to_bellatrix`] reads an actual, concrete altair +/// state to build the bellatrix state that succeeds it. That is a real need for +/// `altair::BeaconState` specifically, and a fork-upgrade function is exactly +/// the case a per-fork projection is right for, since it only ever runs on the +/// one fork it upgrades from. +/// +/// The distinction generalises: project to a concrete per-fork state when the +/// *return type* has to be that fork's, and reach through a `BeaconState` +/// accessor when the *fields* are shared. Confusing the two produced three +/// separate bugs in this module. +pub(crate) fn altair_state_ref<'a>( + state: &'a BeaconState, + function: &'static str, +) -> Result<&'a altair::BeaconState> { + match state { + BeaconState::Altair(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// An altair state with `count` fully active, full-balance validators, + /// positioned the same way `crate::beacon::helpers::test_state::with_validators` + /// positions its phase0 state: one epoch in, so the previous epoch and the + /// block-root history window both have entries. + /// + /// A thin wrapper around the shared fork-parameterised builder: see + /// [`crate::beacon::helpers::test_state::with_validators_at`] for the construction + /// this and every other fork's test module used to duplicate. + fn altair_state_with_validators(count: usize) -> BeaconState { + crate::beacon::helpers::test_state::with_validators_at(ForkName::Altair, count) + } + + #[test] + fn has_flag_and_add_flag_round_trip_every_flag_index() { + for flag_index in [ + constants::TIMELY_SOURCE_FLAG_INDEX, + constants::TIMELY_TARGET_FLAG_INDEX, + constants::TIMELY_HEAD_FLAG_INDEX, + ] { + let flags: ParticipationFlags = 0; + assert!(!has_flag(flags, flag_index)); + let flags = add_flag(flags, flag_index); + assert!(has_flag(flags, flag_index)); + } + } + + #[test] + fn add_flag_is_idempotent() { + let once = add_flag(0, constants::TIMELY_SOURCE_FLAG_INDEX); + let twice = add_flag(once, constants::TIMELY_SOURCE_FLAG_INDEX); + assert_eq!(once, twice); + } + + #[test] + fn add_flag_leaves_other_bits_alone() { + let flags = add_flag(0, constants::TIMELY_SOURCE_FLAG_INDEX); + let flags = add_flag(flags, constants::TIMELY_TARGET_FLAG_INDEX); + assert!(has_flag(flags, constants::TIMELY_SOURCE_FLAG_INDEX)); + assert!(has_flag(flags, constants::TIMELY_TARGET_FLAG_INDEX)); + assert!(!has_flag(flags, constants::TIMELY_HEAD_FLAG_INDEX)); + } + + #[test] + fn next_sync_committee_indices_are_exactly_sync_committee_size_and_may_repeat() { + // Far fewer active validators than the sync committee has seats, so by + // the pigeonhole principle every draw with replacement must repeat + // someone, regardless of which preset the crate was built against. + let state = altair_state_with_validators(4); + let indices = get_next_sync_committee_indices(&state).unwrap(); + + assert_eq!(indices.len(), preset::SYNC_COMMITTEE_SIZE); + assert!(indices.iter().all(|index| *index < 4)); + + let mut seen = std::collections::HashSet::new(); + assert!( + indices.iter().any(|index| !seen.insert(*index)), + "drawing SYNC_COMMITTEE_SIZE seats from 4 validators must repeat someone", + ); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/helpers/attestation.rs b/crates/blockchain/state_transition/src/beacon/helpers/attestation.rs new file mode 100644 index 000000000..d103b00ec --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/attestation.rs @@ -0,0 +1,91 @@ +//! Turning an aggregate attestation into the attesters it covers. +//! +//! An [`Attestation`] names its attesters as a bitfield over a committee, which +//! is compact on the wire but useless for signature verification, since that +//! needs public keys and so needs indices. These three functions bridge the two +//! forms. +//! +//! These take phase0's attestation containers. Electra reshapes them, widening +//! the aggregation bits from one committee to a whole slot's worth and adding a +//! committee bitfield, so it gets its own versions rather than reusing these. + +use crate::beacon::containers::BeaconState; +use crate::beacon::containers::phase0::{Attestation, AttestingIndices, IndexedAttestation}; +use crate::beacon::error::Result; +use crate::beacon::helpers::accessors::{get_beacon_committee, get_domain}; +use crate::beacon::helpers::misc::compute_signing_root; +use crate::beacon::helpers::predicates::are_indices_sorted_and_unique; +use crate::beacon::primitives::{HashTreeRoot as _, ValidatorIndex}; +use crate::beacon::{bls, constants}; + +/// The committee members whose bit is set in `attestation`, in ascending order. +/// +/// The specification returns a `Set` here and sorts it in +/// [`get_indexed_attestation`]. Sorting here instead gives every caller the same +/// order, which is what they all want: `get_indexed_attestation` because +/// [`is_valid_indexed_attestation`] requires sorted indices, and the epoch +/// accounting because it treats the result as a set. +/// +/// The sort is not cosmetic. A committee is a *shuffled* slice of the validator +/// registry, so walking it in position order yields attesters in shuffle order, +/// which is almost never ascending. +pub fn get_attesting_indices( + state: &BeaconState, + attestation: &Attestation, +) -> Result> { + let committee = get_beacon_committee(state, attestation.data.slot, attestation.data.index)?; + let mut indices: Vec = committee + .into_iter() + .enumerate() + .filter(|(position, _)| attestation.aggregation_bits.get(*position).unwrap_or(false)) + .map(|(_, index)| index) + .collect(); + indices.sort_unstable(); + Ok(indices) +} + +/// The same attestation with its attesters named rather than bit-encoded. +pub fn get_indexed_attestation( + state: &BeaconState, + attestation: &Attestation, +) -> Result { + let indices = get_attesting_indices(state, attestation)?; + Ok(IndexedAttestation { + attesting_indices: AttestingIndices::try_from(indices)?, + data: attestation.data, + signature: attestation.signature, + }) +} + +/// Whether an indexed attestation names a valid attester set and carries their +/// aggregate signature. +/// +/// Empty is invalid, and so is any ordering other than sorted and unique. Both +/// checks matter for more than tidiness: a repeated index would let one validator +/// be counted twice, and an unsorted list would make the same attester set have +/// more than one encoding, and so more than one root. +pub fn is_valid_indexed_attestation( + state: &BeaconState, + indexed_attestation: &IndexedAttestation, +) -> bool { + let indices: &[ValidatorIndex] = &indexed_attestation.attesting_indices; + if indices.is_empty() || !are_indices_sorted_and_unique(indices) { + return false; + } + + let mut pubkeys = Vec::with_capacity(indices.len()); + for index in indices { + match state.validator(*index) { + Ok(validator) => pubkeys.push(validator.pubkey), + Err(_) => return false, + } + } + + let domain = get_domain( + state, + constants::DOMAIN_BEACON_ATTESTER, + Some(indexed_attestation.data.target.epoch), + ); + let signing_root = compute_signing_root(indexed_attestation.data.hash_tree_root(), domain); + bls::fast_aggregate_verify(&pubkeys, signing_root, &indexed_attestation.signature) +} diff --git a/crates/blockchain/state_transition/src/beacon/helpers/capella.rs b/crates/blockchain/state_transition/src/beacon/helpers/capella.rs new file mode 100644 index 000000000..da190912f --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/capella.rs @@ -0,0 +1,144 @@ +//! Capella's new predicates: the three checks that decide whether a validator +//! is owed a payout from the withdrawal sweep. +//! +//! Before this fork a validator's balance could shrink but never leave the +//! consensus layer, so nothing needed to ask "is this validator owed money +//! right now". Capella's sweep (`get_expected_withdrawals`, not implemented in +//! this file) asks exactly that once per validator it visits, and these three +//! predicates are the answer: [`has_eth1_withdrawal_credential`] gates the +//! other two on the validator having upgraded its withdrawal credentials at +//! all, [`is_fully_withdrawable_validator`] is true once the validator has +//! exited and its withdrawable epoch has passed, and +//! [`is_partially_withdrawable_validator`] is true for a still-active +//! validator sitting on more balance than it can earn rewards on. +//! +//! These three versions serve capella through deneb. Electra replaces all +//! three ([`crate::beacon::helpers::electra::has_execution_withdrawal_credential`], +//! `is_fully_withdrawable_validator`, `is_partially_withdrawable_validator`) +//! rather than reusing them: EIP-7251 adds a second, compounding withdrawal +//! credential prefix that the fully- and partially-withdrawable checks also +//! need to accept, and replaces the flat [`preset::MAX_EFFECTIVE_BALANCE`] +//! ceiling in the partial check with a per-validator maximum that depends on +//! which credential a validator holds. That is different enough in shape +//! (an extra prefix to check, and a ceiling that is no longer a single +//! constant) that sharing an implementation between the two forks would mean +//! threading electra's parameters through capella's call sites for no benefit +//! to either; the specification itself lists electra's versions as replacing +//! these outright rather than extending them, so this module and electra's +//! coexist rather than one calling the other. + +use crate::beacon::constants; +use crate::beacon::containers::shared::Validator; +use crate::beacon::preset; +use crate::beacon::primitives::{Epoch, Gwei}; + +/// Whether `validator`'s withdrawal credentials have been upgraded to an +/// execution address. +/// +/// Until this is true, the validator's stake has nowhere to be paid out to: +/// the raw BLS credential every validator starts with names a public key, not +/// an execution-layer account, so `has_eth1_withdrawal_credential`'s two +/// callers below both gate on it first. +pub fn has_eth1_withdrawal_credential(validator: &Validator) -> bool { + validator.withdrawal_credentials.0[0] == constants::ETH1_ADDRESS_WITHDRAWAL_PREFIX +} + +/// Whether `validator` should have its entire balance swept out. +/// +/// True once the validator is both past its withdrawable epoch (so it is done +/// being slashable, see [`super::predicates::is_slashable_validator`]) and +/// still holding a positive balance: a validator already swept to zero has +/// nothing left to pay out, so the sweep can skip it without checking the +/// epoch condition again. +pub fn is_fully_withdrawable_validator(validator: &Validator, balance: Gwei, epoch: Epoch) -> bool { + has_eth1_withdrawal_credential(validator) + && validator.withdrawable_epoch <= epoch + && balance > 0 +} + +/// Whether `validator` should have its excess balance (above +/// [`preset::MAX_EFFECTIVE_BALANCE`]) swept out while it keeps validating. +/// +/// Restricted to a validator already at the full effective balance: a +/// validator below that ceiling is still earning rewards on every increment +/// of its actual balance, so nothing above the ceiling exists yet to call +/// excess. +pub fn is_partially_withdrawable_validator(validator: &Validator, balance: Gwei) -> bool { + let has_max_effective_balance = validator.effective_balance == preset::MAX_EFFECTIVE_BALANCE; + let has_excess_balance = balance > preset::MAX_EFFECTIVE_BALANCE; + has_eth1_withdrawal_credential(validator) && has_max_effective_balance && has_excess_balance +} + +#[cfg(test)] +mod tests { + use super::*; + + fn validator_with_prefix(prefix: u8) -> Validator { + let mut withdrawal_credentials = crate::beacon::primitives::Bytes32::ZERO; + withdrawal_credentials.0[0] = prefix; + Validator { + withdrawal_credentials, + effective_balance: preset::MAX_EFFECTIVE_BALANCE, + withdrawable_epoch: 10, + ..Default::default() + } + } + + #[test] + fn only_the_eth1_prefix_counts_as_an_eth1_withdrawal_credential() { + assert!(!has_eth1_withdrawal_credential(&validator_with_prefix( + constants::BLS_WITHDRAWAL_PREFIX + ))); + assert!(has_eth1_withdrawal_credential(&validator_with_prefix( + constants::ETH1_ADDRESS_WITHDRAWAL_PREFIX + ))); + // Electra's compounding prefix is not eth1: this predicate serves + // capella through deneb only, and never sees that prefix in practice, + // but it should not be mistaken for the one it does recognize. + assert!(!has_eth1_withdrawal_credential(&validator_with_prefix( + constants::COMPOUNDING_WITHDRAWAL_PREFIX + ))); + } + + #[test] + fn full_withdrawability_needs_the_credential_the_epoch_and_a_balance() { + let validator = validator_with_prefix(constants::ETH1_ADDRESS_WITHDRAWAL_PREFIX); + + // Before the withdrawable epoch: not yet. + assert!(!is_fully_withdrawable_validator(&validator, 1, 5)); + // At and after the withdrawable epoch, with a balance: withdrawable. + assert!(is_fully_withdrawable_validator(&validator, 1, 10)); + assert!(is_fully_withdrawable_validator(&validator, 1, 20)); + // Nothing left to pay out. + assert!(!is_fully_withdrawable_validator(&validator, 0, 20)); + + // Without the eth1 credential, never withdrawable regardless of epoch + // or balance. + let bls_validator = validator_with_prefix(constants::BLS_WITHDRAWAL_PREFIX); + assert!(!is_fully_withdrawable_validator(&bls_validator, 1, 20)); + } + + #[test] + fn partial_withdrawability_needs_the_credential_and_excess_above_the_ceiling() { + let mut validator = validator_with_prefix(constants::ETH1_ADDRESS_WITHDRAWAL_PREFIX); + + // At the ceiling, no excess yet. + assert!(!is_partially_withdrawable_validator( + &validator, + preset::MAX_EFFECTIVE_BALANCE + )); + // Above the ceiling: the excess is withdrawable. + assert!(is_partially_withdrawable_validator( + &validator, + preset::MAX_EFFECTIVE_BALANCE + 1 + )); + + // Below the full effective balance, excess balance does not count: + // the validator has not maxed out what it can earn rewards on yet. + validator.effective_balance -= 1; + assert!(!is_partially_withdrawable_validator( + &validator, + preset::MAX_EFFECTIVE_BALANCE + 1 + )); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/helpers/electra.rs b/crates/blockchain/state_transition/src/beacon/helpers/electra.rs new file mode 100644 index 000000000..67f9de328 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/electra.rs @@ -0,0 +1,1409 @@ +//! Electra's new and changed helper functions. +//! +//! Electra's headline change is EIP-7251: a validator's effective balance is no +//! longer pinned to one value. A validator that upgrades its withdrawal +//! credentials to the new compounding prefix +//! ([`constants::COMPOUNDING_WITHDRAWAL_PREFIX`]) can hold up to +//! [`preset::MAX_EFFECTIVE_BALANCE_ELECTRA`] rather than the fixed +//! `MAX_EFFECTIVE_BALANCE` every validator was capped at before. Nearly every +//! function below exists because of that one change, in three groups. +//! +//! **The withdrawal credential predicates** ([`is_compounding_withdrawal_credential`], +//! [`has_compounding_withdrawal_credential`], [`has_execution_withdrawal_credential`], +//! and [`get_max_effective_balance`]) are what let [`is_fully_withdrawable_validator`] +//! and [`is_partially_withdrawable_validator`] ask "what is this validator's +//! ceiling" instead of assuming one fixed answer for everyone. +//! [`has_eth1_withdrawal_credential`] is transcribed here too even though +//! electra does not touch it: it is capella's predicate +//! (`specs/capella/beacon-chain.md`), needed unmodified by +//! [`has_execution_withdrawal_credential`], and this module has no shared +//! cross-fork module to put a single reused predicate in instead. +//! +//! **The churn limit becomes balance-based.** Phase0 rate-limits activation and +//! exit by counting validators: at most one fixed-size churn limit's worth of +//! them may enter or leave the registry per epoch, and every validator counts +//! the same because every validator's effective balance was the same. Once a +//! single validator can hold what used to be dozens of validators' worth of +//! stake, counting validators no longer bounds how much *stake* can move in +//! one epoch: one compounding validator's exit could strand as much +//! finality-relevant weight as an old-style validator committee's worth all at +//! once. So electra rebuilds the limit in Gwei instead of a headcount. +//! [`get_balance_churn_limit`] is phase0's `get_validator_churn_limit` with +//! that swap, and [`get_activation_exit_churn_limit`] and +//! [`get_consolidation_churn_limit`] split that one Gwei budget between the +//! two things competing for it, so a busy exit queue cannot alone starve +//! consolidations (or the reverse). +//! +//! **The exit and consolidation queues track a spendable balance, not just a +//! target epoch.** Phase0's exit queue only ever needed an epoch, since every +//! validator consumed the same one "seat" of churn and the queue epoch was +//! answer enough. A balance-based limit cannot work that way: two small exits +//! in the same epoch might together still fit under that epoch's churn, even +//! though the first one alone already used most of it, while a single huge +//! exit might need several epochs' worth of churn before it can go through at +//! all. [`compute_exit_epoch_and_update_churn`] and +//! [`compute_consolidation_epoch_and_update_churn`] carry that as an +//! `(earliest_epoch, balance_to_consume)` cursor on the state: +//! `balance_to_consume` is how much of `earliest_epoch`'s budget is still +//! unspent, refilled to a full epoch's churn only once an exit or +//! consolidation actually needs to push the cursor past the epoch it +//! currently sits on. [`initiate_validator_exit`] replaces phase0's version +//! (`crate::beacon::helpers::mutators::initiate_validator_exit`) with one that defers +//! to [`compute_exit_epoch_and_update_churn`] instead of scanning every +//! validator's `exit_epoch` to find the queue's current occupancy. +//! +//! [`switch_to_compounding_validator`] and [`queue_excess_active_balance`] are +//! the deposit side of the same change: raising a validator's ceiling, or a +//! deposit that pushes a validator's balance above +//! [`preset::MIN_ACTIVATION_BALANCE`], both risk crediting a large amount of +//! new active stake in a single slot, so rather than applying the balance +//! immediately, both instead queue the excess as a +//! [`electra::PendingDeposit`] that epoch processing (not implemented in this +//! file) drains a bounded amount of at a time. +//! [`queue_entire_balance_and_reset_validator`] is the same queue-then-drain +//! pattern applied to a whole balance rather than an excess over a ceiling. +//! It is **not** itself a named helper in `specs/electra/beacon-chain.md`: +//! it is extracted verbatim from a loop body in `specs/electra/fork.md`'s +//! `upgrade_to_electra` (the fork-upgrade function, implemented elsewhere in +//! this module), which resets every not-yet-activated validator's balance to +//! zero at the fork boundary and queues the whole amount as a pending +//! deposit rather than losing it. It is factored out here so the +//! fork-upgrade code does not have to duplicate +//! [`queue_excess_active_balance`]'s pending-deposit construction by hand. +//! +//! **[`get_attesting_indices`], [`get_indexed_attestation`], and +//! [`is_valid_indexed_attestation`]** exist here, rather than reusing +//! [`crate::beacon::helpers::attestation`]'s phase0 versions, for an unrelated reason +//! (EIP-7549, not EIP-7251): from electra on, one [`electra::Attestation`] +//! can name every committee in a slot instead of one, via the new +//! `committee_bits` field, so `aggregation_bits` widens to match and the +//! function reading attester positions out of it has to walk each named +//! committee at its own offset within that wider bitfield. See +//! [`crate::beacon::helpers::attestation`]'s module doc for why phase0's versions do +//! not generalize (different concrete container types, not just a wider +//! bound), and [`get_attesting_indices`]'s own doc for the offset arithmetic. +//! +//! [`compute_proposer_index`] and [`get_next_sync_committee_indices`] are not +//! on this module's list of required electra signatures, but this file adds +//! them anyway: electra's specification modifies both of them (widening the +//! acceptance test's random draw from one byte to two, and swapping in +//! [`preset::MAX_EFFECTIVE_BALANCE_ELECTRA`]), both fall within this file's +//! assigned "Predicates" and "Beacon state accessors" sections of +//! `specs/electra/beacon-chain.md`, and every electra (and fulu) block needs a +//! correctly weighted proposer draw and, at the sync committee period +//! boundary, a correctly weighted committee draw. They mirror +//! [`crate::beacon::helpers::shuffling::compute_proposer_index`] and +//! [`crate::beacon::helpers::altair::get_next_sync_committee_indices`] respectively, +//! which remain phase0's and altair's own unmodified versions for the earlier +//! forks that still use them. +//! +//! [`crate::beacon::helpers::accessors::get_beacon_proposer_index`] is what actually +//! reaches [`compute_proposer_index`] for an electra state (fulu reads +//! `proposer_lookahead` instead, precomputed through this same function by +//! [`crate::beacon::helpers::fulu::compute_proposer_indices`]): that accessor is the +//! one call site every fork-invariant caller of "the" proposer index already +//! goes through unconditionally, so it is where the fork dispatch lives +//! rather than in each of those callers. +//! +//! # The fork projection +//! +//! `pending_deposits`, `pending_partial_withdrawals`, `exit_balance_to_consume`, +//! `earliest_exit_epoch`, `consolidation_balance_to_consume`, and +//! `earliest_consolidation_epoch` are state fields with no fork-invariant +//! accessor on [`BeaconState`]. Unlike altair's participation flags (see +//! [`crate::beacon::helpers::altair::altair_state`]'s doc), these fields are not +//! electra-only: fulu keeps every one of them unchanged (see the [`fulu`] +//! module doc), so [`electra_state`] and [`electra_state_ref`] match both +//! `BeaconState::Electra` and `BeaconState::Fulu` rather than only the +//! former. A projection that matched only `Electra`, the way +//! [`crate::beacon::helpers::altair::altair_state`] matches only `Altair`, would +//! silently break every one of these functions on a fulu state, which is the +//! single easiest mistake to make copying that shape without also copying +//! the reasoning behind it. + +use crate::beacon::bls; +use crate::beacon::config::Config; +use crate::beacon::constants::{self, FAR_FUTURE_EPOCH}; +use crate::beacon::containers::shared::Validator; +use crate::beacon::containers::{BeaconState, electra, fulu}; +use crate::beacon::error::{Error, Result}; +use crate::beacon::hash::hash; +use crate::beacon::preset; +use crate::beacon::primitives::{ + BLS_SIGNATURE_SIZE, BlsSignature, Bytes32, CommitteeIndex, Epoch, Gwei, HashTreeRoot as _, + ValidatorIndex, +}; + +use super::accessors::{ + get_active_validator_indices, get_beacon_committee, get_current_epoch, get_domain, get_seed, + get_total_active_balance, +}; +use super::math::bytes_to_uint64; +use super::misc::{compute_activation_exit_epoch, compute_signing_root}; +use super::predicates::are_indices_sorted_and_unique; +use super::shuffling::compute_shuffled_index; + +// --------------------------------------------------------------------------- +// Predicates +// --------------------------------------------------------------------------- + +/// Whether `validator` has an `0x01`-prefixed "eth1" withdrawal credential. +/// +/// Capella's predicate, not electra's: transcribed from +/// `specs/capella/beacon-chain.md` because [`has_execution_withdrawal_credential`] +/// needs it unmodified and this module has nowhere else to put a single +/// cross-fork predicate reused this way. +pub fn has_eth1_withdrawal_credential(validator: &Validator) -> bool { + validator.withdrawal_credentials.0[0] == constants::ETH1_ADDRESS_WITHDRAWAL_PREFIX +} + +/// Whether `withdrawal_credentials` is `0x02`-prefixed ("compounding"). +pub fn is_compounding_withdrawal_credential(withdrawal_credentials: Bytes32) -> bool { + withdrawal_credentials.0[0] == constants::COMPOUNDING_WITHDRAWAL_PREFIX +} + +/// Whether `validator` has an `0x02`-prefixed "compounding" withdrawal +/// credential. +pub fn has_compounding_withdrawal_credential(validator: &Validator) -> bool { + is_compounding_withdrawal_credential(validator.withdrawal_credentials) +} + +/// Whether `validator` has an `0x01`- or `0x02`-prefixed withdrawal +/// credential, i.e. can actually receive a withdrawal at all (an +/// un-upgraded `0x00` BLS credential cannot). +pub fn has_execution_withdrawal_credential(validator: &Validator) -> bool { + has_eth1_withdrawal_credential(validator) || has_compounding_withdrawal_credential(validator) +} + +/// Whether `validator` is fully withdrawable at `epoch`. +/// +/// Modified from phase0/capella only in which credential predicate it uses: +/// [`has_execution_withdrawal_credential`] accepts either upgraded prefix +/// rather than only the `0x01` one, since a compounding validator is just as +/// withdrawable as an eth1 one once past its `withdrawable_epoch`. +pub fn is_fully_withdrawable_validator(validator: &Validator, balance: Gwei, epoch: Epoch) -> bool { + has_execution_withdrawal_credential(validator) + && validator.withdrawable_epoch <= epoch + && balance > 0 +} + +/// Whether `validator` is partially withdrawable, i.e. sitting at its own +/// ceiling with a real excess balance above it. +/// +/// Modified from phase0/capella to compare against +/// [`get_max_effective_balance`] rather than the single fixed +/// `MAX_EFFECTIVE_BALANCE`: a compounding validator's "at the ceiling, with +/// excess above it" now means its own, higher ceiling, not everyone else's. +pub fn is_partially_withdrawable_validator(validator: &Validator, balance: Gwei) -> bool { + let max_effective_balance = get_max_effective_balance(validator); + let has_max_effective_balance = validator.effective_balance == max_effective_balance; + let has_excess_balance = balance > max_effective_balance; + has_execution_withdrawal_credential(validator) + && has_max_effective_balance + && has_excess_balance +} + +/// Whether `validator` may join the activation queue. +/// +/// Modified from phase0's version (`crate::beacon::helpers::predicates::is_eligible_for_activation_queue`) +/// to require only [`preset::MIN_ACTIVATION_BALANCE`] or more, rather than +/// exactly the old `MAX_EFFECTIVE_BALANCE`: electra's minimum activation +/// balance is deliberately lower than the new compounding ceiling, so a +/// validator can activate well before it ever tops out. +pub fn is_eligible_for_activation_queue(validator: &Validator) -> bool { + validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH + && validator.effective_balance >= preset::MIN_ACTIVATION_BALANCE +} + +/// Electra's replacement for [`crate::beacon::helpers::shuffling::compute_proposer_index`]: +/// a proposer sampled from `indices`, weighted by effective balance. +/// +/// Two things change from phase0's version, both from EIP-7251. The +/// acceptance test compares against [`preset::MAX_EFFECTIVE_BALANCE_ELECTRA`] +/// rather than a caller-supplied (and necessarily lower, pre-electra) ceiling, +/// since a compounding validator's effective balance can now actually reach +/// that higher value. And the random draw widens from a single random byte to +/// a two-byte (16-bit) value: an 8-bit draw can only ever resolve balance +/// differences to one part in 256, which was fine when every validator's +/// effective balance sat at the same value, but is too coarse a filter now +/// that effective balance can vary by a factor of dozens. +/// +/// Like the phase0 version, this takes `effective_balance_of` rather than a +/// state directly, so it stays independent of which fork's state it reads. +pub fn compute_proposer_index( + indices: &[ValidatorIndex], + seed: Bytes32, + mut effective_balance_of: impl FnMut(ValidatorIndex) -> Result, +) -> Result { + crate::beacon::verify(!indices.is_empty(), "len(indices) > 0")?; + + // `2**16 - 1`, the largest value a two-byte little-endian draw can take. + const MAX_RANDOM_VALUE: u64 = u16::MAX as u64; + let total = indices.len() as u64; + + let mut i = 0u64; + loop { + let shuffled = compute_shuffled_index(i % total, total, seed)?; + let candidate = indices[shuffled as usize]; + + let mut random_input = Vec::with_capacity(32 + 8); + random_input.extend_from_slice(&seed.0); + random_input.extend_from_slice(&(i / 16).to_le_bytes()); + let random_bytes = hash(&random_input); + let offset = ((i % 16) * 2) as usize; + let random_value = bytes_to_uint64(&random_bytes.0[offset..offset + 2]); + + let effective_balance = effective_balance_of(candidate)?; + if effective_balance * MAX_RANDOM_VALUE + >= preset::MAX_EFFECTIVE_BALANCE_ELECTRA * random_value + { + return Ok(candidate); + } + + i += 1; + } +} + +/// Whether an indexed attestation names a valid attester set and carries +/// their aggregate signature. +/// +/// Logic identical to [`crate::beacon::helpers::attestation::is_valid_indexed_attestation`]; +/// this exists as its own copy only because [`electra::IndexedAttestation`] +/// is a different concrete type from phase0's `IndexedAttestation`, bounded +/// by `MAX_VALIDATORS_PER_SLOT` rather than `MAX_VALIDATORS_PER_COMMITTEE` +/// (EIP-7549: one electra attestation can span every committee in a slot). +pub fn is_valid_indexed_attestation( + state: &BeaconState, + indexed_attestation: &electra::IndexedAttestation, +) -> bool { + let indices: &[ValidatorIndex] = &indexed_attestation.attesting_indices; + if indices.is_empty() || !are_indices_sorted_and_unique(indices) { + return false; + } + + let mut pubkeys = Vec::with_capacity(indices.len()); + for index in indices { + match state.validator(*index) { + Ok(validator) => pubkeys.push(validator.pubkey), + Err(_) => return false, + } + } + + let domain = get_domain( + state, + constants::DOMAIN_BEACON_ATTESTER, + Some(indexed_attestation.data.target.epoch), + ); + let signing_root = compute_signing_root(indexed_attestation.data.hash_tree_root(), domain); + bls::fast_aggregate_verify(&pubkeys, signing_root, &indexed_attestation.signature) +} + +// --------------------------------------------------------------------------- +// Misc +// --------------------------------------------------------------------------- + +/// The committee indices `committee_bits` names, i.e. the positions of its +/// set bits, in ascending order. +/// +/// [`get_attesting_indices`] reads this to know which committees an +/// [`electra::Attestation`] covers and in what order its widened +/// `aggregation_bits` names their members. +pub fn get_committee_indices(committee_bits: &electra::CommitteeBits) -> Vec { + (0..committee_bits.len()) + .filter(|&index| committee_bits.get(index).unwrap_or(false)) + .map(|index| index as CommitteeIndex) + .collect() +} + +/// The effective balance ceiling for `validator`: the higher +/// [`preset::MAX_EFFECTIVE_BALANCE_ELECTRA`] for a compounding validator, or +/// [`preset::MIN_ACTIVATION_BALANCE`] for everyone else. +/// +/// Named "max effective balance" rather than "ceiling" to match the +/// specification, even though [`preset::MIN_ACTIVATION_BALANCE`] is also the +/// minimum a validator needs to activate at all: pre-electra those two +/// numbers were different constants that happened never to both matter to +/// the same validator at once, and electra reuses the minimum as the +/// non-compounding ceiling rather than introducing a third value. +pub fn get_max_effective_balance(validator: &Validator) -> Gwei { + if has_compounding_withdrawal_credential(validator) { + preset::MAX_EFFECTIVE_BALANCE_ELECTRA + } else { + preset::MIN_ACTIVATION_BALANCE + } +} + +// --------------------------------------------------------------------------- +// Beacon state accessors +// --------------------------------------------------------------------------- + +/// The churn limit for the current epoch, in Gwei. +/// +/// Phase0's `get_validator_churn_limit` +/// (`crate::beacon::helpers::accessors::get_validator_churn_limit`) counts +/// validators, which only bounds a balance amount because every validator's +/// effective balance used to be the same fixed value. Once a compounding +/// validator can hold up to `MAX_EFFECTIVE_BALANCE_ELECTRA`, the same +/// headcount no longer bounds the same amount of stake, so this counts Gwei +/// directly instead: the same fraction of total active balance +/// (`CHURN_LIMIT_QUOTIENT`), floored at +/// [`Config::min_per_epoch_churn_limit_electra`] rather than a +/// validator-count floor, and rounded down to a whole +/// `EFFECTIVE_BALANCE_INCREMENT` so the budget always divides evenly into the +/// unit every balance change is already rounded to. +pub fn get_balance_churn_limit(state: &BeaconState, config: &Config) -> Result { + let total_active_balance = get_total_active_balance(state)?; + let churn = config + .min_per_epoch_churn_limit_electra + .max(total_active_balance / config.churn_limit_quotient); + Ok(churn - churn % preset::EFFECTIVE_BALANCE_INCREMENT) +} + +/// The portion of [`get_balance_churn_limit`] set aside for activations and +/// exits, as opposed to consolidations. +/// +/// Capped separately from the combined budget +/// ([`Config::max_per_epoch_activation_exit_churn_limit`]) so that on a very +/// large validator set, activations and exits cannot alone consume the whole +/// churn budget and starve consolidations of any share at all. +pub fn get_activation_exit_churn_limit(state: &BeaconState, config: &Config) -> Result { + Ok(config + .max_per_epoch_activation_exit_churn_limit + .min(get_balance_churn_limit(state, config)?)) +} + +/// The portion of [`get_balance_churn_limit`] left over for consolidations +/// once [`get_activation_exit_churn_limit`] has taken its share. +pub fn get_consolidation_churn_limit(state: &BeaconState, config: &Config) -> Result { + let balance_churn_limit = get_balance_churn_limit(state, config)?; + let activation_exit_churn_limit = get_activation_exit_churn_limit(state, config)?; + // `get_activation_exit_churn_limit` is a `min` against `balance_churn_limit`, + // so it can never exceed it, and this subtraction cannot underflow. + Ok(balance_churn_limit - activation_exit_churn_limit) +} + +/// The total amount queued in [`electra::PendingPartialWithdrawal`]s for +/// `index`, not yet paid out. +/// +/// Read by electra's execution layer consolidation request processing (not +/// implemented in this file) to refuse consolidating a validator that still +/// has a partial withdrawal in flight: consolidating it out from under that +/// withdrawal would leave nothing left to pay the withdrawal from. +pub fn get_pending_balance_to_withdraw(state: &BeaconState, index: ValidatorIndex) -> Result { + let fields = electra_state_ref(state, "get_pending_balance_to_withdraw")?; + let mut total: Gwei = 0; + for withdrawal in fields.pending_partial_withdrawals().iter() { + if withdrawal.validator_index == index { + total = total.saturating_add(withdrawal.amount); + } + } + Ok(total) +} + +/// The committee members whose bit is set in `attestation`, in ascending +/// order. +/// +/// EIP-7549 moves the committee index out of `AttestationData` and lets one +/// attestation cover every committee in a slot, so `aggregation_bits` is now +/// the concatenation of each named committee's member bits, in the same +/// ascending committee-index order [`get_committee_indices`] returns them +/// in. Reading attester `position` out of committee `committee_index`'s +/// segment therefore means indexing `aggregation_bits` at `committee_offset + +/// position`, where `committee_offset` is the total length of every +/// previously-*named* committee, not the committee's own index or position +/// in the loop: a naive `committee_index * committee_size` offset would +/// misalign as soon as two named committees differ in size, and skipping an +/// *unnamed* committee (one whose bit is clear in `committee_bits`) must not +/// advance the offset at all, since that committee's members never appear in +/// `aggregation_bits` to begin with. Accumulating `committee_offset` from +/// each named committee's own `len()`, in the order [`get_committee_indices`] +/// visits them, is what keeps the running offset correct regardless of which +/// (possibly non-contiguous) committee indices are actually named. +/// +/// Sorted at the end for the same reason +/// [`crate::beacon::helpers::attestation::get_attesting_indices`] sorts: the +/// specification returns a set, and a committee is a *shuffled* slice of the +/// registry, so reading one in position order yields attester indices in +/// shuffle order, almost never ascending. Not deduplicated: a slot's +/// committees partition its active set (see +/// `crate::beacon::helpers::accessors`'s +/// `committees_cover_every_active_validator_once_per_epoch` test), so the +/// same validator index cannot appear under two different named committees, +/// and a single committee cannot name the same position twice. +pub fn get_attesting_indices( + state: &BeaconState, + attestation: &electra::Attestation, +) -> Result> { + let committee_indices = get_committee_indices(&attestation.committee_bits); + + let mut indices = Vec::new(); + let mut committee_offset = 0usize; + for committee_index in committee_indices { + let committee = get_beacon_committee(state, attestation.data.slot, committee_index)?; + for (position, attester_index) in committee.iter().enumerate() { + let bit = committee_offset + position; + if attestation.aggregation_bits.get(bit).unwrap_or(false) { + indices.push(*attester_index); + } + } + committee_offset += committee.len(); + } + + indices.sort_unstable(); + Ok(indices) +} + +/// The same attestation with its attesters named rather than bit-encoded. +pub fn get_indexed_attestation( + state: &BeaconState, + attestation: &electra::Attestation, +) -> Result { + let indices = get_attesting_indices(state, attestation)?; + Ok(electra::IndexedAttestation { + attesting_indices: electra::AttestingIndices::try_from(indices)?, + data: attestation.data, + signature: attestation.signature, + }) +} + +/// Electra's replacement for +/// [`crate::beacon::helpers::altair::get_next_sync_committee_indices`]: the sync +/// committee indices, with possible duplicates, for the sync committee +/// period starting next epoch. +/// +/// Same EIP-7251 change as [`compute_proposer_index`]: the acceptance test's +/// ceiling becomes [`preset::MAX_EFFECTIVE_BALANCE_ELECTRA`] and its random +/// draw widens from one byte to two, for the same reasons. +pub fn get_next_sync_committee_indices(state: &BeaconState) -> Result> { + let epoch = get_current_epoch(state) + 1; + + // `2**16 - 1`, the largest value a two-byte little-endian draw can take. + const MAX_RANDOM_VALUE: u64 = u16::MAX as u64; + + let active_validator_indices = get_active_validator_indices(state, epoch); + let active_validator_count = active_validator_indices.len() as u64; + crate::beacon::verify( + active_validator_count > 0, + "len(active_validator_indices) > 0", + )?; + let seed = get_seed(state, epoch, constants::DOMAIN_SYNC_COMMITTEE); + + let mut i: u64 = 0; + let mut sync_committee_indices = Vec::with_capacity(preset::SYNC_COMMITTEE_SIZE); + while sync_committee_indices.len() < preset::SYNC_COMMITTEE_SIZE { + let shuffled_index = + compute_shuffled_index(i % active_validator_count, active_validator_count, seed)?; + let candidate_index = active_validator_indices[shuffled_index as usize]; + + let mut random_input = Vec::with_capacity(32 + 8); + random_input.extend_from_slice(&seed.0); + random_input.extend_from_slice(&(i / 16).to_le_bytes()); + let random_bytes = hash(&random_input); + let offset = ((i % 16) * 2) as usize; + let random_value = bytes_to_uint64(&random_bytes.0[offset..offset + 2]); + + let effective_balance = state.validator(candidate_index)?.effective_balance; + if effective_balance * MAX_RANDOM_VALUE + >= preset::MAX_EFFECTIVE_BALANCE_ELECTRA * random_value + { + sync_committee_indices.push(candidate_index); + } + i += 1; + } + Ok(sync_committee_indices) +} + +// --------------------------------------------------------------------------- +// Beacon state mutators +// --------------------------------------------------------------------------- + +/// Puts a validator into the exit queue. +/// +/// Modified from phase0's version +/// (`crate::beacon::helpers::mutators::initiate_validator_exit`) to compute the exit +/// epoch through [`compute_exit_epoch_and_update_churn`] instead of scanning +/// every validator's `exit_epoch` for the queue's current occupancy: that +/// scan counted validators, which stopped being a valid proxy for churned +/// balance the moment validators stopped all weighing the same. +pub fn initiate_validator_exit( + state: &mut BeaconState, + index: ValidatorIndex, + config: &Config, +) -> Result<()> { + if state.validator(index)?.exit_epoch != FAR_FUTURE_EPOCH { + return Ok(()); + } + + let effective_balance = state.validator(index)?.effective_balance; + let exit_queue_epoch = compute_exit_epoch_and_update_churn(state, effective_balance, config)?; + + // See `crate::beacon::helpers::mutators::initiate_validator_exit` for why this is + // checked rather than left to wrap: a validator already queued with an + // exit epoch close to `FAR_FUTURE_EPOCH` could otherwise overflow into a + // withdrawable epoch in the past. + let withdrawable = exit_queue_epoch + .checked_add(config.min_validator_withdrawability_delay) + .ok_or(Error::ArithmeticOverflow( + "exit_queue_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY", + ))?; + + let validator = state.validator_mut(index)?; + validator.exit_epoch = exit_queue_epoch; + validator.withdrawable_epoch = withdrawable; + Ok(()) +} + +/// Advances electra's exit-queue cursor for an exit of `exit_balance`, +/// returning the epoch it may take effect at. +/// +/// This is where the "balance to consume" cursor this module's doc describes +/// actually lives: `earliest_exit_epoch` is the earliest epoch that still has +/// unspent churn, and `exit_balance_to_consume` is how much of that epoch's +/// budget remains. A new epoch's budget is only opened (refilled to a full +/// [`get_activation_exit_churn_limit`]) once the cursor actually needs to move +/// past the epoch it currently sits on; until then, a later, smaller exit in +/// the same epoch spends whatever an earlier one left over instead of always +/// waiting for a fresh epoch. +pub fn compute_exit_epoch_and_update_churn( + state: &mut BeaconState, + exit_balance: Gwei, + config: &Config, +) -> Result { + let current_epoch = get_current_epoch(state); + let per_epoch_churn = get_activation_exit_churn_limit(state, config)?; + + let mut fields = electra_state(state, "compute_exit_epoch_and_update_churn")?; + + let mut earliest_exit_epoch = fields + .earliest_exit_epoch() + .max(compute_activation_exit_epoch(current_epoch)); + + // A later epoch than the cursor currently sits on: that epoch has not + // spent any of its churn yet, so its budget starts full. Otherwise the + // cursor has not moved, and whatever it left unspent carries over. + let mut exit_balance_to_consume = if fields.earliest_exit_epoch() < earliest_exit_epoch { + per_epoch_churn + } else { + fields.exit_balance_to_consume() + }; + + if exit_balance > exit_balance_to_consume { + let balance_to_process = exit_balance - exit_balance_to_consume; + // Ceiling division: how many additional epochs' worth of churn this + // exit needs beyond what the current epoch has left. + let additional_epochs = balance_to_process + .checked_sub(1) + .and_then(|value| value.checked_div(per_epoch_churn)) + .and_then(|value| value.checked_add(1)) + .ok_or(Error::ArithmeticOverflow( + "(exit_balance - exit_balance_to_consume - 1) / per_epoch_churn + 1", + ))?; + let additional_churn = + additional_epochs + .checked_mul(per_epoch_churn) + .ok_or(Error::ArithmeticOverflow( + "additional_epochs * per_epoch_churn", + ))?; + earliest_exit_epoch = + earliest_exit_epoch + .checked_add(additional_epochs) + .ok_or(Error::ArithmeticOverflow( + "earliest_exit_epoch + additional_epochs", + ))?; + exit_balance_to_consume = exit_balance_to_consume + .checked_add(additional_churn) + .ok_or(Error::ArithmeticOverflow( + "exit_balance_to_consume + additional_epochs * per_epoch_churn", + ))?; + } + + *fields.exit_balance_to_consume_mut() = exit_balance_to_consume + .checked_sub(exit_balance) + .ok_or(Error::ArithmeticOverflow( + "exit_balance_to_consume - exit_balance", + ))?; + *fields.earliest_exit_epoch_mut() = earliest_exit_epoch; + + Ok(earliest_exit_epoch) +} + +/// Advances electra's consolidation-queue cursor for a consolidation moving +/// `consolidation_balance`, returning the epoch it may take effect at. +/// +/// The consolidation-side counterpart of +/// [`compute_exit_epoch_and_update_churn`], carrying the exact same +/// `(earliest_epoch, balance_to_consume)` cursor shape but drawing from +/// [`get_consolidation_churn_limit`]'s separate budget instead of the +/// activation/exit one, so a burst of consolidations cannot also drain the +/// budget an unrelated exit needs. +pub fn compute_consolidation_epoch_and_update_churn( + state: &mut BeaconState, + consolidation_balance: Gwei, + config: &Config, +) -> Result { + let current_epoch = get_current_epoch(state); + let per_epoch_churn = get_consolidation_churn_limit(state, config)?; + + let mut fields = electra_state(state, "compute_consolidation_epoch_and_update_churn")?; + + let mut earliest_consolidation_epoch = fields + .earliest_consolidation_epoch() + .max(compute_activation_exit_epoch(current_epoch)); + + let mut consolidation_balance_to_consume = + if fields.earliest_consolidation_epoch() < earliest_consolidation_epoch { + per_epoch_churn + } else { + fields.consolidation_balance_to_consume() + }; + + if consolidation_balance > consolidation_balance_to_consume { + let balance_to_process = consolidation_balance - consolidation_balance_to_consume; + let additional_epochs = balance_to_process + .checked_sub(1) + .and_then(|value| value.checked_div(per_epoch_churn)) + .and_then(|value| value.checked_add(1)) + .ok_or(Error::ArithmeticOverflow( + "(consolidation_balance - consolidation_balance_to_consume - 1) / per_epoch_churn + 1", + ))?; + let additional_churn = + additional_epochs + .checked_mul(per_epoch_churn) + .ok_or(Error::ArithmeticOverflow( + "additional_epochs * per_epoch_churn", + ))?; + earliest_consolidation_epoch = earliest_consolidation_epoch + .checked_add(additional_epochs) + .ok_or(Error::ArithmeticOverflow( + "earliest_consolidation_epoch + additional_epochs", + ))?; + consolidation_balance_to_consume = consolidation_balance_to_consume + .checked_add(additional_churn) + .ok_or(Error::ArithmeticOverflow( + "consolidation_balance_to_consume + additional_epochs * per_epoch_churn", + ))?; + } + + *fields.consolidation_balance_to_consume_mut() = consolidation_balance_to_consume + .checked_sub(consolidation_balance) + .ok_or(Error::ArithmeticOverflow( + "consolidation_balance_to_consume - consolidation_balance", + ))?; + *fields.earliest_consolidation_epoch_mut() = earliest_consolidation_epoch; + + Ok(earliest_consolidation_epoch) +} + +/// Upgrades a validator to a compounding withdrawal credential, queuing +/// whatever balance is already above [`preset::MIN_ACTIVATION_BALANCE`] the +/// same way a fresh deposit above it would be. +pub fn switch_to_compounding_validator( + state: &mut BeaconState, + index: ValidatorIndex, +) -> Result<()> { + state.validator_mut(index)?.withdrawal_credentials.0[0] = + constants::COMPOUNDING_WITHDRAWAL_PREFIX; + queue_excess_active_balance(state, index) +} + +/// Caps a validator's balance at [`preset::MIN_ACTIVATION_BALANCE`], queuing +/// anything above that as a [`electra::PendingDeposit`] rather than +/// crediting it as active stake immediately. +/// +/// Does nothing if the balance is already at or below the cap: called after +/// [`switch_to_compounding_validator`] raises a validator's ceiling, and +/// after a deposit, both of which are ordinary, common-case calls that most +/// of the time have nothing to queue. +pub fn queue_excess_active_balance(state: &mut BeaconState, index: ValidatorIndex) -> Result<()> { + let balance = state.balance(index)?; + if balance <= preset::MIN_ACTIVATION_BALANCE { + return Ok(()); + } + + let excess_balance = balance - preset::MIN_ACTIVATION_BALANCE; + // `state.balance(index)?` above already proved `index` is in range, and + // `balances` is always exactly as long as `validators`, so this indexing + // cannot panic. + state.balances_mut()[index as usize] = preset::MIN_ACTIVATION_BALANCE; + + let deposit = placeholder_pending_deposit(state.validator(index)?, excess_balance); + electra_state(state, "queue_excess_active_balance")? + .pending_deposits_mut() + .push(deposit)?; + Ok(()) +} + +/// Zeroes a validator's balance and effective balance, resets its activation +/// eligibility to "not yet eligible", and queues the balance it held as a +/// [`electra::PendingDeposit`]. +/// +/// Not itself a named helper in `specs/electra/beacon-chain.md`. It is +/// extracted verbatim from a loop body in `specs/electra/fork.md`'s +/// `upgrade_to_electra`, which applies exactly this to every not-yet-active +/// validator at the electra fork boundary rather than losing its balance: +/// [`switch_to_compounding_validator`] and [`queue_excess_active_balance`] +/// already queue a validator's *excess* balance the same way, and the fork +/// upgrade needs the same construction for a validator's *entire* balance, +/// so this factors the shared shape into one function rather than +/// duplicating the pending-deposit literal at both call sites. +pub fn queue_entire_balance_and_reset_validator( + state: &mut BeaconState, + index: ValidatorIndex, +) -> Result<()> { + let balance = state.balance(index)?; + // See `queue_excess_active_balance` for why this indexing cannot panic. + state.balances_mut()[index as usize] = 0; + + let validator = state.validator_mut(index)?; + validator.effective_balance = 0; + validator.activation_eligibility_epoch = FAR_FUTURE_EPOCH; + + let deposit = placeholder_pending_deposit(state.validator(index)?, balance); + electra_state(state, "queue_entire_balance_and_reset_validator")? + .pending_deposits_mut() + .push(deposit)?; + Ok(()) +} + +// --------------------------------------------------------------------------- +// Fork projection +// --------------------------------------------------------------------------- + +/// The compressed encoding of the identity element of G2 +/// (`specs/altair/bls.md`'s `G2_POINT_AT_INFINITY`), used as the placeholder +/// signature on a synthetic pending deposit that never carried a real proof +/// of possession. +/// +/// [`crate::beacon::bls`] keeps its own copy of this same encoding for +/// `eth_fast_aggregate_verify`'s empty-committee case, but does not export +/// it, so this file builds its own rather than reaching into that module's +/// internals. +fn g2_point_at_infinity() -> BlsSignature { + let mut bytes = [0u8; BLS_SIGNATURE_SIZE]; + // The top two bits are the compression and infinity flags; setting both + // and leaving every other bit zero is the point at infinity's compressed + // encoding. + bytes[0] = 0b1100_0000; + BlsSignature(bytes) +} + +/// A [`electra::PendingDeposit`] standing in for a balance that never +/// belonged to a real, signed deposit: the shared shape +/// [`queue_excess_active_balance`] and +/// [`queue_entire_balance_and_reset_validator`] both build, differing only in +/// how much balance they queue. +fn placeholder_pending_deposit(validator: &Validator, amount: Gwei) -> electra::PendingDeposit { + electra::PendingDeposit { + pubkey: validator.pubkey, + withdrawal_credentials: validator.withdrawal_credentials, + amount, + signature: g2_point_at_infinity(), + slot: constants::GENESIS_SLOT, + } +} + +/// Either fork whose state carries electra's balance-churn accounting and +/// pending-deposit/withdrawal queues (EIP-7251) unchanged: electra itself, or +/// fulu, which never redefines any of the fields read through this. See this +/// module's doc for why both are accepted, and [`electra_state`] for the +/// mutable counterpart. +pub(crate) enum ElectraOrFulu<'a> { + Electra(&'a electra::BeaconState), + Fulu(&'a fulu::BeaconState), +} + +impl<'a> ElectraOrFulu<'a> { + /// Partial withdrawals queued but not yet paid out, read by + /// [`get_pending_balance_to_withdraw`]. + pub(crate) fn pending_partial_withdrawals(&self) -> &electra::PendingPartialWithdrawals { + match self { + ElectraOrFulu::Electra(state) => &state.pending_partial_withdrawals, + ElectraOrFulu::Fulu(state) => &state.pending_partial_withdrawals, + } + } +} + +/// The mutable counterpart of [`ElectraOrFulu`]. See [`electra_state`]. +pub(crate) enum ElectraOrFuluMut<'a> { + Electra(&'a mut electra::BeaconState), + Fulu(&'a mut fulu::BeaconState), +} + +impl<'a> ElectraOrFuluMut<'a> { + pub(crate) fn earliest_exit_epoch(&self) -> Epoch { + match self { + ElectraOrFuluMut::Electra(state) => state.earliest_exit_epoch, + ElectraOrFuluMut::Fulu(state) => state.earliest_exit_epoch, + } + } + + pub(crate) fn earliest_exit_epoch_mut(&mut self) -> &mut Epoch { + match self { + ElectraOrFuluMut::Electra(state) => &mut state.earliest_exit_epoch, + ElectraOrFuluMut::Fulu(state) => &mut state.earliest_exit_epoch, + } + } + + pub(crate) fn exit_balance_to_consume(&self) -> Gwei { + match self { + ElectraOrFuluMut::Electra(state) => state.exit_balance_to_consume, + ElectraOrFuluMut::Fulu(state) => state.exit_balance_to_consume, + } + } + + pub(crate) fn exit_balance_to_consume_mut(&mut self) -> &mut Gwei { + match self { + ElectraOrFuluMut::Electra(state) => &mut state.exit_balance_to_consume, + ElectraOrFuluMut::Fulu(state) => &mut state.exit_balance_to_consume, + } + } + + pub(crate) fn earliest_consolidation_epoch(&self) -> Epoch { + match self { + ElectraOrFuluMut::Electra(state) => state.earliest_consolidation_epoch, + ElectraOrFuluMut::Fulu(state) => state.earliest_consolidation_epoch, + } + } + + pub(crate) fn earliest_consolidation_epoch_mut(&mut self) -> &mut Epoch { + match self { + ElectraOrFuluMut::Electra(state) => &mut state.earliest_consolidation_epoch, + ElectraOrFuluMut::Fulu(state) => &mut state.earliest_consolidation_epoch, + } + } + + pub(crate) fn consolidation_balance_to_consume(&self) -> Gwei { + match self { + ElectraOrFuluMut::Electra(state) => state.consolidation_balance_to_consume, + ElectraOrFuluMut::Fulu(state) => state.consolidation_balance_to_consume, + } + } + + pub(crate) fn consolidation_balance_to_consume_mut(&mut self) -> &mut Gwei { + match self { + ElectraOrFuluMut::Electra(state) => &mut state.consolidation_balance_to_consume, + ElectraOrFuluMut::Fulu(state) => &mut state.consolidation_balance_to_consume, + } + } + + /// Deposits queued but not yet credited to the validator registry, pushed + /// to by [`queue_excess_active_balance`] and + /// [`queue_entire_balance_and_reset_validator`]. + pub(crate) fn pending_deposits_mut(&mut self) -> &mut electra::PendingDeposits { + match self { + ElectraOrFuluMut::Electra(state) => &mut state.pending_deposits, + ElectraOrFuluMut::Fulu(state) => &mut state.pending_deposits, + } + } +} + +/// The electra-or-fulu state, mutably, or an error naming the function that +/// needs one. See [`ElectraOrFuluMut`] and this module's doc for why both +/// forks are accepted. +pub(crate) fn electra_state<'a>( + state: &'a mut BeaconState, + function: &'static str, +) -> Result> { + match state { + BeaconState::Electra(state) => Ok(ElectraOrFuluMut::Electra(state)), + BeaconState::Fulu(state) => Ok(ElectraOrFuluMut::Fulu(state)), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +/// The electra-or-fulu state, immutably. See [`electra_state`]. +pub(crate) fn electra_state_ref<'a>( + state: &'a BeaconState, + function: &'static str, +) -> Result> { + match state { + BeaconState::Electra(state) => Ok(ElectraOrFulu::Electra(state)), + BeaconState::Fulu(state) => Ok(ElectraOrFulu::Fulu(state)), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::containers::shared::AttestationData; + use crate::beacon::fork::ForkName; + + /// An electra state with `count` fully active, full-balance validators, + /// positioned the same way `crate::beacon::helpers::test_state::with_validators` + /// positions its phase0 state: one epoch in, so the previous epoch and + /// the block-root history window both have entries. + /// + /// A thin wrapper around the shared fork-parameterised builder: see + /// [`crate::beacon::helpers::test_state::with_validators_at`] for the construction + /// this and every other fork's test module used to duplicate. + fn electra_state_with_validators(count: usize) -> BeaconState { + crate::beacon::helpers::test_state::with_validators_at(ForkName::Electra, count) + } + + /// A fulu state, otherwise identical to [`electra_state_with_validators`], + /// used only to prove [`electra_state`]/[`electra_state_ref`] accept fulu + /// too and are not accidentally scoped to `BeaconState::Electra` alone. + fn fulu_state_with_validators(count: usize) -> BeaconState { + crate::beacon::helpers::test_state::with_validators_at(ForkName::Fulu, count) + } + + // -- Predicates --------------------------------------------------------- + + #[test] + fn withdrawal_credential_predicates_read_the_prefix_byte() { + let mut validator = Validator { + withdrawal_credentials: Bytes32::ZERO, + ..Default::default() + }; + // 0x00: a raw BLS credential, before the validator has upgraded. + assert!(!has_eth1_withdrawal_credential(&validator)); + assert!(!has_compounding_withdrawal_credential(&validator)); + assert!(!has_execution_withdrawal_credential(&validator)); + + validator.withdrawal_credentials.0[0] = constants::ETH1_ADDRESS_WITHDRAWAL_PREFIX; + assert!(has_eth1_withdrawal_credential(&validator)); + assert!(!has_compounding_withdrawal_credential(&validator)); + assert!(has_execution_withdrawal_credential(&validator)); + + validator.withdrawal_credentials.0[0] = constants::COMPOUNDING_WITHDRAWAL_PREFIX; + assert!(!has_eth1_withdrawal_credential(&validator)); + assert!(has_compounding_withdrawal_credential(&validator)); + assert!(has_execution_withdrawal_credential(&validator)); + } + + #[test] + fn max_effective_balance_depends_on_the_compounding_credential() { + let mut validator = Validator { + withdrawal_credentials: Bytes32::ZERO, + ..Default::default() + }; + validator.withdrawal_credentials.0[0] = constants::ETH1_ADDRESS_WITHDRAWAL_PREFIX; + assert_eq!( + get_max_effective_balance(&validator), + preset::MIN_ACTIVATION_BALANCE + ); + + validator.withdrawal_credentials.0[0] = constants::COMPOUNDING_WITHDRAWAL_PREFIX; + assert_eq!( + get_max_effective_balance(&validator), + preset::MAX_EFFECTIVE_BALANCE_ELECTRA + ); + } + + #[test] + fn partially_withdrawable_requires_both_a_full_ceiling_and_excess_balance() { + let mut validator = Validator { + withdrawal_credentials: Bytes32::ZERO, + effective_balance: preset::MIN_ACTIVATION_BALANCE, + ..Default::default() + }; + validator.withdrawal_credentials.0[0] = constants::ETH1_ADDRESS_WITHDRAWAL_PREFIX; + + assert!(!is_partially_withdrawable_validator( + &validator, + preset::MIN_ACTIVATION_BALANCE + )); + assert!(is_partially_withdrawable_validator( + &validator, + preset::MIN_ACTIVATION_BALANCE + 1 + )); + + // No longer sitting at its own ceiling, so no longer withdrawable + // even with a nominally excess balance. + validator.effective_balance = preset::MIN_ACTIVATION_BALANCE - 1; + assert!(!is_partially_withdrawable_validator( + &validator, + preset::MIN_ACTIVATION_BALANCE + 1 + )); + } + + #[test] + fn activation_queue_eligibility_accepts_balance_at_or_above_the_minimum() { + let mut validator = Validator { + activation_eligibility_epoch: FAR_FUTURE_EPOCH, + effective_balance: preset::MIN_ACTIVATION_BALANCE, + ..Default::default() + }; + assert!(is_eligible_for_activation_queue(&validator)); + + // Unlike phase0's version (exact equality with MAX_EFFECTIVE_BALANCE), + // electra also accepts a compounding validator's higher balance. + validator.effective_balance = preset::MAX_EFFECTIVE_BALANCE_ELECTRA; + assert!(is_eligible_for_activation_queue(&validator)); + + validator.effective_balance = preset::MIN_ACTIVATION_BALANCE - 1; + assert!(!is_eligible_for_activation_queue(&validator)); + } + + #[test] + fn compute_proposer_index_prefers_a_full_balance_under_the_electra_ceiling() { + let indices: Vec = (0..16).collect(); + let max = preset::MAX_EFFECTIVE_BALANCE_ELECTRA; + + let mut chose_the_rich_one = 0; + for trial in 0..32u8 { + let chosen = compute_proposer_index(&indices, Bytes32::repeat_byte(trial), |index| { + Ok(if index == 3 { max } else { 1 }) + }) + .unwrap(); + if chosen == 3 { + chose_the_rich_one += 1; + } + } + assert!( + chose_the_rich_one > 16, + "the full-balance validator was chosen {chose_the_rich_one} times out of 32" + ); + } + + #[test] + fn compute_proposer_index_rejects_an_empty_set() { + assert!(compute_proposer_index(&[], Bytes32::ZERO, |_| Ok(1)).is_err()); + } + + // -- Misc ----------------------------------------------------------- + + #[test] + fn get_committee_indices_lists_only_the_set_bits_in_ascending_order() { + let mut bits = electra::CommitteeBits::default(); + // `CommitteeBits` is exactly `MAX_COMMITTEES_PER_SLOT` bits long, and + // minimal's preset shrinks that bound far below mainnet's, so the + // highest index this vector actually holds has to come from the + // constant itself: a literal high enough to be interesting under + // mainnet (e.g. 4) is out of bounds under minimal. + let last = preset::MAX_COMMITTEES_PER_SLOT - 1; + bits.set(last, true).unwrap(); + bits.set(1, true).unwrap(); + assert_eq!( + get_committee_indices(&bits), + vec![1, last as CommitteeIndex] + ); + } + + // -- Beacon state accessors ---------------------------------------------- + + #[test] + fn activation_exit_and_consolidation_churn_partition_the_balance_churn_limit() { + let config = Config::mainnet(); + let state = electra_state_with_validators(64); + + let balance_churn = get_balance_churn_limit(&state, &config).unwrap(); + let activation_exit_churn = get_activation_exit_churn_limit(&state, &config).unwrap(); + let consolidation_churn = get_consolidation_churn_limit(&state, &config).unwrap(); + + assert_eq!(activation_exit_churn + consolidation_churn, balance_churn); + } + + #[test] + fn balance_churn_limit_respects_its_electra_floor() { + let config = Config::mainnet(); + // A tiny active set falls below the proportional limit, so the + // electra-specific floor applies, not phase0's smaller one. + let state = electra_state_with_validators(4); + assert_eq!( + get_balance_churn_limit(&state, &config).unwrap(), + config.min_per_epoch_churn_limit_electra, + ); + } + + #[test] + fn pending_balance_to_withdraw_sums_only_the_matching_validator() { + let mut state = electra_state_with_validators(4); + if let BeaconState::Electra(inner) = &mut state { + inner.pending_partial_withdrawals = vec![ + electra::PendingPartialWithdrawal { + validator_index: 0, + amount: 10, + withdrawable_epoch: 5, + }, + electra::PendingPartialWithdrawal { + validator_index: 1, + amount: 20, + withdrawable_epoch: 5, + }, + electra::PendingPartialWithdrawal { + validator_index: 0, + amount: 30, + withdrawable_epoch: 6, + }, + ] + .try_into() + .unwrap(); + } else { + unreachable!("just built as Electra"); + } + + assert_eq!(get_pending_balance_to_withdraw(&state, 0).unwrap(), 40); + assert_eq!(get_pending_balance_to_withdraw(&state, 1).unwrap(), 20); + assert_eq!(get_pending_balance_to_withdraw(&state, 2).unwrap(), 0); + } + + #[test] + fn get_attesting_indices_returns_ascending_indices_across_noncontiguous_committees() { + // Enough active validators that a slot splits into more than one + // committee under either preset this module compiles for. Exactly how + // many committees (and what size) `get_committee_count_per_slot` + // lands on differs by preset: mainnet's larger `TARGET_COMMITTEE_SIZE` + // but higher `MAX_COMMITTEES_PER_SLOT` ceiling divides this count one + // way, minimal's smaller versions of both divide it another way. So + // this test reads the committees it actually gets back rather than + // asserting a size tied to one preset's arithmetic; what it exercises + // is the committee-offset bookkeeping in `get_attesting_indices`, not + // any preset's specific committee count or size. Fewer validators + // would risk naming only one committee under some preset, which + // cannot expose a misaligned offset. + let count = 8192; + let state = electra_state_with_validators(count); + let slot = state.slot(); + + // Committee indices 0 and 2, deliberately non-contiguous: naming + // index 1's slot but skipping it must not shift where index 2's + // segment starts in `aggregation_bits`. This needs at least three + // committees per slot, true under both presets at this validator + // count. + let committee_0 = get_beacon_committee(&state, slot, 0).unwrap(); + let committee_2 = get_beacon_committee(&state, slot, 2).unwrap(); + assert!(!committee_0.is_empty(), "test needs a non-empty committee"); + // `count` divides evenly by the total committee count under both + // presets, so every committee in this epoch is exactly the same + // size; asserting that (rather than a preset-specific literal) is + // what lets the rest of this test use `committee_0.len()` as the + // offset into committee 2's segment. + assert_eq!(committee_0.len(), committee_2.len()); + + let mut committee_bits = electra::CommitteeBits::default(); + committee_bits.set(0, true).unwrap(); + committee_bits.set(2, true).unwrap(); + + let mut aggregation_bits = + electra::AggregationBits::with_length(committee_0.len() + committee_2.len()).unwrap(); + // Two members of the first named committee's own segment. + aggregation_bits.set(0, true).unwrap(); + aggregation_bits.set(5, true).unwrap(); + // Two members of the second named committee, offset past the whole + // first committee's segment (not past committee index 1's, which + // this attestation never names and which must not consume any + // offset at all). + aggregation_bits.set(committee_0.len() + 3, true).unwrap(); + aggregation_bits + .set(committee_0.len() + committee_2.len() - 1, true) + .unwrap(); + + let attestation = electra::Attestation { + aggregation_bits, + data: AttestationData { + slot, + ..Default::default() + }, + signature: BlsSignature::default(), + committee_bits, + }; + + let indices = get_attesting_indices(&state, &attestation).unwrap(); + + let mut expected = vec![ + committee_0[0], + committee_0[5], + committee_2[3], + committee_2[committee_2.len() - 1], + ]; + expected.sort_unstable(); + + assert_eq!(indices, expected); + assert!( + indices.windows(2).all(|pair| pair[0] < pair[1]), + "get_attesting_indices must return a strictly ascending, duplicate-free list" + ); + } + + #[test] + fn get_indexed_attestation_carries_the_attesting_indices_and_signature() { + // 16 validators split across a whole epoch's worth of committee slots + // (32 under the mainnet preset) would leave most of those slots + // empty; enough validators that every slot's single committee is + // reliably non-empty is what this test actually needs. + let state = electra_state_with_validators(1024); + let slot = state.slot(); + let committee = get_beacon_committee(&state, slot, 0).unwrap(); + + let mut committee_bits = electra::CommitteeBits::default(); + committee_bits.set(0, true).unwrap(); + let mut aggregation_bits = electra::AggregationBits::with_length(committee.len()).unwrap(); + aggregation_bits.set(0, true).unwrap(); + + let attestation = electra::Attestation { + aggregation_bits, + data: AttestationData { + slot, + ..Default::default() + }, + signature: BlsSignature([9; BLS_SIGNATURE_SIZE]), + committee_bits, + }; + + let indexed = get_indexed_attestation(&state, &attestation).unwrap(); + assert_eq!(&*indexed.attesting_indices, &[committee[0]]); + assert_eq!(indexed.signature, attestation.signature); + assert_eq!(indexed.data, attestation.data); + } + + #[test] + fn next_sync_committee_indices_are_exactly_sync_committee_size() { + let state = electra_state_with_validators(4); + let indices = get_next_sync_committee_indices(&state).unwrap(); + assert_eq!(indices.len(), preset::SYNC_COMMITTEE_SIZE); + assert!(indices.iter().all(|index| *index < 4)); + } + + // -- Beacon state mutators ----------------------------------------------- + + #[test] + fn initiate_validator_exit_is_idempotent_and_sets_withdrawable_epoch() { + let config = Config::mainnet(); + let mut state = electra_state_with_validators(4); + + initiate_validator_exit(&mut state, 0, &config).unwrap(); + let first_exit_epoch = state.validator(0).unwrap().exit_epoch; + assert_ne!(first_exit_epoch, FAR_FUTURE_EPOCH); + assert_eq!( + state.validator(0).unwrap().withdrawable_epoch, + first_exit_epoch + config.min_validator_withdrawability_delay, + ); + + initiate_validator_exit(&mut state, 0, &config).unwrap(); + assert_eq!(state.validator(0).unwrap().exit_epoch, first_exit_epoch); + } + + #[test] + fn a_large_exit_consumes_more_than_one_epoch_of_churn() { + let config = Config::mainnet(); + let mut state = electra_state_with_validators(4); + + let per_epoch_churn = get_activation_exit_churn_limit(&state, &config).unwrap(); + let baseline = compute_activation_exit_epoch(get_current_epoch(&state)); + + let exit_epoch = + compute_exit_epoch_and_update_churn(&mut state, per_epoch_churn * 2, &config).unwrap(); + assert!(exit_epoch > baseline); + } + + #[test] + fn two_small_exits_in_the_same_epoch_share_its_leftover_churn() { + let config = Config::mainnet(); + let mut state = electra_state_with_validators(4); + let per_epoch_churn = get_activation_exit_churn_limit(&state, &config).unwrap(); + + let first_epoch = + compute_exit_epoch_and_update_churn(&mut state, per_epoch_churn / 4, &config).unwrap(); + let second_epoch = + compute_exit_epoch_and_update_churn(&mut state, per_epoch_churn / 4, &config).unwrap(); + + // Together they are still under one epoch's churn limit, so the + // cursor lets the second exit spend what the first left over instead + // of always waiting for a fresh epoch. + assert_eq!(first_epoch, second_epoch); + } + + #[test] + fn switch_to_compounding_validator_sets_the_prefix_and_queues_excess() { + let mut state = electra_state_with_validators(4); + state.balances_mut()[0] = preset::MIN_ACTIVATION_BALANCE + 1_000_000_000; + + switch_to_compounding_validator(&mut state, 0).unwrap(); + + assert!(has_compounding_withdrawal_credential( + state.validator(0).unwrap() + )); + assert_eq!(state.balance(0).unwrap(), preset::MIN_ACTIVATION_BALANCE); + } + + #[test] + fn queue_excess_active_balance_caps_the_balance_and_queues_the_rest() { + let mut state = electra_state_with_validators(4); + let pubkey = state.validator(0).unwrap().pubkey; + state.balances_mut()[0] = preset::MIN_ACTIVATION_BALANCE + 5_000_000_000; + + queue_excess_active_balance(&mut state, 0).unwrap(); + + assert_eq!(state.balance(0).unwrap(), preset::MIN_ACTIVATION_BALANCE); + let BeaconState::Electra(inner) = &state else { + unreachable!("just built as Electra"); + }; + assert_eq!(inner.pending_deposits.len(), 1); + assert_eq!(inner.pending_deposits[0].amount, 5_000_000_000); + assert_eq!(inner.pending_deposits[0].pubkey, pubkey); + } + + #[test] + fn queue_excess_active_balance_does_nothing_at_or_below_the_minimum() { + let mut state = electra_state_with_validators(4); + state.balances_mut()[0] = preset::MIN_ACTIVATION_BALANCE; + queue_excess_active_balance(&mut state, 0).unwrap(); + let BeaconState::Electra(inner) = &state else { + unreachable!("just built as Electra"); + }; + assert!(inner.pending_deposits.is_empty()); + } + + #[test] + fn queue_entire_balance_and_reset_validator_zeroes_the_validator() { + let mut state = electra_state_with_validators(4); + state.balances_mut()[0] = 12_000_000_000; + + queue_entire_balance_and_reset_validator(&mut state, 0).unwrap(); + + assert_eq!(state.balance(0).unwrap(), 0); + let validator = state.validator(0).unwrap(); + assert_eq!(validator.effective_balance, 0); + assert_eq!(validator.activation_eligibility_epoch, FAR_FUTURE_EPOCH); + + let BeaconState::Electra(inner) = &state else { + unreachable!("just built as Electra"); + }; + assert_eq!(inner.pending_deposits.len(), 1); + assert_eq!(inner.pending_deposits[0].amount, 12_000_000_000); + } + + // -- Fork projection ------------------------------------------------------ + + #[test] + fn electra_state_ref_accepts_both_electra_and_fulu_but_not_phase0() { + let electra_state_value = electra_state_with_validators(4); + assert!(electra_state_ref(&electra_state_value, "test").is_ok()); + + let fulu_state_value = fulu_state_with_validators(4); + assert!(electra_state_ref(&fulu_state_value, "test").is_ok()); + + let phase0_state_value = crate::beacon::helpers::test_state::with_validators(4); + assert!(electra_state_ref(&phase0_state_value, "test").is_err()); + } + + #[test] + fn electra_state_mut_accepts_both_electra_and_fulu_but_not_phase0() { + let mut electra_state_value = electra_state_with_validators(4); + assert!(electra_state(&mut electra_state_value, "test").is_ok()); + + let mut fulu_state_value = fulu_state_with_validators(4); + assert!(electra_state(&mut fulu_state_value, "test").is_ok()); + + let mut phase0_state_value = crate::beacon::helpers::test_state::with_validators(4); + assert!(electra_state(&mut phase0_state_value, "test").is_err()); + } + + #[test] + fn compute_exit_epoch_and_update_churn_works_on_a_fulu_state_too() { + let config = Config::mainnet(); + let mut state = fulu_state_with_validators(4); + let baseline = compute_activation_exit_epoch(get_current_epoch(&state)); + + let exit_epoch = compute_exit_epoch_and_update_churn(&mut state, 1, &config).unwrap(); + assert_eq!(exit_epoch, baseline); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/helpers/finality.rs b/crates/blockchain/state_transition/src/beacon/helpers/finality.rs new file mode 100644 index 000000000..9c945c9bd --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/finality.rs @@ -0,0 +1,56 @@ +//! Epoch-boundary accessors that every fork shares. +//! +//! The specification introduces these under phase0's epoch processing, and no +//! later fork changes them, so both phase0's and altair's reward accounting call +//! the same three functions. They live in `helpers` rather than in either fork's +//! reward module so that neither has to depend on the other: altair's helpers +//! previously reached into phase0's `stf::epoch::rewards` for them, which made +//! `helpers` depend on `stf` where the dependency otherwise runs the other way. + +use crate::beacon::containers::BeaconState; +use crate::beacon::preset; +use crate::beacon::primitives::{Epoch, ValidatorIndex}; + +use super::accessors::get_previous_epoch; +use super::predicates::is_active_validator; + +/// How many epochs finality has lagged behind the previous epoch. +/// +/// Zero whenever finality is keeping pace with attestation processing; grows +/// by one every further epoch the chain fails to finalize, which is what lets +/// [`is_in_inactivity_leak`] and the inactivity penalty scale with how long the +/// stall has lasted rather than firing at a fixed severity. +pub fn get_finality_delay(state: &BeaconState) -> Epoch { + get_previous_epoch(state) - state.finalized_checkpoint().epoch +} + +/// Whether the chain has gone long enough without finalizing that inactive +/// validators' balances should start leaking away. +/// +/// The leak exists so a large inactive or adversarial minority cannot stall +/// finality forever while keeping its stake intact: the longer finality +/// stalls, the faster an inactive validator's share of the active set shrinks, +/// until the honest, active minority eventually clears the two-thirds +/// threshold on its own. +pub fn is_in_inactivity_leak(state: &BeaconState) -> bool { + get_finality_delay(state) > preset::MIN_EPOCHS_TO_INACTIVITY_PENALTY +} + +/// Validators whose participation this epoch's rewards and penalties account +/// for: every currently active validator, plus one already exited but not yet +/// past its withdrawable epoch, so a validator that leaves the active set +/// still pays (or earns) whatever this epoch's accounting owes it up to that +/// point. +pub fn get_eligible_validator_indices(state: &BeaconState) -> Vec { + let previous_epoch = get_previous_epoch(state); + state + .validators() + .iter() + .enumerate() + .filter(|(_, validator)| { + is_active_validator(validator, previous_epoch) + || (validator.slashed && previous_epoch + 1 < validator.withdrawable_epoch) + }) + .map(|(index, _)| index as ValidatorIndex) + .collect() +} diff --git a/crates/blockchain/state_transition/src/beacon/helpers/fulu.rs b/crates/blockchain/state_transition/src/beacon/helpers/fulu.rs new file mode 100644 index 000000000..d488a0f7d --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/fulu.rs @@ -0,0 +1,279 @@ +//! Fulu's proposer lookahead. +//! +//! Every fork through electra computes a slot's proposer on demand: it +//! shuffles that slot's epoch's active set under a seed drawn from the +//! randao mix, and that seed only exists once the mix it reads is +//! `MIN_SEED_LOOKAHEAD` epochs old (see [`super::accessors::get_seed`]). A +//! validator therefore cannot know its own proposer duty for next epoch, +//! only for the current one, because next epoch's seed is not fixed yet. +//! +//! Fulu breaks that coupling by moving the computation off the read path. +//! `BeaconState::proposer_lookahead` (`crate::beacon::containers::fulu::BeaconState`) +//! precomputes a rolling window of upcoming proposers, one epoch at a time, +//! as far ahead as a seed is ever knowable: [`initialize_proposer_lookahead`] +//! fills the window from scratch at genesis and when upgrading to fulu, and +//! the specification's `process_proposer_lookahead` (`beacon-chain.md`'s +//! "Epoch processing", not implemented in this file, see below) shifts it +//! forward by one epoch at every later epoch boundary. Reading a duty is then +//! a lookup into whatever the window last computed, rather than a shuffle run +//! at the moment something asks: [`get_beacon_proposer_index`] becomes +//! `state.proposer_lookahead[state.slot % SLOTS_PER_EPOCH]`, an index into +//! already-settled answers instead of a computation over the current +//! shuffling seed. +//! +//! [`get_beacon_proposer_index`] here does not replace +//! [`super::accessors::get_beacon_proposer_index`] in place: the two coexist, +//! fulu's reading the precomputed window and every earlier fork's computing +//! on demand, and that accessor dispatches between them by fork itself, +//! rather than each of *its* own callers doing so, the same split +//! [`super::altair::altair_state_ref`] documents for altair's +//! participation-flag fields. A state older than fulu has no +//! `proposer_lookahead` to read, so [`get_beacon_proposer_index`] fails +//! through [`fulu_state_ref`] rather than falling back to the on-demand +//! computation. +//! +//! [`compute_proposer_indices`] and [`get_beacon_proposer_indices`] are the +//! building blocks the window is filled from. Both take a [`BeaconState`] of +//! any fork, not only fulu's, because both read the state only through +//! fork-invariant accessors (`get_active_validator_indices`, `get_seed`, +//! `state.validator`) and never touch `proposer_lookahead` themselves; the +//! specification's own `upgrade_to_fulu` (`fork.md`) relies on exactly that, +//! calling [`initialize_proposer_lookahead`] on the electra state being +//! upgraded, one slot before a `proposer_lookahead` field exists anywhere to +//! read back out of. +//! +//! This file does not implement `process_proposer_lookahead` itself: that +//! function mutates state at an epoch boundary, and every other fork's +//! equivalent epoch-processing step lives in `crate::beacon::stf`, not in a +//! `helpers::` module (see [`super::altair`]'s module docs, which make +//! the same point about `process_attestation`). [`fulu_state`] is kept +//! alongside [`fulu_state_ref`] for whenever that step is written, the same +//! way altair keeps a mutable state projection ready for its own +//! not-yet-written processing steps. + +use crate::beacon::constants; +use crate::beacon::containers::{BeaconState, fulu}; +use crate::beacon::error::{Error, Result}; +use crate::beacon::hash::hash; +use crate::beacon::preset; +use crate::beacon::primitives::{Bytes32, Epoch, ValidatorIndex}; + +use super::accessors::{get_active_validator_indices, get_current_epoch, get_seed}; +use super::electra::compute_proposer_index; +use super::misc::compute_start_slot_at_epoch; + +// --------------------------------------------------------------------------- +// Misc +// --------------------------------------------------------------------------- + +/// The proposer for every slot of `epoch`, drawn from `indices` under `seed`. +/// +/// One shuffling seed per epoch is not enough on its own: every slot of that +/// epoch would otherwise draw the same proposer. The specification mixes +/// `seed` with each slot number first (shadowing its own `seed` parameter +/// with the result, one hash per slot, inside a single list comprehension); +/// this keeps that per-slot hash in its own binding, `slot_seed`, instead. +/// +/// Calls [`super::electra::compute_proposer_index`], not +/// [`super::shuffling::compute_proposer_index`]: fulu's specification builds +/// on electra's (`beacon-chain.md`'s own introduction says as much), so the +/// `compute_proposer_index` this function's own spec text calls is already +/// electra's widened-draw, `MAX_EFFECTIVE_BALANCE_ELECTRA`-weighted version, +/// not phase0's. A fulu validator can hold exactly the same balances an +/// electra one can, so nothing here would justify falling back to the +/// narrower, pre-electra acceptance test. +pub fn compute_proposer_indices( + state: &BeaconState, + epoch: Epoch, + seed: Bytes32, + indices: &[ValidatorIndex], +) -> Result> { + let start_slot = compute_start_slot_at_epoch(epoch); + + let mut proposer_indices = Vec::with_capacity(preset::SLOTS_PER_EPOCH as usize); + for offset in 0..preset::SLOTS_PER_EPOCH { + let mut input = Vec::with_capacity(32 + 8); + input.extend_from_slice(&seed.0); + input.extend_from_slice(&(start_slot + offset).to_le_bytes()); + let slot_seed = hash(&input); + + let proposer_index = compute_proposer_index(indices, slot_seed, |index| { + Ok(state.validator(index)?.effective_balance) + })?; + proposer_indices.push(proposer_index); + } + Ok(proposer_indices) +} + +// --------------------------------------------------------------------------- +// Beacon state accessors +// --------------------------------------------------------------------------- + +/// The proposer for every slot of `epoch`, computed fresh from that epoch's +/// active set and shuffling seed. +/// +/// What [`initialize_proposer_lookahead`] calls once per epoch of the window, +/// and what the specification's `process_proposer_lookahead` (not implemented +/// in this file, see the module docs) calls once more each epoch boundary to +/// extend the window by one epoch. +pub fn get_beacon_proposer_indices( + state: &BeaconState, + epoch: Epoch, +) -> Result> { + let indices = get_active_validator_indices(state, epoch); + let seed = get_seed(state, epoch, constants::DOMAIN_BEACON_PROPOSER); + compute_proposer_indices(state, epoch, seed, &indices) +} + +/// The proposer for the state's current slot. +/// +/// Fulu's replacement for [`super::accessors::get_beacon_proposer_index`]: a +/// lookup into the current epoch's slice of `proposer_lookahead` rather than +/// a shuffle computed on demand. See the module docs for why that lookup is +/// possible at all and why the on-demand version is not simply reused here. +pub fn get_beacon_proposer_index(state: &BeaconState) -> Result { + let fulu_state = fulu_state_ref(state, "get_beacon_proposer_index")?; + let index = (state.slot() % preset::SLOTS_PER_EPOCH) as usize; + fulu_state + .proposer_lookahead + .get(index) + .copied() + .ok_or(Error::IndexOutOfBounds { + index, + len: fulu_state.proposer_lookahead.len(), + }) +} + +// --------------------------------------------------------------------------- +// Fork upgrade +// --------------------------------------------------------------------------- + +/// The full lookahead window for `state`'s current epoch: every proposer from +/// the start of the current epoch through `MIN_SEED_LOOKAHEAD` full epochs +/// beyond it. +/// +/// Used to seed `BeaconState::proposer_lookahead` from nothing, at genesis and +/// when upgrading to fulu, which is the only time the whole window has to be +/// computed at once; every later epoch only needs one more epoch appended; see +/// the module docs for why that step is not implemented here. The loop runs +/// `MIN_SEED_LOOKAHEAD + 1` times (the current epoch, plus that many ahead of +/// it) because that many epochs of `SLOTS_PER_EPOCH` proposers each is exactly +/// [`preset::PROPOSER_LOOKAHEAD_LENGTH`] slots, the window's fixed length. +pub fn initialize_proposer_lookahead(state: &BeaconState) -> Result> { + let current_epoch = get_current_epoch(state); + + let mut lookahead = Vec::with_capacity(preset::PROPOSER_LOOKAHEAD_LENGTH); + for offset in 0..=preset::MIN_SEED_LOOKAHEAD { + lookahead.extend(get_beacon_proposer_indices(state, current_epoch + offset)?); + } + Ok(lookahead) +} + +// --------------------------------------------------------------------------- +// Fork projection +// --------------------------------------------------------------------------- + +/// The fulu state, mutably, or an error naming the function that needs one. +/// +/// Only [`get_beacon_proposer_index`] needs this: it is the one function in +/// this module that reads `proposer_lookahead` itself rather than working +/// through fork-invariant accessors. Kept alongside [`fulu_state_ref`] for +/// `process_proposer_lookahead`, which will need to write through this same +/// projection once it is written (see the module docs); nothing in this file +/// calls it yet. +#[allow(dead_code)] +pub(crate) fn fulu_state<'a>( + state: &'a mut BeaconState, + function: &'static str, +) -> Result<&'a mut fulu::BeaconState> { + match state { + BeaconState::Fulu(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +/// The fulu state, immutably. See [`fulu_state`]. +pub(crate) fn fulu_state_ref<'a>( + state: &'a BeaconState, + function: &'static str, +) -> Result<&'a fulu::BeaconState> { + match state { + BeaconState::Fulu(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::fork::ForkName; + + /// A fulu state with `count` fully active, full-balance validators and a + /// `proposer_lookahead` filled by [`initialize_proposer_lookahead`], + /// positioned the same way `crate::beacon::helpers::test_state::with_validators` + /// positions its phase0 state: one epoch in, so the previous epoch and + /// the block-root history window both have entries. + /// + /// The shared builder leaves `proposer_lookahead` zeroed, since that field + /// is fulu-specific and most of this module's per-fork test states never + /// touch it; this is the caller that does, so it runs the real + /// computation on top before handing the state back. + fn fulu_state_with_validators(count: usize) -> BeaconState { + let mut state = + crate::beacon::helpers::test_state::with_validators_at(ForkName::Fulu, count); + let lookahead = initialize_proposer_lookahead(&state).unwrap(); + if let BeaconState::Fulu(fulu_state) = &mut state { + fulu_state.proposer_lookahead = lookahead.try_into().expect( + "initialize_proposer_lookahead returns exactly PROPOSER_LOOKAHEAD_LENGTH indices", + ); + } + state + } + + #[test] + fn initialize_proposer_lookahead_fills_the_whole_window() { + let state = fulu_state_with_validators(32); + let lookahead = initialize_proposer_lookahead(&state).unwrap(); + assert_eq!(lookahead.len(), preset::PROPOSER_LOOKAHEAD_LENGTH); + assert!(lookahead.iter().all(|index| *index < 32)); + } + + #[test] + fn initialize_proposer_lookahead_matches_get_beacon_proposer_indices_epoch_by_epoch() { + // The window is just those two (or more, at MIN_SEED_LOOKAHEAD greater + // than one) epochs' worth of proposers concatenated, so recomputing + // each epoch independently must reproduce the same slice. + let state = fulu_state_with_validators(32); + let current_epoch = get_current_epoch(&state); + let lookahead = initialize_proposer_lookahead(&state).unwrap(); + + let mut expected = Vec::new(); + for offset in 0..=preset::MIN_SEED_LOOKAHEAD { + expected.extend(get_beacon_proposer_indices(&state, current_epoch + offset).unwrap()); + } + assert_eq!(lookahead, expected); + } + + #[test] + fn get_beacon_proposer_index_reads_the_current_slot_out_of_the_lookahead() { + let state = fulu_state_with_validators(32); + let expected = if let BeaconState::Fulu(fulu_state) = &state { + fulu_state.proposer_lookahead[(state.slot() % preset::SLOTS_PER_EPOCH) as usize] + } else { + unreachable!() + }; + assert_eq!(get_beacon_proposer_index(&state).unwrap(), expected); + } + + #[test] + fn get_beacon_proposer_index_rejects_a_state_older_than_fulu() { + let phase0_state = crate::beacon::helpers::test_state::with_validators(4); + assert!(get_beacon_proposer_index(&phase0_state).is_err()); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/helpers/math.rs b/crates/blockchain/state_transition/src/beacon/helpers/math.rs new file mode 100644 index 000000000..d0a53254f --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/math.rs @@ -0,0 +1,95 @@ +//! The specification's math helpers. + +use crate::beacon::constants::{UINT64_MAX, UINT64_MAX_SQRT}; +use crate::beacon::primitives::{Bytes32, H256}; + +/// The largest integer `x` such that `x * x <= n`. +/// +/// Newton's method, as the specification writes it. The maximum input is special +/// cased because the general algorithm's first step would overflow on it. +pub fn integer_squareroot(n: u64) -> u64 { + if n == UINT64_MAX { + return UINT64_MAX_SQRT; + } + let mut x = n; + let mut y = x.div_ceil(2); + while y < x { + x = y; + y = (x + n / x) / 2; + } + x +} + +/// The exclusive-or of two 32-byte strings. +pub fn xor(a: Bytes32, b: Bytes32) -> Bytes32 { + let mut out = [0u8; 32]; + for (index, byte) in out.iter_mut().enumerate() { + *byte = a.0[index] ^ b.0[index]; + } + H256(out) +} + +/// Interprets up to eight bytes as a little-endian integer, which is the +/// specification's `bytes_to_uint64`. +/// +/// Shorter input is zero-extended rather than rejected, since the specification +/// applies this to hash prefixes of a fixed width. +pub fn bytes_to_uint64(data: &[u8]) -> u64 { + let mut buffer = [0u8; 8]; + let take = data.len().min(8); + buffer[..take].copy_from_slice(&data[..take]); + u64::from_le_bytes(buffer) +} + +/// `a - b`, saturating at zero. +/// +/// The specification names this because Python integers do not wrap, so a +/// subtraction that would go negative has to be written explicitly. Rust's +/// `saturating_sub` is the same operation, and this exists so call sites can read +/// like the spec. +pub fn saturating_sub(a: u64, b: u64) -> u64 { + a.saturating_sub(b) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn integer_squareroot_matches_the_definition() { + for n in 0u64..100 { + let root = integer_squareroot(n); + assert!(root * root <= n, "{root}^2 should be at most {n}"); + assert!( + (root + 1) * (root + 1) > n, + "{root} should be the largest such integer for {n}" + ); + } + assert_eq!(integer_squareroot(0), 0); + assert_eq!(integer_squareroot(1), 1); + assert_eq!(integer_squareroot(u64::MAX), UINT64_MAX_SQRT); + } + + #[test] + fn integer_squareroot_handles_perfect_squares_and_their_neighbours() { + // The loop's exit condition is where an off-by-one would hide, so check + // either side of a boundary. + assert_eq!(integer_squareroot(15), 3); + assert_eq!(integer_squareroot(16), 4); + assert_eq!(integer_squareroot(17), 4); + } + + #[test] + fn xor_is_its_own_inverse() { + let a = Bytes32::repeat_byte(0xa5); + let b = Bytes32::repeat_byte(0x3c); + assert_eq!(xor(xor(a, b), b), a); + } + + #[test] + fn bytes_to_uint64_is_little_endian_and_zero_extends() { + assert_eq!(bytes_to_uint64(&[1, 0, 0, 0, 0, 0, 0, 0]), 1); + assert_eq!(bytes_to_uint64(&[0, 1]), 256); + assert_eq!(bytes_to_uint64(&[0xff; 8]), u64::MAX); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/helpers/misc.rs b/crates/blockchain/state_transition/src/beacon/helpers/misc.rs new file mode 100644 index 000000000..294b61ccf --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/misc.rs @@ -0,0 +1,199 @@ +//! Slot and epoch arithmetic, signing domains, and merkle branch verification. +//! +//! These are the helpers that depend on nothing but their arguments, so unlike +//! the accessors in [`super::accessors`] they never take a state. + +use crate::beacon::constants; +use crate::beacon::containers::shared::SigningData; +use crate::beacon::hash::hash; +use crate::beacon::preset; +use crate::beacon::primitives::{ + Bytes32, Domain, DomainType, Epoch, HashTreeRoot as _, Root, Slot, Version, +}; + +/// The epoch containing `slot`. +pub fn compute_epoch_at_slot(slot: Slot) -> Epoch { + slot / preset::SLOTS_PER_EPOCH +} + +/// The first slot of `epoch`. +pub fn compute_start_slot_at_epoch(epoch: Epoch) -> Slot { + epoch * preset::SLOTS_PER_EPOCH +} + +/// The epoch at which an activation or exit initiated during `epoch` takes +/// effect. +/// +/// The delay exists so that the committee shuffling for an epoch is already +/// settled before validators can join or leave it, which is what stops an +/// attacker from steering their own committee assignment. +pub fn compute_activation_exit_epoch(epoch: Epoch) -> Epoch { + epoch + 1 + preset::MAX_SEED_LOOKAHEAD +} + +// The root binding a fork version to a chain's genesis validator set, which +// mixes both into every signing domain. It lives in `ethlambda-types` beside +// `compute_fork_digest`, which needs it and which the networking crate needs in +// turn; re-exported here at its old path, since every signing domain below is +// built from it. +pub use ethlambda_types::beacon::fork_digest::compute_fork_data_root; + +/// The signing domain for a message type on a particular fork and chain. +/// +/// The domain is the four-byte domain type followed by the first 28 bytes of the +/// fork data root, so it fits in 32 bytes while still committing to both. +pub fn compute_domain( + domain_type: DomainType, + fork_version: Version, + genesis_validators_root: Root, +) -> Domain { + let fork_data_root = compute_fork_data_root(fork_version, genesis_validators_root); + let mut domain = [0u8; 32]; + domain[..4].copy_from_slice(&domain_type); + domain[4..].copy_from_slice(&fork_data_root.0[..28]); + domain +} + +/// The root a signature is actually computed over: the message's root combined +/// with its domain. +pub fn compute_signing_root(object_root: Root, domain: Domain) -> Root { + SigningData { + object_root, + domain, + } + .hash_tree_root() +} + +/// Whether `leaf` at `index` is proven by `branch` against `root`. +/// +/// The bit of `index` at each level decides which side the sibling goes on, so a +/// branch only verifies at the position it was generated for. +pub fn is_valid_merkle_branch( + leaf: Bytes32, + branch: &[Bytes32], + depth: u64, + index: u64, + root: Root, +) -> bool { + if branch.len() < depth as usize { + return false; + } + + let mut value = leaf; + for level in 0..depth { + let sibling = branch[level as usize]; + // Whether this leaf is the right child at this level. + let on_the_right = (index / 2u64.pow(level as u32)) % 2 == 1; + value = if on_the_right { + hash(&[sibling.0, value.0].concat()) + } else { + hash(&[value.0, sibling.0].concat()) + }; + } + value == root +} + +/// The fork version in effect at `epoch`, given the state's fork schedule. +/// +/// A message signed just before a fork boundary must still verify just after it, +/// which is why the state keeps the previous version at all. +pub fn fork_version_at_epoch( + fork: &crate::beacon::containers::shared::Fork, + epoch: Epoch, +) -> Version { + if epoch < fork.epoch { + fork.previous_version + } else { + fork.current_version + } +} + +/// The domain for a deposit signature. +/// +/// Deposits are the one message signed under a genesis-independent domain, since +/// a deposit has to be valid before the chain it funds has started, so it cannot +/// commit to a genesis validators root. +pub fn compute_deposit_domain(genesis_fork_version: Version) -> Domain { + compute_domain(constants::DOMAIN_DEPOSIT, genesis_fork_version, Root::ZERO) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::containers::shared::Fork; + + #[test] + fn slot_and_epoch_arithmetic_round_trips() { + for epoch in 0u64..5 { + let start = compute_start_slot_at_epoch(epoch); + assert_eq!(compute_epoch_at_slot(start), epoch); + // The last slot of an epoch still belongs to it. + assert_eq!( + compute_epoch_at_slot(start + preset::SLOTS_PER_EPOCH - 1), + epoch + ); + } + } + + #[test] + fn domain_carries_the_type_then_the_fork_data_prefix() { + let domain = compute_domain( + constants::DOMAIN_BEACON_ATTESTER, + [1, 0, 0, 0], + Root::repeat_byte(9), + ); + assert_eq!(&domain[..4], &constants::DOMAIN_BEACON_ATTESTER); + + let fork_data_root = compute_fork_data_root([1, 0, 0, 0], Root::repeat_byte(9)); + assert_eq!(&domain[4..], &fork_data_root.0[..28]); + } + + #[test] + fn domain_separates_forks_and_chains() { + let a = compute_domain(constants::DOMAIN_RANDAO, [1, 0, 0, 0], Root::ZERO); + let b = compute_domain(constants::DOMAIN_RANDAO, [2, 0, 0, 0], Root::ZERO); + let c = compute_domain(constants::DOMAIN_RANDAO, [1, 0, 0, 0], Root::repeat_byte(1)); + assert_ne!( + a, b, + "a different fork version must give a different domain" + ); + assert_ne!(a, c, "a different chain must give a different domain"); + } + + #[test] + fn fork_version_switches_at_the_boundary() { + let fork = Fork { + previous_version: [1, 0, 0, 0], + current_version: [2, 0, 0, 0], + epoch: 10, + }; + assert_eq!(fork_version_at_epoch(&fork, 9), [1, 0, 0, 0]); + assert_eq!(fork_version_at_epoch(&fork, 10), [2, 0, 0, 0]); + } + + #[test] + fn merkle_branch_verifies_only_at_its_own_index() { + // A two-leaf tree: root = hash(left + right). + let left = Bytes32::repeat_byte(1); + let right = Bytes32::repeat_byte(2); + let root = hash(&[left.0, right.0].concat()); + + assert!(is_valid_merkle_branch(left, &[right], 1, 0, root)); + assert!(is_valid_merkle_branch(right, &[left], 1, 1, root)); + // The same leaf and branch at the wrong index must not verify. + assert!(!is_valid_merkle_branch(left, &[right], 1, 1, root)); + } + + #[test] + fn merkle_branch_rejects_a_short_branch() { + // A branch shorter than the claimed depth would index out of bounds, so + // it has to be rejected rather than panicking. + assert!(!is_valid_merkle_branch( + Bytes32::ZERO, + &[], + 1, + 0, + Root::ZERO + )); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/helpers/mod.rs b/crates/blockchain/state_transition/src/beacon/helpers/mod.rs new file mode 100644 index 000000000..5c6f90939 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/mod.rs @@ -0,0 +1,27 @@ +//! The specification's helper functions. +//! +//! Grouped the way the specification groups them: math, predicates, the +//! committee shuffle, slot and epoch arithmetic with signing domains, state +//! accessors, and state mutators. +//! +//! One systematic difference from the spec's own signatures: the spec reads its +//! parameters from global scope, whereas here preset values are compile-time +//! constants but configuration values are not, so any function needing a +//! configuration value takes a [`crate::beacon::config::Config`]. Everything else keeps +//! the spec's name and argument order, so a call site can be checked against the +//! spec line by line. + +pub mod accessors; +pub mod altair; +pub mod attestation; +pub mod capella; +pub mod electra; +pub mod finality; +pub mod fulu; +pub mod math; +pub mod misc; +pub mod mutators; +pub mod predicates; +pub mod shuffling; +#[cfg(test)] +pub(crate) mod test_state; diff --git a/crates/blockchain/state_transition/src/beacon/helpers/mutators.rs b/crates/blockchain/state_transition/src/beacon/helpers/mutators.rs new file mode 100644 index 000000000..6f37c7360 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/mutators.rs @@ -0,0 +1,270 @@ +//! Beacon state mutators. +//! +//! These are the specification's four functions that change a state in place: +//! the two balance adjustments, and the two ways a validator leaves. + +use crate::beacon::ForkName; +use crate::beacon::config::Config; +use crate::beacon::constants::FAR_FUTURE_EPOCH; +use crate::beacon::containers::BeaconState; +use crate::beacon::error::{Error, Result}; +use crate::beacon::preset; +use crate::beacon::primitives::{Epoch, Gwei, ValidatorIndex}; + +use super::accessors::{get_beacon_proposer_index, get_current_epoch, get_validator_churn_limit}; +use super::misc::compute_activation_exit_epoch; + +/// Adds `delta` to a validator's balance. +pub fn increase_balance(state: &mut BeaconState, index: ValidatorIndex, delta: Gwei) -> Result<()> { + let balance = state + .balances_mut() + .get_mut(index as usize) + .ok_or(crate::beacon::Error::UnknownValidator(index))?; + *balance = balance.saturating_add(delta); + Ok(()) +} + +/// Subtracts `delta` from a validator's balance, flooring at zero. +/// +/// Saturating rather than checked: the specification defines a balance as +/// unsigned and explicitly floors this at zero, since a penalty larger than the +/// remaining balance is normal rather than an error. +pub fn decrease_balance(state: &mut BeaconState, index: ValidatorIndex, delta: Gwei) -> Result<()> { + let balance = state + .balances_mut() + .get_mut(index as usize) + .ok_or(crate::beacon::Error::UnknownValidator(index))?; + *balance = balance.saturating_sub(delta); + Ok(()) +} + +/// Puts a validator into the exit queue. +/// +/// Does nothing if it is already exiting, so this is safe to call more than once +/// for the same validator, which is what lets `slash_validator` call it +/// unconditionally. +/// +/// The queue epoch is the later of the earliest permissible exit and the last +/// epoch already in use, pushed out by one more if that epoch is already at the +/// churn limit. Rate limiting exits is what stops a large fraction of the +/// validator set from leaving fast enough to strand finality. +pub fn initiate_validator_exit( + state: &mut BeaconState, + index: ValidatorIndex, + config: &Config, +) -> Result<()> { + if state.validator(index)?.exit_epoch != FAR_FUTURE_EPOCH { + return Ok(()); + } + + let earliest = compute_activation_exit_epoch(get_current_epoch(state)); + let mut exit_queue_epoch = state + .validators() + .iter() + .map(|validator| validator.exit_epoch) + .filter(|epoch| *epoch != FAR_FUTURE_EPOCH) + .chain(core::iter::once(earliest)) + .max() + .unwrap_or(earliest); + + let churn_at_that_epoch = state + .validators() + .iter() + .filter(|validator| validator.exit_epoch == exit_queue_epoch) + .count() as u64; + if churn_at_that_epoch >= get_validator_churn_limit(state, config) { + exit_queue_epoch += 1; + } + + // A validator already in the queue with an exit epoch just short of + // `FAR_FUTURE_EPOCH` drags `exit_queue_epoch` up with it, and adding the + // withdrawability delay to that overflows. The specification treats a `uint64` + // overflow as invalid rather than wrapping, and wrapping here would be worse + // than a rejection: it would produce a withdrawable epoch in the past and let + // the validator withdraw immediately. + let withdrawable = exit_queue_epoch + .checked_add(config.min_validator_withdrawability_delay) + .ok_or(Error::ArithmeticOverflow( + "exit_queue_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY", + ))?; + let validator = state.validator_mut(index)?; + validator.exit_epoch = exit_queue_epoch; + validator.withdrawable_epoch = withdrawable; + Ok(()) +} + +/// Slashes a validator: exits it, penalizes it, and pays the reporter. +/// +/// The immediate penalty is only a fraction of the effective balance. The rest of +/// the punishment is applied at the epoch boundary and scales with how much of +/// the validator set was slashed around the same time, which is what makes a +/// coordinated attack far more expensive than an isolated mistake. Recording the +/// balance in `slashings` here is what lets that later computation see it. +/// +/// `whistleblower_index` defaults to the current proposer when not given. +/// +/// One copy of this function serves every fork. The immediate penalty's divisor +/// falls at altair, bellatrix, and electra, and the reporter's divisor rises at +/// electra, all without changing anything else here, so both are selected by +/// fork through [`preset::retuned`] rather than by redefining the function per +/// fork the way the specification does. +/// +/// Altair does also restate `proposer_reward` as +/// `whistleblower_reward * PROPOSER_WEIGHT / WEIGHT_DENOMINATOR` in place of +/// phase0's division by `PROPOSER_REWARD_QUOTIENT`. Those two agree exactly for +/// every input, since `PROPOSER_WEIGHT / WEIGHT_DENOMINATOR` reduces to the same +/// fraction, so this keeps phase0's spelling for all forks rather than selecting +/// between two expressions that cannot disagree. +/// +/// The exit it starts, however, is genuinely fork-dependent, which is what +/// [`initiate_validator_exit_for_fork`] exists to resolve. +/// Starts `index`'s exit under the rules of the state's own fork. +/// +/// Electra replaces [`initiate_validator_exit`] outright +/// ([`crate::beacon::helpers::electra::initiate_validator_exit`], EIP-7251): the exit +/// epoch comes from a balance-denominated churn budget rather than from +/// counting how many validators are already queued. Every other caller of +/// either version sits in a module that belongs to one fork and so names the +/// version it wants directly. [`slash_validator`] is the exception, being one +/// function that serves all seven forks, so it is the one place that has to +/// ask the state which rule applies. +/// +/// Reaching for phase0's version here instead is not a quiet inaccuracy: a +/// slashing at electra would set a different `exit_epoch`, and leave the +/// state's churn cursor unadvanced, so every subsequent exit in the same epoch +/// would queue wrongly too. +fn initiate_validator_exit_for_fork( + state: &mut BeaconState, + index: ValidatorIndex, + config: &Config, +) -> Result<()> { + match state.fork_name() { + ForkName::Electra | ForkName::Fulu => { + crate::beacon::helpers::electra::initiate_validator_exit(state, index, config) + } + _ => initiate_validator_exit(state, index, config), + } +} + +pub fn slash_validator( + state: &mut BeaconState, + slashed_index: ValidatorIndex, + whistleblower_index: Option, + config: &Config, +) -> Result<()> { + let epoch = get_current_epoch(state); + initiate_validator_exit_for_fork(state, slashed_index, config)?; + + let effective_balance = state.validator(slashed_index)?.effective_balance; + + let validator = state.validator_mut(slashed_index)?; + validator.slashed = true; + validator.withdrawable_epoch = validator + .withdrawable_epoch + .max(epoch + preset::EPOCHS_PER_SLASHINGS_VECTOR as Epoch); + + let slot = epoch as usize % preset::EPOCHS_PER_SLASHINGS_VECTOR; + let slashings = state.slashings_mut(); + slashings[slot] = slashings[slot].saturating_add(effective_balance); + + let fork = state.fork_name(); + let penalty_quotient = preset::retuned::min_slashing_penalty_quotient(fork); + decrease_balance(state, slashed_index, effective_balance / penalty_quotient)?; + + let proposer_index = get_beacon_proposer_index(state)?; + let whistleblower_index = whistleblower_index.unwrap_or(proposer_index); + let reward_quotient = preset::retuned::whistleblower_reward_quotient(fork); + let whistleblower_reward = effective_balance / reward_quotient; + let proposer_reward = whistleblower_reward / preset::PROPOSER_REWARD_QUOTIENT; + + increase_balance(state, proposer_index, proposer_reward)?; + increase_balance( + state, + whistleblower_index, + whistleblower_reward - proposer_reward, + )?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn decreasing_below_zero_floors_at_zero() { + let mut state = crate::beacon::helpers::test_state::with_validators(4); + decrease_balance(&mut state, 0, Gwei::MAX).unwrap(); + assert_eq!(state.balance(0).unwrap(), 0); + } + + #[test] + fn increasing_and_decreasing_are_inverses() { + let mut state = crate::beacon::helpers::test_state::with_validators(4); + let before = state.balance(1).unwrap(); + increase_balance(&mut state, 1, 500).unwrap(); + assert_eq!(state.balance(1).unwrap(), before + 500); + decrease_balance(&mut state, 1, 500).unwrap(); + assert_eq!(state.balance(1).unwrap(), before); + } + + #[test] + fn an_unknown_validator_is_an_error() { + let mut state = crate::beacon::helpers::test_state::with_validators(4); + assert!(increase_balance(&mut state, 99, 1).is_err()); + assert!(decrease_balance(&mut state, 99, 1).is_err()); + } + + #[test] + fn initiating_an_exit_twice_leaves_the_first_one_alone() { + let config = Config::mainnet(); + let mut state = crate::beacon::helpers::test_state::with_validators(8); + + initiate_validator_exit(&mut state, 0, &config).unwrap(); + let first = state.validator(0).unwrap().exit_epoch; + assert_ne!(first, FAR_FUTURE_EPOCH); + + // A second call must not push the validator further out. + initiate_validator_exit(&mut state, 0, &config).unwrap(); + assert_eq!(state.validator(0).unwrap().exit_epoch, first); + } + + #[test] + fn exit_sets_a_withdrawable_epoch_after_the_exit() { + let config = Config::mainnet(); + let mut state = crate::beacon::helpers::test_state::with_validators(8); + initiate_validator_exit(&mut state, 0, &config).unwrap(); + + let validator = state.validator(0).unwrap(); + assert_eq!( + validator.withdrawable_epoch, + validator.exit_epoch + config.min_validator_withdrawability_delay + ); + } + + #[test] + fn slashing_marks_exits_penalizes_and_records() { + let config = Config::mainnet(); + let mut state = crate::beacon::helpers::test_state::with_validators(32); + let effective_balance = state.validator(3).unwrap().effective_balance; + let balance_before = state.balance(3).unwrap(); + + slash_validator(&mut state, 3, None, &config).unwrap(); + + let validator = state.validator(3).unwrap(); + assert!(validator.slashed); + assert_ne!(validator.exit_epoch, FAR_FUTURE_EPOCH); + + // The effective balance is recorded for the epoch boundary's + // proportional penalty. + let epoch = get_current_epoch(&state); + assert_eq!( + state.slashings()[epoch as usize % preset::EPOCHS_PER_SLASHINGS_VECTOR], + effective_balance + ); + + // The immediate penalty is only a fraction of the effective balance, so + // the validator keeps most of its balance for now. + assert!(state.balance(3).unwrap() < balance_before); + assert!(state.balance(3).unwrap() > balance_before / 2); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/helpers/predicates.rs b/crates/blockchain/state_transition/src/beacon/helpers/predicates.rs new file mode 100644 index 000000000..13635c0db --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/predicates.rs @@ -0,0 +1,167 @@ +//! Predicates over validators and attestations. + +use crate::beacon::constants::FAR_FUTURE_EPOCH; +use crate::beacon::containers::shared::{AttestationData, Validator}; +use crate::beacon::preset; +use crate::beacon::primitives::Epoch; + +/// Whether `validator` is active at `epoch`. +pub fn is_active_validator(validator: &Validator, epoch: Epoch) -> bool { + validator.activation_epoch <= epoch && epoch < validator.exit_epoch +} + +/// Whether `validator` may join the activation queue. +/// +/// Requires the full effective balance, not merely a positive one: a partially +/// funded validator waits until its balance is topped up. +pub fn is_eligible_for_activation_queue(validator: &Validator) -> bool { + validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH + && validator.effective_balance == preset::MAX_EFFECTIVE_BALANCE +} + +/// Whether `validator` may be activated, given the finalized epoch. +/// +/// Activation waits for the queue placement itself to be finalized, so that a +/// reorg cannot retroactively change who was activated when. +pub fn is_eligible_for_activation(validator: &Validator, finalized_epoch: Epoch) -> bool { + validator.activation_eligibility_epoch <= finalized_epoch + && validator.activation_epoch == FAR_FUTURE_EPOCH +} + +/// Whether `validator` can still be slashed at `epoch`. +/// +/// Remains true until the withdrawable epoch rather than the exit epoch, which is +/// what keeps an offence punishable for a while after the validator leaves. +pub fn is_slashable_validator(validator: &Validator, epoch: Epoch) -> bool { + !validator.slashed + && validator.activation_epoch <= epoch + && epoch < validator.withdrawable_epoch +} + +/// Whether two attestations are slashable under the Casper FFG rules. +/// +/// Two cases. A double vote is two different attestations for the same target +/// epoch. A surround vote is one attestation whose source and target strictly +/// enclose the other's, which is the equivocation that would let a validator +/// support two conflicting finalizations. +pub fn is_slashable_attestation_data(data_1: &AttestationData, data_2: &AttestationData) -> bool { + let double_vote = data_1 != data_2 && data_1.target.epoch == data_2.target.epoch; + let surround_vote = + data_1.source.epoch < data_2.source.epoch && data_2.target.epoch < data_1.target.epoch; + double_vote || surround_vote +} + +/// Whether a list of attesting indices is sorted and free of duplicates, which +/// the specification requires of an `IndexedAttestation`. +/// +/// Canonical ordering matters because the attestation's root, and therefore +/// slashing evidence built on it, would otherwise depend on the order a client +/// happened to produce. +pub fn are_indices_sorted_and_unique(indices: &[u64]) -> bool { + !indices.is_empty() && indices.windows(2).all(|pair| pair[0] < pair[1]) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::containers::shared::Checkpoint; + + fn validator() -> Validator { + Validator { + activation_epoch: 5, + exit_epoch: 10, + withdrawable_epoch: 20, + effective_balance: preset::MAX_EFFECTIVE_BALANCE, + activation_eligibility_epoch: FAR_FUTURE_EPOCH, + ..Default::default() + } + } + + #[test] + fn activity_is_a_half_open_interval() { + let validator = validator(); + assert!(!is_active_validator(&validator, 4)); + assert!(is_active_validator(&validator, 5)); + assert!(is_active_validator(&validator, 9)); + assert!(!is_active_validator(&validator, 10)); + } + + #[test] + fn slashability_outlasts_activity() { + let validator = validator(); + // Past the exit epoch but before the withdrawable epoch: no longer + // active, still slashable. + assert!(!is_active_validator(&validator, 15)); + assert!(is_slashable_validator(&validator, 15)); + assert!(!is_slashable_validator(&validator, 20)); + } + + #[test] + fn an_already_slashed_validator_is_not_slashable_again() { + let mut validator = validator(); + validator.slashed = true; + assert!(!is_slashable_validator(&validator, 6)); + } + + #[test] + fn activation_queue_eligibility_needs_the_full_balance() { + let mut validator = validator(); + assert!(is_eligible_for_activation_queue(&validator)); + + validator.effective_balance -= 1; + assert!(!is_eligible_for_activation_queue(&validator)); + } + + fn data(source: Epoch, target: Epoch, root: u8) -> AttestationData { + AttestationData { + source: Checkpoint { + epoch: source, + root: Default::default(), + }, + target: Checkpoint { + epoch: target, + root: crate::beacon::primitives::Root::repeat_byte(root), + }, + ..Default::default() + } + } + + #[test] + fn identical_attestations_are_not_slashable() { + let one = data(1, 2, 0); + assert!(!is_slashable_attestation_data(&one, &one)); + } + + #[test] + fn a_double_vote_is_slashable() { + // Same target epoch, different content. + let a = data(1, 2, 1); + let b = data(1, 2, 2); + assert!(is_slashable_attestation_data(&a, &b)); + } + + #[test] + fn a_surround_vote_is_slashable_in_one_direction_only() { + // a's span strictly encloses b's. + let a = data(1, 6, 1); + let b = data(2, 5, 2); + assert!(is_slashable_attestation_data(&a, &b)); + // The predicate is asymmetric: the caller checks both orders. + assert!(!is_slashable_attestation_data(&b, &a)); + } + + #[test] + fn non_overlapping_attestations_are_not_slashable() { + let a = data(1, 2, 1); + let b = data(3, 4, 2); + assert!(!is_slashable_attestation_data(&a, &b)); + } + + #[test] + fn indices_must_be_sorted_unique_and_non_empty() { + assert!(are_indices_sorted_and_unique(&[0, 1, 5])); + assert!(!are_indices_sorted_and_unique(&[])); + assert!(!are_indices_sorted_and_unique(&[1, 1])); + assert!(!are_indices_sorted_and_unique(&[5, 1])); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/helpers/shuffling.rs b/crates/blockchain/state_transition/src/beacon/helpers/shuffling.rs new file mode 100644 index 000000000..e838bbb69 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/shuffling.rs @@ -0,0 +1,226 @@ +//! The committee shuffle. +//! +//! The specification shuffles with the "swap-or-not" construction, which has two +//! properties the beacon chain needs. It is a permutation, so every validator +//! lands in exactly one committee. And it can be evaluated for a single index +//! without computing the whole permutation, which is what lets a client work out +//! one committee without shuffling the entire registry. +//! +//! The cost is that shuffling one index runs `SHUFFLE_ROUND_COUNT` rounds of +//! hashing, so computing a whole committee this way rehashes the same rounds +//! repeatedly. That is the specification's own formulation and what the fixtures +//! pin down, so it is what this implements. + +use crate::beacon::error::{Error, Result}; +use crate::beacon::hash::hash; +use crate::beacon::preset; +use crate::beacon::primitives::{Bytes32, Gwei, ValidatorIndex}; + +use super::math::bytes_to_uint64; + +/// Where `index` ends up after shuffling a set of `index_count` items under +/// `seed`. +/// +/// Fails if `index` is not in range, which the specification asserts. +pub fn compute_shuffled_index(index: u64, index_count: u64, seed: Bytes32) -> Result { + crate::beacon::verify(index < index_count, "index < index_count")?; + + let mut index = index; + for round in 0..preset::SHUFFLE_ROUND_COUNT { + let round_byte = round as u8; + + // The pivot for this round, derived from the seed and the round number. + let mut pivot_input = Vec::with_capacity(33); + pivot_input.extend_from_slice(&seed.0); + pivot_input.push(round_byte); + let pivot = bytes_to_uint64(&hash(&pivot_input).0[0..8]) % index_count; + + // The position `index` would swap with, and the higher of the two, which + // is the one the decision bit is drawn for. Taking the maximum is what + // makes the swap symmetric, and therefore a permutation. + let flip = (pivot + index_count - index) % index_count; + let position = index.max(flip); + + // One bit out of a hash covering a 256-position window, so a whole + // window's decisions come from a single hash. + let mut source_input = Vec::with_capacity(37); + source_input.extend_from_slice(&seed.0); + source_input.push(round_byte); + source_input.extend_from_slice(&((position / 256) as u32).to_le_bytes()); + let source = hash(&source_input); + + let byte = source.0[((position % 256) / 8) as usize]; + let bit = (byte >> (position % 8)) % 2; + if bit == 1 { + index = flip; + } + } + + Ok(index) +} + +/// The `index`-th of `count` committees drawn from `indices` under `seed`. +pub fn compute_committee( + indices: &[ValidatorIndex], + seed: Bytes32, + index: u64, + count: u64, +) -> Result> { + crate::beacon::verify(count > 0, "count > 0")?; + + let total = indices.len() as u64; + let start = (total * index) / count; + let end = (total * (index + 1)) / count; + + let mut committee = Vec::with_capacity((end - start) as usize); + for position in start..end { + let shuffled = compute_shuffled_index(position, total, seed)?; + let validator = indices + .get(shuffled as usize) + .ok_or(Error::IndexOutOfBounds { + index: shuffled as usize, + len: indices.len(), + })?; + committee.push(*validator); + } + Ok(committee) +} + +/// A proposer sampled from `indices`, weighted by effective balance. +/// +/// Rejection sampling rather than a weighted draw: a candidate is picked +/// uniformly, then accepted with probability proportional to its effective +/// balance. That keeps the result computable from the seed alone, with no running +/// total to agree on, at the cost of an unbounded (but in practice very short) +/// number of attempts. +/// +/// `effective_balance_of` returns the effective balance for a validator index, so +/// this stays independent of which fork's state it is reading. +/// +/// Serves phase0 through deneb only. Electra widens the acceptance test's +/// random draw from one byte to two and weighs against +/// [`preset::MAX_EFFECTIVE_BALANCE_ELECTRA`] rather than a caller-supplied +/// ceiling (EIP-7251: a compounding validator's effective balance can now +/// reach values an 8-bit draw no longer discriminates finely enough between), +/// so from electra on the acceptance test itself changes, not only the +/// ceiling passed in here: [`crate::beacon::helpers::electra::compute_proposer_index`] +/// is electra's (and fulu's) own copy, not a caller of this one with a +/// different `max_effective_balance`. +/// [`crate::beacon::helpers::accessors::get_beacon_proposer_index`] is where the two +/// are dispatched between by fork; do not call this one directly for a state +/// that might be electra or later. +pub fn compute_proposer_index( + indices: &[ValidatorIndex], + seed: Bytes32, + max_effective_balance: Gwei, + mut effective_balance_of: impl FnMut(ValidatorIndex) -> Result, +) -> Result { + crate::beacon::verify(!indices.is_empty(), "len(indices) > 0")?; + + const MAX_RANDOM_BYTE: u64 = u8::MAX as u64; + let total = indices.len() as u64; + + let mut attempt = 0u64; + loop { + let shuffled = compute_shuffled_index(attempt % total, total, seed)?; + let candidate = indices[shuffled as usize]; + + let mut random_input = Vec::with_capacity(40); + random_input.extend_from_slice(&seed.0); + random_input.extend_from_slice(&(attempt / 32).to_le_bytes()); + let random_byte = hash(&random_input).0[(attempt % 32) as usize] as u64; + + let effective_balance = effective_balance_of(candidate)?; + if effective_balance * MAX_RANDOM_BYTE >= max_effective_balance * random_byte { + return Ok(candidate); + } + + attempt += 1; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn shuffling_is_a_permutation() { + // Every index must map to a distinct index in range, otherwise a + // validator would land in two committees or none. + let seed = Bytes32::repeat_byte(0x42); + let count = 25u64; + + let mut seen = vec![false; count as usize]; + for index in 0..count { + let shuffled = compute_shuffled_index(index, count, seed).unwrap(); + assert!(shuffled < count); + assert!(!seen[shuffled as usize], "{shuffled} produced twice"); + seen[shuffled as usize] = true; + } + assert!(seen.into_iter().all(|hit| hit)); + } + + #[test] + fn shuffling_depends_on_the_seed() { + let count = 20u64; + let a: Vec = (0..count) + .map(|i| compute_shuffled_index(i, count, Bytes32::repeat_byte(1)).unwrap()) + .collect(); + let b: Vec = (0..count) + .map(|i| compute_shuffled_index(i, count, Bytes32::repeat_byte(2)).unwrap()) + .collect(); + assert_ne!(a, b); + } + + #[test] + fn an_out_of_range_index_is_rejected() { + assert!(compute_shuffled_index(5, 5, Bytes32::ZERO).is_err()); + } + + #[test] + fn committees_partition_the_validator_set() { + // Splitting into `count` committees must cover every validator exactly + // once, since the split is over positions of one permutation. + let indices: Vec = (0..40).collect(); + let seed = Bytes32::repeat_byte(7); + let count = 4; + + let mut all = Vec::new(); + for index in 0..count { + all.extend(compute_committee(&indices, seed, index, count).unwrap()); + } + all.sort_unstable(); + assert_eq!(all, indices); + } + + #[test] + fn proposer_selection_prefers_a_full_balance() { + // With one full-balance validator and the rest at a token balance, the + // full one should be chosen overwhelmingly often. This checks the + // acceptance test is the right way round, which a uniform draw would not + // catch. + let indices: Vec = (0..16).collect(); + let max = 32_000_000_000u64; + + let mut chose_the_rich_one = 0; + for trial in 0..32u8 { + let chosen = + compute_proposer_index(&indices, Bytes32::repeat_byte(trial), max, |index| { + Ok(if index == 3 { max } else { 1 }) + }) + .unwrap(); + if chosen == 3 { + chose_the_rich_one += 1; + } + } + assert!( + chose_the_rich_one > 16, + "the full-balance validator was chosen {chose_the_rich_one} times out of 32" + ); + } + + #[test] + fn proposer_selection_rejects_an_empty_set() { + assert!(compute_proposer_index(&[], Bytes32::ZERO, 1, |_| Ok(1)).is_err()); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/helpers/test_state.rs b/crates/blockchain/state_transition/src/beacon/helpers/test_state.rs new file mode 100644 index 000000000..9e4293f90 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/helpers/test_state.rs @@ -0,0 +1,509 @@ +//! A minimal state builder shared by the helper tests. +//! +//! Several helpers can only be exercised against a state with a populated +//! validator registry and correctly sized history vectors, and building one by +//! hand in each test would bury the assertion under setup. Test-only: nothing in +//! the crate's public surface depends on it. +//! +//! [`with_validators`] builds a phase0 state; [`with_validators_at`] +//! generalises it to every other fork. Each fork used to grow its own +//! near-duplicate of the same struct literal, one per test module that first +//! needed a state in that fork's shape: `crate::beacon::helpers::altair`, +//! `crate::beacon::stf::bellatrix`, `crate::beacon::stf::capella` and +//! `crate::beacon::stf::epoch::capella` (identical to each other), +//! `crate::beacon::stf::epoch::registry`, `crate::beacon::helpers::electra` (which grew two, +//! electra's and a fulu one) and `crate::beacon::stf::epoch::electra` (identical to +//! `helpers::electra`'s electra one), and `crate::beacon::stf::fulu`, +//! `crate::beacon::helpers::fulu`, and `crate::beacon::stf::epoch::fulu` (the latter two +//! identical to each other). This module is now the one place that shape is +//! built; a caller whose test needs something beyond the default (a +//! caller-supplied execution payload header, real BLS pubkeys, a state +//! positioned many epochs past genesis) builds the default here and then +//! applies its own small, documented override, the same way it would change +//! any other already-built state's field. + +use crate::beacon::constants; +use crate::beacon::containers::shared::{ + Balances, EpochParticipation, InactivityScores, Validator, +}; +use crate::beacon::containers::{ + BeaconState, BlockRoots, RandaoMixes, Slashings, altair, bellatrix, capella, deneb, electra, + fulu, phase0, +}; +use crate::beacon::fork::ForkName; +use crate::beacon::lean_fork_unreachable; +use crate::beacon::preset; +use crate::beacon::primitives::{ + BlsPubkey, Bytes32, ExecutionAddress, ExecutionBlockHash, Gwei, Root, Uint256, +}; + +/// A deterministic but genuinely valid BLS public key for validator `index`. +/// +/// A zero pubkey is not a curve point, so anything that aggregates or validates +/// keys rejects it. That makes the all-default validator unusable for the sync +/// committee, which aggregates its members' keys, and it would silently limit +/// every later fork's tests in the same way. Deriving a real key from the index +/// keeps the state reproducible while letting the BLS paths run. +fn pubkey_for(index: usize) -> BlsPubkey { + let mut ikm = [0u8; 32]; + ikm[..8].copy_from_slice(&(index as u64 + 1).to_le_bytes()); + let secret = blst::min_pk::SecretKey::key_gen(&ikm, &[]) + .expect("32 bytes of input material is enough for key generation"); + BlsPubkey(secret.sk_to_pk().to_bytes()) +} + +/// A phase0 state with `count` fully active, full-balance validators, positioned +/// one epoch in so that the previous epoch exists and the block root window has +/// entries behind it. +pub fn with_validators(count: usize) -> BeaconState { + let validators: Vec = (0..count) + .map(|index| Validator { + pubkey: pubkey_for(index), + effective_balance: preset::MAX_EFFECTIVE_BALANCE, + activation_eligibility_epoch: 0, + activation_epoch: 0, + exit_epoch: constants::FAR_FUTURE_EPOCH, + withdrawable_epoch: constants::FAR_FUTURE_EPOCH, + ..Default::default() + }) + .collect(); + + BeaconState::Phase0(phase0::BeaconState { + genesis_time: 0, + genesis_validators_root: Root::ZERO, + slot: preset::SLOTS_PER_EPOCH, + fork: Default::default(), + latest_block_header: Default::default(), + block_roots: vec![Root::ZERO; preset::SLOTS_PER_HISTORICAL_ROOT] + .try_into() + .expect("the vector is built at its exact length"), + state_roots: vec![Root::ZERO; preset::SLOTS_PER_HISTORICAL_ROOT] + .try_into() + .expect("the vector is built at its exact length"), + historical_roots: Default::default(), + eth1_data: Default::default(), + eth1_data_votes: Default::default(), + eth1_deposit_index: 0, + validators: validators + .try_into() + .expect("count is far below VALIDATOR_REGISTRY_LIMIT"), + balances: vec![preset::MAX_EFFECTIVE_BALANCE; count] + .try_into() + .expect("count is far below VALIDATOR_REGISTRY_LIMIT"), + randao_mixes: vec![Bytes32::ZERO; preset::EPOCHS_PER_HISTORICAL_VECTOR] + .try_into() + .expect("the vector is built at its exact length"), + slashings: vec![0; preset::EPOCHS_PER_SLASHINGS_VECTOR] + .try_into() + .expect("the vector is built at its exact length"), + previous_epoch_attestations: Default::default(), + current_epoch_attestations: Default::default(), + justification_bits: Default::default(), + previous_justified_checkpoint: Default::default(), + current_justified_checkpoint: Default::default(), + finalized_checkpoint: Default::default(), + }) +} + +/// The [`with_validators`] counterpart for every fork phase0 through fulu. +/// +/// Builds `count` fully active, full-balance validators, positioned one epoch +/// in exactly like [`with_validators`], with every field a later fork adds +/// (participation flags, inactivity scores, sync committees, an execution +/// payload header, the withdrawal cursor and historical summaries, the +/// electra pending queues, fulu's proposer lookahead) left at its own +/// all-default placeholder. A test that needs one of those fields to hold +/// something other than the placeholder builds this and overrides it +/// afterward; see `crate::beacon::stf::electra::tests::electra_state_with_validators` +/// for an example that overrides several at once. +pub fn with_validators_at(fork: ForkName, count: usize) -> BeaconState { + match fork { + ForkName::Phase0 => with_validators(count), + ForkName::Altair => BeaconState::Altair(altair_state(count)), + ForkName::Bellatrix => BeaconState::Bellatrix(bellatrix_state(count)), + ForkName::Capella => BeaconState::Capella(capella_state(count)), + ForkName::Deneb => BeaconState::Deneb(deneb_state(count)), + ForkName::Electra => BeaconState::Electra(electra_state(count)), + ForkName::Fulu => BeaconState::Fulu(fulu_state(count)), + // A test asking for a lean state from a beacon builder, which no fixture + // fork name can produce; the `fork:` form, since the argument is the + // whole input. + ForkName::Lean => lean_fork_unreachable("with_validators_at"), + } +} + +// -- Pieces shared by every fork's state literal below ----------------------- +// +// None of these are fork-specific on their own; what varies fork to fork is +// which of them a given `BeaconState` variant has a field for, which is why +// `with_validators_at`'s match arms below still need one struct literal per +// fork rather than a single generic constructor. + +/// `count` validators, each with `effective_balance` and otherwise eligible, +/// active since genesis, and never exiting. +fn full_validators( + count: usize, + effective_balance: Gwei, +) -> crate::beacon::containers::shared::Validators { + let validators: Vec = (0..count) + .map(|_| Validator { + effective_balance, + activation_eligibility_epoch: 0, + activation_epoch: 0, + exit_epoch: constants::FAR_FUTURE_EPOCH, + withdrawable_epoch: constants::FAR_FUTURE_EPOCH, + ..Default::default() + }) + .collect(); + validators + .try_into() + .expect("count is far below VALIDATOR_REGISTRY_LIMIT") +} + +/// `count` balances, each matching [`full_validators`]'s `effective_balance`. +fn full_balances(count: usize, effective_balance: Gwei) -> Balances { + vec![effective_balance; count] + .try_into() + .expect("count is far below VALIDATOR_REGISTRY_LIMIT") +} + +/// An all-zero `block_roots`/`state_roots` vector: both fields share this +/// exact type, so one builder serves either. +fn zero_root_vector() -> BlockRoots { + vec![Root::ZERO; preset::SLOTS_PER_HISTORICAL_ROOT] + .try_into() + .expect("the vector is built at its exact length") +} + +fn zero_randao_mixes() -> RandaoMixes { + vec![Bytes32::ZERO; preset::EPOCHS_PER_HISTORICAL_VECTOR] + .try_into() + .expect("the vector is built at its exact length") +} + +fn zero_slashings() -> Slashings { + vec![0; preset::EPOCHS_PER_SLASHINGS_VECTOR] + .try_into() + .expect("the vector is built at its exact length") +} + +/// An all-zero `previous_epoch_participation`/`current_epoch_participation` +/// vector, one entry per validator. +fn zero_participation(count: usize) -> EpochParticipation { + vec![0; count] + .try_into() + .expect("count is far below VALIDATOR_REGISTRY_LIMIT") +} + +fn zero_inactivity_scores(count: usize) -> InactivityScores { + vec![0; count] + .try_into() + .expect("count is far below VALIDATOR_REGISTRY_LIMIT") +} + +/// A sync committee with every seat at its all-default (invalid-as-a-curve- +/// point) pubkey. Good enough for tests that only need the field populated at +/// the right length, not for anything that aggregates or verifies against it. +fn empty_sync_committee() -> altair::SyncCommittee { + altair::SyncCommittee { + pubkeys: vec![BlsPubkey::default(); preset::SYNC_COMMITTEE_SIZE] + .try_into() + .expect("built at exactly SYNC_COMMITTEE_SIZE"), + aggregate_pubkey: BlsPubkey::default(), + } +} + +/// An all-default execution payload header in bellatrix's shape (no +/// `withdrawals_root`, no blob fields), standing in for the genesis payload. +fn empty_bellatrix_execution_payload_header() -> bellatrix::ExecutionPayloadHeader { + bellatrix::ExecutionPayloadHeader { + parent_hash: ExecutionBlockHash::ZERO, + fee_recipient: ExecutionAddress::ZERO, + state_root: Bytes32::ZERO, + receipts_root: Bytes32::ZERO, + logs_bloom: vec![0u8; preset::BYTES_PER_LOGS_BLOOM] + .try_into() + .expect("built at exactly BYTES_PER_LOGS_BLOOM"), + prev_randao: Bytes32::ZERO, + block_number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: 0, + extra_data: Default::default(), + base_fee_per_gas: Uint256::ZERO, + block_hash: ExecutionBlockHash::ZERO, + transactions_root: Root::ZERO, + } +} + +/// The capella-shaped counterpart of +/// [`empty_bellatrix_execution_payload_header`]: adds `withdrawals_root`. +fn empty_capella_execution_payload_header() -> capella::ExecutionPayloadHeader { + capella::ExecutionPayloadHeader { + parent_hash: ExecutionBlockHash::ZERO, + fee_recipient: ExecutionAddress::ZERO, + state_root: Bytes32::ZERO, + receipts_root: Bytes32::ZERO, + logs_bloom: vec![0u8; preset::BYTES_PER_LOGS_BLOOM] + .try_into() + .expect("built at exactly BYTES_PER_LOGS_BLOOM"), + prev_randao: Bytes32::ZERO, + block_number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: 0, + extra_data: Default::default(), + base_fee_per_gas: Uint256::ZERO, + block_hash: ExecutionBlockHash::ZERO, + transactions_root: Root::ZERO, + withdrawals_root: Root::ZERO, + } +} + +/// The deneb-shaped counterpart of [`empty_capella_execution_payload_header`]: +/// adds the blob fields. Electra and fulu keep this same shape unchanged (see +/// `crate::beacon::containers` module docs), so this builds their header too. +fn empty_deneb_execution_payload_header() -> deneb::ExecutionPayloadHeader { + deneb::ExecutionPayloadHeader { + parent_hash: ExecutionBlockHash::ZERO, + fee_recipient: ExecutionAddress::ZERO, + state_root: Bytes32::ZERO, + receipts_root: Bytes32::ZERO, + logs_bloom: vec![0u8; preset::BYTES_PER_LOGS_BLOOM] + .try_into() + .expect("built at exactly BYTES_PER_LOGS_BLOOM"), + prev_randao: Bytes32::ZERO, + block_number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: 0, + extra_data: Default::default(), + base_fee_per_gas: Uint256::ZERO, + block_hash: ExecutionBlockHash::ZERO, + transactions_root: Root::ZERO, + withdrawals_root: Root::ZERO, + blob_gas_used: 0, + excess_blob_gas: 0, + } +} + +// -- One struct literal per fork --------------------------------------------- + +fn altair_state(count: usize) -> altair::BeaconState { + altair::BeaconState { + genesis_time: 0, + genesis_validators_root: Root::ZERO, + slot: preset::SLOTS_PER_EPOCH, + fork: Default::default(), + latest_block_header: Default::default(), + block_roots: zero_root_vector(), + state_roots: zero_root_vector(), + historical_roots: Default::default(), + eth1_data: Default::default(), + eth1_data_votes: Default::default(), + eth1_deposit_index: 0, + validators: full_validators(count, preset::MAX_EFFECTIVE_BALANCE), + balances: full_balances(count, preset::MAX_EFFECTIVE_BALANCE), + randao_mixes: zero_randao_mixes(), + slashings: zero_slashings(), + previous_epoch_participation: zero_participation(count), + current_epoch_participation: zero_participation(count), + justification_bits: Default::default(), + previous_justified_checkpoint: Default::default(), + current_justified_checkpoint: Default::default(), + finalized_checkpoint: Default::default(), + inactivity_scores: zero_inactivity_scores(count), + current_sync_committee: empty_sync_committee(), + next_sync_committee: empty_sync_committee(), + } +} + +fn bellatrix_state(count: usize) -> bellatrix::BeaconState { + bellatrix::BeaconState { + genesis_time: 0, + genesis_validators_root: Root::ZERO, + slot: preset::SLOTS_PER_EPOCH, + fork: Default::default(), + latest_block_header: Default::default(), + block_roots: zero_root_vector(), + state_roots: zero_root_vector(), + historical_roots: Default::default(), + eth1_data: Default::default(), + eth1_data_votes: Default::default(), + eth1_deposit_index: 0, + validators: full_validators(count, preset::MAX_EFFECTIVE_BALANCE), + balances: full_balances(count, preset::MAX_EFFECTIVE_BALANCE), + randao_mixes: zero_randao_mixes(), + slashings: zero_slashings(), + previous_epoch_participation: zero_participation(count), + current_epoch_participation: zero_participation(count), + justification_bits: Default::default(), + previous_justified_checkpoint: Default::default(), + current_justified_checkpoint: Default::default(), + finalized_checkpoint: Default::default(), + inactivity_scores: zero_inactivity_scores(count), + current_sync_committee: empty_sync_committee(), + next_sync_committee: empty_sync_committee(), + // Thrown away by every real caller, which needs a specific payload + // (or lack of one) under test and overrides this right after; see + // `crate::beacon::stf::bellatrix::tests::bellatrix_state_with_validators`. + latest_execution_payload_header: empty_bellatrix_execution_payload_header(), + } +} + +fn capella_state(count: usize) -> capella::BeaconState { + capella::BeaconState { + genesis_time: 0, + genesis_validators_root: Root::ZERO, + slot: preset::SLOTS_PER_EPOCH, + fork: Default::default(), + latest_block_header: Default::default(), + block_roots: zero_root_vector(), + state_roots: zero_root_vector(), + historical_roots: Default::default(), + eth1_data: Default::default(), + eth1_data_votes: Default::default(), + eth1_deposit_index: 0, + validators: full_validators(count, preset::MAX_EFFECTIVE_BALANCE), + balances: full_balances(count, preset::MAX_EFFECTIVE_BALANCE), + randao_mixes: zero_randao_mixes(), + slashings: zero_slashings(), + previous_epoch_participation: zero_participation(count), + current_epoch_participation: zero_participation(count), + justification_bits: Default::default(), + previous_justified_checkpoint: Default::default(), + current_justified_checkpoint: Default::default(), + finalized_checkpoint: Default::default(), + inactivity_scores: zero_inactivity_scores(count), + current_sync_committee: empty_sync_committee(), + next_sync_committee: empty_sync_committee(), + latest_execution_payload_header: empty_capella_execution_payload_header(), + next_withdrawal_index: 0, + next_withdrawal_validator_index: 0, + historical_summaries: Default::default(), + } +} + +fn deneb_state(count: usize) -> deneb::BeaconState { + deneb::BeaconState { + genesis_time: 0, + genesis_validators_root: Root::ZERO, + slot: preset::SLOTS_PER_EPOCH, + fork: Default::default(), + latest_block_header: Default::default(), + block_roots: zero_root_vector(), + state_roots: zero_root_vector(), + historical_roots: Default::default(), + eth1_data: Default::default(), + eth1_data_votes: Default::default(), + eth1_deposit_index: 0, + validators: full_validators(count, preset::MAX_EFFECTIVE_BALANCE), + balances: full_balances(count, preset::MAX_EFFECTIVE_BALANCE), + randao_mixes: zero_randao_mixes(), + slashings: zero_slashings(), + previous_epoch_participation: zero_participation(count), + current_epoch_participation: zero_participation(count), + justification_bits: Default::default(), + previous_justified_checkpoint: Default::default(), + current_justified_checkpoint: Default::default(), + finalized_checkpoint: Default::default(), + inactivity_scores: zero_inactivity_scores(count), + current_sync_committee: empty_sync_committee(), + next_sync_committee: empty_sync_committee(), + latest_execution_payload_header: empty_deneb_execution_payload_header(), + next_withdrawal_index: 0, + next_withdrawal_validator_index: 0, + historical_summaries: Default::default(), + } +} + +fn electra_state(count: usize) -> electra::BeaconState { + electra::BeaconState { + genesis_time: 0, + genesis_validators_root: Root::ZERO, + slot: preset::SLOTS_PER_EPOCH, + fork: Default::default(), + latest_block_header: Default::default(), + block_roots: zero_root_vector(), + state_roots: zero_root_vector(), + historical_roots: Default::default(), + eth1_data: Default::default(), + eth1_data_votes: Default::default(), + eth1_deposit_index: 0, + validators: full_validators(count, preset::MIN_ACTIVATION_BALANCE), + balances: full_balances(count, preset::MIN_ACTIVATION_BALANCE), + randao_mixes: zero_randao_mixes(), + slashings: zero_slashings(), + previous_epoch_participation: zero_participation(count), + current_epoch_participation: zero_participation(count), + justification_bits: Default::default(), + previous_justified_checkpoint: Default::default(), + current_justified_checkpoint: Default::default(), + finalized_checkpoint: Default::default(), + inactivity_scores: zero_inactivity_scores(count), + current_sync_committee: empty_sync_committee(), + next_sync_committee: empty_sync_committee(), + latest_execution_payload_header: empty_deneb_execution_payload_header(), + next_withdrawal_index: 0, + next_withdrawal_validator_index: 0, + historical_summaries: Default::default(), + deposit_requests_start_index: constants::UNSET_DEPOSIT_REQUESTS_START_INDEX, + deposit_balance_to_consume: 0, + exit_balance_to_consume: 0, + earliest_exit_epoch: 0, + consolidation_balance_to_consume: 0, + earliest_consolidation_epoch: 0, + pending_deposits: Default::default(), + pending_partial_withdrawals: Default::default(), + pending_consolidations: Default::default(), + } +} + +fn fulu_state(count: usize) -> fulu::BeaconState { + fulu::BeaconState { + genesis_time: 0, + genesis_validators_root: Root::ZERO, + slot: preset::SLOTS_PER_EPOCH, + fork: Default::default(), + latest_block_header: Default::default(), + block_roots: zero_root_vector(), + state_roots: zero_root_vector(), + historical_roots: Default::default(), + eth1_data: Default::default(), + eth1_data_votes: Default::default(), + eth1_deposit_index: 0, + validators: full_validators(count, preset::MAX_EFFECTIVE_BALANCE), + balances: full_balances(count, preset::MAX_EFFECTIVE_BALANCE), + randao_mixes: zero_randao_mixes(), + slashings: zero_slashings(), + previous_epoch_participation: zero_participation(count), + current_epoch_participation: zero_participation(count), + justification_bits: Default::default(), + previous_justified_checkpoint: Default::default(), + current_justified_checkpoint: Default::default(), + finalized_checkpoint: Default::default(), + inactivity_scores: zero_inactivity_scores(count), + current_sync_committee: empty_sync_committee(), + next_sync_committee: empty_sync_committee(), + latest_execution_payload_header: empty_deneb_execution_payload_header(), + next_withdrawal_index: 0, + next_withdrawal_validator_index: 0, + historical_summaries: Default::default(), + deposit_requests_start_index: constants::UNSET_DEPOSIT_REQUESTS_START_INDEX, + deposit_balance_to_consume: 0, + exit_balance_to_consume: 0, + earliest_exit_epoch: 0, + consolidation_balance_to_consume: 0, + earliest_consolidation_epoch: 0, + pending_deposits: Default::default(), + pending_partial_withdrawals: Default::default(), + pending_consolidations: Default::default(), + // Left at zero rather than run through `initialize_proposer_lookahead`: + // that is a derived value a fulu-specific test can compute for itself + // and override (see `crate::beacon::helpers::fulu::tests::fulu_state_with_validators`), + // and this builder has no fulu-specific import to spare for it. + proposer_lookahead: vec![0; preset::PROPOSER_LOOKAHEAD_LENGTH] + .try_into() + .expect("the vector is built at its exact length"), + } +} diff --git a/crates/blockchain/state_transition/src/beacon/kzg.rs b/crates/blockchain/state_transition/src/beacon/kzg.rs new file mode 100644 index 000000000..f6c892a81 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/kzg.rs @@ -0,0 +1,968 @@ +//! KZG polynomial commitments: EIP-4844 blobs (deneb) and their EIP-7594 cell +//! proofs (fulu). +//! +//! This module wraps [`c-kzg`](https://github.com/ethereum/c-kzg-4844), the C +//! library the specification's own polynomial-commitments documents describe, +//! and exposes it under the specification's own function names so call sites +//! read like `specs/deneb/polynomial-commitments.md` and +//! `specs/fulu/polynomial-commitments-sampling.md` rather than like c-kzg's +//! Rust bindings. +//! +//! c-kzg's public API stops short of two helpers those documents define and +//! whose fixture suites call directly: `compute_challenge` and +//! `compute_verify_cell_kzg_proof_batch_challenge`. Both build a Fiat-Shamir +//! transcript (a domain separator, some fixed-width integers, and the +//! arguments' raw bytes), hash it, and reduce the digest modulo the BLS +//! scalar field. c-kzg keeps them as private steps of its own +//! `compute_blob_kzg_proof`/`verify_blob_kzg_proof` and +//! `verify_cell_kzg_proof_batch` and does not export them, so they are +//! reimplemented here directly from the spec text. +//! +//! Every function accepts untrusted bytes and returns [`Result`] rather than +//! panicking. The deneb spec says as much of its own public functions: they +//! "MUST accept raw bytes as input and perform the required cryptographic +//! normalization before invoking any internal functions" (polynomial +//! commitments, introduction). A blob of the wrong length, a field element +//! that is not canonically reduced, or a byte string that does not decode to +//! a curve point is exactly the input that normalization step exists to +//! reject, and the fixture suites downloaded for this module test that +//! rejection directly: many cases have `output: null`, meaning the operation +//! must fail rather than panic. + +use std::sync::LazyLock; + +use num_bigint::BigUint; + +use crate::beacon::error::{Error, Result, verify}; +use crate::beacon::hash::hash; +use crate::beacon::primitives::{Bytes32, H256, KzgCommitment, KzgProof}; + +/// The cells (equivalently, proofs) produced from one extended blob: the +/// fulu spec's `CELLS_PER_EXT_BLOB`-length vectors. +type CellsPerExtBlob = [c_kzg::Cell; c_kzg::CELLS_PER_EXT_BLOB]; +/// A proof for each cell of an extended blob. +type ProofsPerExtBlob = [KzgProof; c_kzg::CELLS_PER_EXT_BLOB]; + +/// The Ethereum mainnet trusted setup, parsed once. +/// +/// The setup is four thousand G1 points in both monomial and Lagrange form +/// plus sixty-five G2 points, embedded in the `c-kzg` binary by the +/// `ethereum_kzg_settings` feature. Parsing that is not free, and every +/// function in this module needs the result, so a per-call load would repeat +/// the parse on every gossiped blob and every block. `LazyLock` runs it +/// exactly once, on first use; every later call reuses the same settings. +/// c-kzg's own `ethereum_kzg_settings` helper happens to cache internally as +/// well, but wrapping it here keeps that behavior a property of this module's +/// code rather than an implementation detail of c-kzg's that this module would +/// otherwise be relying on implicitly. +/// +/// The precompute argument (0-15) trades memory for faster +/// `verify_kzg_proof`/`verify_blob_kzg_proof`. Nothing in this module verifies +/// KZG proofs in a hot loop, so 0 keeps the smaller footprint rather than +/// spending memory on precomputed tables this module would rarely use. +static KZG_SETTINGS: LazyLock<&'static c_kzg::KzgSettings> = + LazyLock::new(|| c_kzg::ethereum_kzg_settings(0)); + +/// Scalar field modulus of BLS12-381: the deneb spec's `BLS_MODULUS`, copied +/// verbatim from its constants table. +const BLS_MODULUS_DECIMAL: &str = + "52435875175126190479447740508185965837690552500527637822603658699938581184513"; + +/// `BLS_MODULUS`, parsed once rather than on every challenge computed. +static BLS_MODULUS: LazyLock = LazyLock::new(|| { + BigUint::parse_bytes(BLS_MODULUS_DECIMAL.as_bytes(), 10) + .expect("BLS_MODULUS_DECIMAL is a valid base-10 literal") +}); + +/// Parses raw bytes into a c-kzg blob, rejecting anything but exactly +/// `BYTES_PER_BLOB` bytes. +fn to_blob(bytes: &[u8]) -> Result { + c_kzg::Blob::from_bytes(bytes).map_err(|_| Error::SpecAssert("len(blob) == BYTES_PER_BLOB")) +} + +/// Converts a c-kzg commitment into this module's [`KzgCommitment`], so this +/// module's public functions deal in one commitment type rather than leaking +/// c-kzg's. +fn commitment_from_c_kzg(raw: c_kzg::KzgCommitment) -> KzgCommitment { + KzgCommitment(raw.to_bytes().into_inner()) +} + +/// Converts a c-kzg proof into this module's [`KzgProof`]. +fn proof_from_c_kzg(raw: c_kzg::KzgProof) -> KzgProof { + KzgProof(raw.to_bytes().into_inner()) +} + +/// Converts a boxed array of c-kzg proofs into this module's proof type, +/// keeping the result on the heap throughout (`CELLS_PER_EXT_BLOB` proofs of +/// `KZG_POINT_SIZE` bytes each is small, but there is no reason to round-trip +/// it through the stack). +fn proofs_from_c_kzg( + raw: Box<[c_kzg::KzgProof; c_kzg::CELLS_PER_EXT_BLOB]>, +) -> Box { + let converted: Vec = raw.iter().map(|proof| proof_from_c_kzg(*proof)).collect(); + converted + .into_boxed_slice() + .try_into() + .expect("converted has exactly CELLS_PER_EXT_BLOB elements, one per input proof") +} + +/// Converts a c-kzg field element into this module's [`Bytes32`]. +fn bytes32_from_c_kzg(raw: c_kzg::Bytes32) -> Bytes32 { + H256(*raw.as_ref()) +} + +/// The specification's `blob_to_kzg_commitment` +/// (`specs/deneb/polynomial-commitments.md#blob_to_kzg_commitment`). +/// +/// Fails if `blob` is not exactly `BYTES_PER_BLOB` bytes, or if any of its +/// field elements is not canonically reduced modulo `BLS_MODULUS`. +pub fn blob_to_kzg_commitment(blob: &[u8]) -> Result { + let blob = to_blob(blob)?; + KZG_SETTINGS + .blob_to_kzg_commitment(&blob) + .map(commitment_from_c_kzg) + .map_err(|_| Error::SpecAssert("every field element in blob is < BLS_MODULUS")) +} + +/// The specification's `compute_kzg_proof` +/// (`specs/deneb/polynomial-commitments.md#compute_kzg_proof`). +/// +/// Returns the proof that the polynomial `blob` represents evaluates to `y` +/// at `z`, along with `y` itself. Fails if `blob` is the wrong length, if any +/// of its field elements is not canonical, or if `z` is not canonical. +pub fn compute_kzg_proof(blob: &[u8], z: &Bytes32) -> Result<(KzgProof, Bytes32)> { + let blob = to_blob(blob)?; + let z_bytes = c_kzg::Bytes32::new(z.0); + KZG_SETTINGS + .compute_kzg_proof(&blob, &z_bytes) + .map(|(proof, y)| (proof_from_c_kzg(proof), bytes32_from_c_kzg(y))) + .map_err(|_| Error::SpecAssert("blob and z are valid inputs to compute_kzg_proof")) +} + +/// The specification's `compute_blob_kzg_proof` +/// (`specs/deneb/polynomial-commitments.md#compute_blob_kzg_proof`). +/// +/// This is the proof gossiped alongside a blob and its commitment, evaluated +/// at the Fiat-Shamir challenge point `compute_challenge` derives from them, +/// rather than at a caller-chosen point. Fails if `blob` is invalid, or if +/// `commitment` is not `blob`'s commitment. +pub fn compute_blob_kzg_proof(blob: &[u8], commitment: &KzgCommitment) -> Result { + let blob = to_blob(blob)?; + let commitment_bytes = c_kzg::Bytes48::new(commitment.0); + KZG_SETTINGS + .compute_blob_kzg_proof(&blob, &commitment_bytes) + .map(proof_from_c_kzg) + .map_err(|_| Error::SpecAssert("commitment is a valid KZG commitment to blob")) +} + +/// The specification's `verify_kzg_proof` +/// (`specs/deneb/polynomial-commitments.md#verify_kzg_proof`). +/// +/// Checks that `proof` attests that the polynomial committed to by +/// `commitment` evaluates to `y` at `z`. Fails, rather than returning `false`, +/// if any of the byte strings do not decode to a valid point or a canonical +/// field element. +pub fn verify_kzg_proof( + commitment: &KzgCommitment, + z: &Bytes32, + y: &Bytes32, + proof: &KzgProof, +) -> Result { + let commitment_bytes = c_kzg::Bytes48::new(commitment.0); + let z_bytes = c_kzg::Bytes32::new(z.0); + let y_bytes = c_kzg::Bytes32::new(y.0); + let proof_bytes = c_kzg::Bytes48::new(proof.0); + KZG_SETTINGS + .verify_kzg_proof(&commitment_bytes, &z_bytes, &y_bytes, &proof_bytes) + .map_err(|_| Error::SpecAssert("commitment, z, y, and proof decode to valid points")) +} + +/// The specification's `verify_blob_kzg_proof` +/// (`specs/deneb/polynomial-commitments.md#verify_blob_kzg_proof`). +/// +/// Checks that `proof` attests that `commitment` commits to `blob`, evaluated +/// at the Fiat-Shamir challenge `compute_challenge` derives from them. Fails, +/// rather than returning `false`, on malformed input. +pub fn verify_blob_kzg_proof( + blob: &[u8], + commitment: &KzgCommitment, + proof: &KzgProof, +) -> Result { + let blob = to_blob(blob)?; + let commitment_bytes = c_kzg::Bytes48::new(commitment.0); + let proof_bytes = c_kzg::Bytes48::new(proof.0); + KZG_SETTINGS + .verify_blob_kzg_proof(&blob, &commitment_bytes, &proof_bytes) + .map_err(|_| Error::SpecAssert("proof attests that commitment commits to blob")) +} + +/// The specification's `verify_blob_kzg_proof_batch` +/// (`specs/deneb/polynomial-commitments.md#verify_blob_kzg_proof_batch`). +/// +/// Verifies many (blob, commitment, proof) triples with one random linear +/// combination rather than one pairing check per triple. `blobs`, +/// `commitments`, and `proofs` must have equal length; fails, rather than +/// returning `false`, if they do not, or if any element is malformed. +pub fn verify_blob_kzg_proof_batch( + blobs: &[&[u8]], + commitments: &[KzgCommitment], + proofs: &[KzgProof], +) -> Result { + let mut c_kzg_blobs = Vec::with_capacity(blobs.len()); + for blob in blobs { + c_kzg_blobs.push(to_blob(blob)?); + } + let commitment_bytes: Vec = commitments + .iter() + .map(|commitment| c_kzg::Bytes48::new(commitment.0)) + .collect(); + let proof_bytes: Vec = proofs + .iter() + .map(|proof| c_kzg::Bytes48::new(proof.0)) + .collect(); + KZG_SETTINGS + .verify_blob_kzg_proof_batch(&c_kzg_blobs, &commitment_bytes, &proof_bytes) + .map_err(|_| Error::SpecAssert("blobs, commitments, and proofs have equal, valid entries")) +} + +/// The specification's `compute_cells` +/// (`specs/fulu/polynomial-commitments-sampling.md#compute_cells`). +/// +/// Extends `blob`'s polynomial by a factor of two and splits the extension +/// into `CELLS_PER_EXT_BLOB` cells, without the accompanying proofs; see +/// [`compute_cells_and_kzg_proofs`] when the proofs are needed too. Fails if +/// `blob` is invalid. +pub fn compute_cells(blob: &[u8]) -> Result> { + let blob = to_blob(blob)?; + KZG_SETTINGS + .compute_cells(&blob) + .map_err(|_| Error::SpecAssert("blob is the evaluation of a valid polynomial")) +} + +/// The specification's `compute_cells_and_kzg_proofs` +/// (`specs/fulu/polynomial-commitments-sampling.md#compute_cells_and_kzg_proofs`). +/// +/// Same extension as [`compute_cells`], plus a KZG proof for each cell. +/// Fails if `blob` is invalid. +pub fn compute_cells_and_kzg_proofs( + blob: &[u8], +) -> Result<(Box, Box)> { + let blob = to_blob(blob)?; + let (cells, proofs) = KZG_SETTINGS + .compute_cells_and_kzg_proofs(&blob) + .map_err(|_| Error::SpecAssert("blob is the evaluation of a valid polynomial"))?; + Ok((cells, proofs_from_c_kzg(proofs))) +} + +/// The specification's `recover_cells_and_kzg_proofs` +/// (`specs/fulu/polynomial-commitments-sampling.md#recover_cells_and_kzg_proofs`). +/// +/// Reconstructs every cell and proof of an extended blob from a partial set, +/// via Reed-Solomon erasure decoding. `cell_indices` and `cells` must have +/// equal length, with no repeated index; fails if they do not, or if too few +/// cells are given to recover the rest. +pub fn recover_cells_and_kzg_proofs( + cell_indices: &[u64], + cells: &[c_kzg::Cell], +) -> Result<(Box, Box)> { + let (cells, proofs) = KZG_SETTINGS + .recover_cells_and_kzg_proofs(cell_indices, cells) + .map_err(|_| Error::SpecAssert("cell_indices and cells recover a valid extended blob"))?; + Ok((cells, proofs_from_c_kzg(proofs))) +} + +/// The specification's `verify_cell_kzg_proof_batch` +/// (`specs/fulu/polynomial-commitments-sampling.md#verify_cell_kzg_proof_batch`). +/// +/// Checks that each `cell` is the evaluation of the polynomial `commitment` +/// commits to, over the domain `cell_index` selects, using `proof`. +/// `commitments`, `cell_indices`, `cells`, and `proofs` must have equal +/// length; fails, rather than returning `false`, if they do not, or if any +/// entry is malformed. +pub fn verify_cell_kzg_proof_batch( + commitments: &[KzgCommitment], + cell_indices: &[u64], + cells: &[c_kzg::Cell], + proofs: &[KzgProof], +) -> Result { + let commitment_bytes: Vec = commitments + .iter() + .map(|commitment| c_kzg::Bytes48::new(commitment.0)) + .collect(); + let proof_bytes: Vec = proofs + .iter() + .map(|proof| c_kzg::Bytes48::new(proof.0)) + .collect(); + KZG_SETTINGS + .verify_cell_kzg_proof_batch(&commitment_bytes, cell_indices, cells, &proof_bytes) + .map_err(|_| { + Error::SpecAssert("commitments, cell_indices, cells, and proofs are consistent") + }) +} + +/// Domain separator for `compute_challenge`: the deneb spec's +/// `FIAT_SHAMIR_PROTOCOL_DOMAIN`, copied verbatim. +const FIAT_SHAMIR_PROTOCOL_DOMAIN: &[u8; 16] = b"FSBLOBVERIFY_V1_"; + +/// Domain separator for `compute_verify_cell_kzg_proof_batch_challenge`: the +/// fulu spec's `RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN`, copied verbatim. Not +/// to be confused with deneb's own `RANDOM_CHALLENGE_KZG_BATCH_DOMAIN`, a +/// different constant this module has no use for because +/// `verify_blob_kzg_proof_batch` above is delegated to c-kzg wholesale. +const RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN: &[u8; 16] = b"RCKZGCBATCH__V1_"; + +/// The specification's `hash_to_bls_field` +/// (`specs/deneb/polynomial-commitments.md#hash_to_bls_field`): hash `data` +/// and reduce the digest modulo `BLS_MODULUS`, interpreting both the digest +/// and the reduced value big-endian (`KZG_ENDIANNESS`). Shared by both +/// challenge functions below. +/// +/// Not exported: like `compute_challenge` and +/// `compute_verify_cell_kzg_proof_batch_challenge`, this is an internal +/// helper the spec document does not flag as a "Public method". +fn hash_to_bls_field(data: &[u8]) -> Bytes32 { + let digest = hash(data); + let value = BigUint::from_bytes_be(digest.as_slice()) % &*BLS_MODULUS; + let reduced = value.to_bytes_be(); + + // `reduced` is big-endian and shorter than 32 bytes whenever the value has + // leading zero bytes; right-align it so the missing bytes come out zero. + let mut bytes = [0u8; 32]; + bytes[32 - reduced.len()..].copy_from_slice(&reduced); + H256(bytes) +} + +/// The specification's `compute_challenge` +/// (`specs/deneb/polynomial-commitments.md#compute_challenge`): the +/// Fiat-Shamir challenge point at which `compute_blob_kzg_proof` and +/// `verify_blob_kzg_proof` evaluate `blob`'s polynomial. +/// +/// c-kzg computes this internally as a step of those two functions but does +/// not export it; it is reimplemented here directly from the spec text so +/// the standalone `compute_challenge` fixtures, which call it in isolation, +/// can be checked. +/// +/// Fails if `blob` is not exactly `BYTES_PER_BLOB` bytes. Unlike the +/// functions above, this never fails on the *content* of `blob` or +/// `commitment`: the transcript is their raw bytes, hashed, with no +/// curve-point or field-element validation performed along the way. +pub fn compute_challenge(blob: &[u8], commitment: &KzgCommitment) -> Result { + verify( + blob.len() == c_kzg::BYTES_PER_BLOB, + "len(blob) == BYTES_PER_BLOB", + )?; + + let mut data = Vec::with_capacity( + FIAT_SHAMIR_PROTOCOL_DOMAIN.len() + 16 + blob.len() + commitment.0.len(), + ); + data.extend_from_slice(FIAT_SHAMIR_PROTOCOL_DOMAIN); + // The degree of the polynomial, as a domain separator. The spec encodes + // it as a 16-byte big-endian integer here (`int.to_bytes(FIELD_ELEMENTS_PER_BLOB, 16, KZG_ENDIANNESS)`); + // `compute_verify_cell_kzg_proof_batch_challenge` below encodes every + // integer in its own transcript as 8 bytes instead, so the width is not + // interchangeable between the two functions. + data.extend_from_slice(&(c_kzg::FIELD_ELEMENTS_PER_BLOB as u128).to_be_bytes()); + data.extend_from_slice(blob); + data.extend_from_slice(commitment.as_ref()); + + Ok(hash_to_bls_field(&data)) +} + +/// The specification's `compute_verify_cell_kzg_proof_batch_challenge` +/// (`specs/fulu/polynomial-commitments-sampling.md#compute_verify_cell_kzg_proof_batch_challenge`): +/// the random challenge `r` the universal verification equation in +/// `verify_cell_kzg_proof_batch` uses to combine many cell proofs into one +/// check. +/// +/// c-kzg computes this internally as a step of its own +/// `verify_cell_kzg_proof_batch` but does not export it; it is reimplemented +/// here directly from the spec text so the standalone fixtures for it, which +/// call it in isolation, can be checked. +/// +/// `commitments` must already be deduplicated and `commitment_indices` must +/// map each coset back to its entry, exactly as `verify_cell_kzg_proof_batch` +/// constructs them internally; this function does not deduplicate on the +/// caller's behalf. `commitment_indices`, `cell_indices`, and `proofs` must +/// each have one entry per element of `cosets_evals`, and each coset's +/// evaluations must number `FIELD_ELEMENTS_PER_CELL`; this function returns +/// `Err` rather than indexing out of bounds if they do not. +pub fn compute_verify_cell_kzg_proof_batch_challenge( + commitments: &[KzgCommitment], + commitment_indices: &[u64], + cell_indices: &[u64], + cosets_evals: &[Vec], + proofs: &[KzgProof], +) -> Result { + verify( + commitment_indices.len() == cosets_evals.len(), + "commitment_indices has one entry per coset", + )?; + verify( + cell_indices.len() == cosets_evals.len(), + "cell_indices has one entry per coset", + )?; + verify( + proofs.len() == cosets_evals.len(), + "proofs has one entry per coset", + )?; + for coset_evals in cosets_evals { + verify( + coset_evals.len() == c_kzg::FIELD_ELEMENTS_PER_CELL, + "each coset has FIELD_ELEMENTS_PER_CELL evaluations", + )?; + } + + let mut data = Vec::new(); + data.extend_from_slice(RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN); + // Unlike `compute_challenge` above, every integer in this transcript is + // an 8-byte big-endian encoding (the spec's `int.to_bytes(_, 8, KZG_ENDIANNESS)`). + data.extend_from_slice(&(c_kzg::FIELD_ELEMENTS_PER_BLOB as u64).to_be_bytes()); + data.extend_from_slice(&(c_kzg::FIELD_ELEMENTS_PER_CELL as u64).to_be_bytes()); + data.extend_from_slice(&(commitments.len() as u64).to_be_bytes()); + data.extend_from_slice(&(cell_indices.len() as u64).to_be_bytes()); + for commitment in commitments { + data.extend_from_slice(commitment.as_ref()); + } + for (k, coset_evals) in cosets_evals.iter().enumerate() { + data.extend_from_slice(&commitment_indices[k].to_be_bytes()); + data.extend_from_slice(&cell_indices[k].to_be_bytes()); + for coset_eval in coset_evals { + data.extend_from_slice(coset_eval.as_slice()); + } + data.extend_from_slice(proofs[k].as_ref()); + } + + Ok(hash_to_bls_field(&data)) +} + +#[cfg(test)] +mod tests { + use std::fs; + use std::path::{Path, PathBuf}; + + use serde_yaml_ng::Value; + + use super::*; + + /// Root of the downloaded consensus spec test fixtures. + /// + /// The fixture harness other stages of this module share does not exist + /// yet (it lands in a later stage), so this test module loads its own + /// small subset of it: KZG fixtures are plain YAML with hex strings, no + /// SSZ and no snappy compression, so no shared machinery is needed. + fn fixtures_root() -> PathBuf { + let root = + Path::new(env!("CARGO_MANIFEST_DIR")).join("../../../consensus-spec-tests/tests"); + if !root.exists() { + panic!( + "consensus spec test fixtures not found at {}; run `make consensus-spec-tests`", + root.display() + ); + } + root + } + + /// Loads every `data.yaml` under `general//kzg//kzg-mainnet/*/`. + fn cases(fork: &str, handler: &str) -> Vec { + let dir = fixtures_root() + .join("general") + .join(fork) + .join("kzg") + .join(handler) + .join("kzg-mainnet"); + let entries = fs::read_dir(&dir) + .unwrap_or_else(|err| panic!("reading fixture directory {}: {err}", dir.display())); + entries + .map(|entry| { + let case_dir = entry.expect("readable directory entry").path(); + let data = fs::read(case_dir.join("data.yaml")) + .unwrap_or_else(|err| panic!("reading {}: {err}", case_dir.display())); + serde_yaml_ng::from_slice(&data) + .unwrap_or_else(|err| panic!("parsing {}: {err}", case_dir.display())) + }) + .collect() + } + + /// Decodes a `0x`-prefixed hex string into heap-allocated bytes. Blobs + /// are `BYTES_PER_BLOB` (128 KiB) each, so this, not a stack array, is how + /// every hex field in this test module is decoded. + fn hex_bytes(value: &Value) -> Vec { + let hex_str = value.as_str().expect("value is a hex string"); + hex::decode( + hex_str + .strip_prefix("0x") + .expect("hex string has a 0x prefix"), + ) + .expect("value is valid hex") + } + + /// Decodes a 32-byte hex string, or `None` if it is not exactly 32 bytes. + /// A length mismatch is treated the same way the upstream c-kzg test + /// harness treats one: as a case whose expected output must be `null`, + /// since this module's typed KZG functions cannot even be called with a + /// malformed-length field element. + fn hex_bytes32(value: &Value) -> Option { + let bytes = hex_bytes(value); + let bytes: [u8; 32] = bytes.try_into().ok()?; + Some(H256(bytes)) + } + + /// Decodes a 48-byte hex string into a [`KzgCommitment`], or `None` if it + /// is not exactly 48 bytes. + fn hex_commitment(value: &Value) -> Option { + let bytes = hex_bytes(value); + let bytes: [u8; 48] = bytes.try_into().ok()?; + Some(KzgCommitment(bytes)) + } + + /// Decodes a 48-byte hex string into a [`KzgProof`], or `None` if it is + /// not exactly 48 bytes. + fn hex_proof(value: &Value) -> Option { + let bytes = hex_bytes(value); + let bytes: [u8; 48] = bytes.try_into().ok()?; + Some(KzgProof(bytes)) + } + + /// Decodes a `BYTES_PER_CELL`-byte hex string into a [`c_kzg::Cell`], or + /// `None` if the length is wrong. + fn hex_cell(value: &Value) -> Option { + c_kzg::Cell::from_bytes(&hex_bytes(value)).ok() + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn blob_to_kzg_commitment_matches_fixtures() { + let cases = cases("deneb", "blob_to_kzg_commitment"); + assert!( + !cases.is_empty(), + "no blob_to_kzg_commitment fixtures found" + ); + for case in &cases { + let blob = hex_bytes(&case["input"]["blob"]); + let expected = &case["output"]; + match blob_to_kzg_commitment(&blob) { + Ok(commitment) => { + assert_eq!(Some(commitment), hex_commitment(expected)); + } + Err(_) => assert!(expected.is_null()), + } + } + println!("blob_to_kzg_commitment: {} cases", cases.len()); + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn compute_kzg_proof_matches_fixtures() { + let cases = cases("deneb", "compute_kzg_proof"); + assert!(!cases.is_empty(), "no compute_kzg_proof fixtures found"); + for case in &cases { + let blob = hex_bytes(&case["input"]["blob"]); + let expected = &case["output"]; + let Some(z) = hex_bytes32(&case["input"]["z"]) else { + assert!(expected.is_null()); + continue; + }; + match compute_kzg_proof(&blob, &z) { + Ok((proof, y)) => { + let expected = expected.as_sequence().expect("output is [proof, y]"); + assert_eq!(Some(proof), hex_proof(&expected[0])); + assert_eq!(Some(y), hex_bytes32(&expected[1])); + } + Err(_) => assert!(expected.is_null()), + } + } + println!("compute_kzg_proof: {} cases", cases.len()); + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn compute_blob_kzg_proof_matches_fixtures() { + let cases = cases("deneb", "compute_blob_kzg_proof"); + assert!( + !cases.is_empty(), + "no compute_blob_kzg_proof fixtures found" + ); + for case in &cases { + let blob = hex_bytes(&case["input"]["blob"]); + let expected = &case["output"]; + let Some(commitment) = hex_commitment(&case["input"]["commitment"]) else { + assert!(expected.is_null()); + continue; + }; + match compute_blob_kzg_proof(&blob, &commitment) { + Ok(proof) => assert_eq!(Some(proof), hex_proof(expected)), + Err(_) => assert!(expected.is_null()), + } + } + println!("compute_blob_kzg_proof: {} cases", cases.len()); + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn verify_kzg_proof_matches_fixtures() { + let cases = cases("deneb", "verify_kzg_proof"); + assert!(!cases.is_empty(), "no verify_kzg_proof fixtures found"); + for case in &cases { + let expected = &case["output"]; + let input = &case["input"]; + let (Some(commitment), Some(z), Some(y), Some(proof)) = ( + hex_commitment(&input["commitment"]), + hex_bytes32(&input["z"]), + hex_bytes32(&input["y"]), + hex_proof(&input["proof"]), + ) else { + assert!(expected.is_null()); + continue; + }; + match verify_kzg_proof(&commitment, &z, &y, &proof) { + Ok(verified) => assert_eq!(Some(verified), expected.as_bool()), + Err(_) => assert!(expected.is_null()), + } + } + println!("verify_kzg_proof: {} cases", cases.len()); + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn verify_blob_kzg_proof_matches_fixtures() { + let cases = cases("deneb", "verify_blob_kzg_proof"); + assert!(!cases.is_empty(), "no verify_blob_kzg_proof fixtures found"); + for case in &cases { + let expected = &case["output"]; + let input = &case["input"]; + let blob = hex_bytes(&input["blob"]); + let (Some(commitment), Some(proof)) = ( + hex_commitment(&input["commitment"]), + hex_proof(&input["proof"]), + ) else { + assert!(expected.is_null()); + continue; + }; + match verify_blob_kzg_proof(&blob, &commitment, &proof) { + Ok(verified) => assert_eq!(Some(verified), expected.as_bool()), + Err(_) => assert!(expected.is_null()), + } + } + println!("verify_blob_kzg_proof: {} cases", cases.len()); + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn verify_blob_kzg_proof_batch_matches_fixtures() { + let cases = cases("deneb", "verify_blob_kzg_proof_batch"); + assert!( + !cases.is_empty(), + "no verify_blob_kzg_proof_batch fixtures found" + ); + for case in &cases { + let expected = &case["output"]; + let input = &case["input"]; + let blobs: Vec> = input["blobs"] + .as_sequence() + .expect("blobs is a list") + .iter() + .map(hex_bytes) + .collect(); + let blob_refs: Vec<&[u8]> = blobs.iter().map(Vec::as_slice).collect(); + + let commitments: Option> = input["commitments"] + .as_sequence() + .expect("commitments is a list") + .iter() + .map(hex_commitment) + .collect(); + let proofs: Option> = input["proofs"] + .as_sequence() + .expect("proofs is a list") + .iter() + .map(hex_proof) + .collect(); + let (Some(commitments), Some(proofs)) = (commitments, proofs) else { + assert!(expected.is_null()); + continue; + }; + + match verify_blob_kzg_proof_batch(&blob_refs, &commitments, &proofs) { + Ok(verified) => assert_eq!(Some(verified), expected.as_bool()), + Err(_) => assert!(expected.is_null()), + } + } + println!("verify_blob_kzg_proof_batch: {} cases", cases.len()); + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn compute_cells_matches_fixtures() { + let cases = cases("fulu", "compute_cells"); + assert!(!cases.is_empty(), "no compute_cells fixtures found"); + for case in &cases { + let blob = hex_bytes(&case["input"]["blob"]); + let expected = &case["output"]; + match compute_cells(&blob) { + Ok(cells) => { + let expected = expected.as_sequence().expect("output is a list of cells"); + assert_eq!(cells.len(), expected.len()); + for (cell, expected_cell) in cells.iter().zip(expected) { + assert_eq!(Some(*cell), hex_cell(expected_cell)); + } + } + Err(_) => assert!(expected.is_null()), + } + } + println!("compute_cells: {} cases", cases.len()); + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn compute_cells_and_kzg_proofs_matches_fixtures() { + let cases = cases("fulu", "compute_cells_and_kzg_proofs"); + assert!( + !cases.is_empty(), + "no compute_cells_and_kzg_proofs fixtures found" + ); + for case in &cases { + let blob = hex_bytes(&case["input"]["blob"]); + let expected = &case["output"]; + match compute_cells_and_kzg_proofs(&blob) { + Ok((cells, proofs)) => { + let expected = expected.as_sequence().expect("output is [cells, proofs]"); + let expected_cells = expected[0].as_sequence().expect("cells is a list"); + let expected_proofs = expected[1].as_sequence().expect("proofs is a list"); + for (cell, expected_cell) in cells.iter().zip(expected_cells) { + assert_eq!(Some(*cell), hex_cell(expected_cell)); + } + for (proof, expected_proof) in proofs.iter().zip(expected_proofs) { + assert_eq!(Some(*proof), hex_proof(expected_proof)); + } + } + Err(_) => assert!(expected.is_null()), + } + } + println!("compute_cells_and_kzg_proofs: {} cases", cases.len()); + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn recover_cells_and_kzg_proofs_matches_fixtures() { + let cases = cases("fulu", "recover_cells_and_kzg_proofs"); + assert!( + !cases.is_empty(), + "no recover_cells_and_kzg_proofs fixtures found" + ); + for case in &cases { + let expected = &case["output"]; + let input = &case["input"]; + let cell_indices: Vec = input["cell_indices"] + .as_sequence() + .expect("cell_indices is a list") + .iter() + .map(|v| v.as_u64().expect("cell index is an integer")) + .collect(); + let cells: Option> = input["cells"] + .as_sequence() + .expect("cells is a list") + .iter() + .map(hex_cell) + .collect(); + let Some(cells) = cells else { + assert!(expected.is_null()); + continue; + }; + + match recover_cells_and_kzg_proofs(&cell_indices, &cells) { + Ok((recovered_cells, recovered_proofs)) => { + let expected = expected.as_sequence().expect("output is [cells, proofs]"); + let expected_cells = expected[0].as_sequence().expect("cells is a list"); + let expected_proofs = expected[1].as_sequence().expect("proofs is a list"); + for (cell, expected_cell) in recovered_cells.iter().zip(expected_cells) { + assert_eq!(Some(*cell), hex_cell(expected_cell)); + } + for (proof, expected_proof) in recovered_proofs.iter().zip(expected_proofs) { + assert_eq!(Some(*proof), hex_proof(expected_proof)); + } + } + Err(_) => assert!(expected.is_null()), + } + } + println!("recover_cells_and_kzg_proofs: {} cases", cases.len()); + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn verify_cell_kzg_proof_batch_matches_fixtures() { + let cases = cases("fulu", "verify_cell_kzg_proof_batch"); + assert!( + !cases.is_empty(), + "no verify_cell_kzg_proof_batch fixtures found" + ); + for case in &cases { + let expected = &case["output"]; + let input = &case["input"]; + let cell_indices: Vec = input["cell_indices"] + .as_sequence() + .expect("cell_indices is a list") + .iter() + .map(|v| v.as_u64().expect("cell index is an integer")) + .collect(); + + let commitments: Option> = input["commitments"] + .as_sequence() + .expect("commitments is a list") + .iter() + .map(hex_commitment) + .collect(); + let cells: Option> = input["cells"] + .as_sequence() + .expect("cells is a list") + .iter() + .map(hex_cell) + .collect(); + let proofs: Option> = input["proofs"] + .as_sequence() + .expect("proofs is a list") + .iter() + .map(hex_proof) + .collect(); + let (Some(commitments), Some(cells), Some(proofs)) = (commitments, cells, proofs) + else { + assert!(expected.is_null()); + continue; + }; + + match verify_cell_kzg_proof_batch(&commitments, &cell_indices, &cells, &proofs) { + Ok(verified) => assert_eq!(Some(verified), expected.as_bool()), + Err(_) => assert!(expected.is_null()), + } + } + println!("verify_cell_kzg_proof_batch: {} cases", cases.len()); + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn compute_challenge_matches_fixtures() { + let cases = cases("deneb", "compute_challenge"); + assert!(!cases.is_empty(), "no compute_challenge fixtures found"); + for case in &cases { + let blob = hex_bytes(&case["input"]["blob"]); + let expected = &case["output"]; + let Some(commitment) = hex_commitment(&case["input"]["commitment"]) else { + assert!(expected.is_null()); + continue; + }; + match compute_challenge(&blob, &commitment) { + Ok(challenge) => assert_eq!(Some(challenge), hex_bytes32(expected)), + Err(_) => assert!(expected.is_null()), + } + } + println!("compute_challenge: {} cases", cases.len()); + } + + #[test] + #[cfg_attr( + not(feature = "beacon-spec-tests"), + ignore = "needs the consensus-spec fixture tree; run `make consensus-spec-tests`" + )] + fn compute_verify_cell_kzg_proof_batch_challenge_matches_fixtures() { + let cases = cases("fulu", "compute_verify_cell_kzg_proof_batch_challenge"); + assert!( + !cases.is_empty(), + "no compute_verify_cell_kzg_proof_batch_challenge fixtures found" + ); + for case in &cases { + let expected = &case["output"]; + let input = &case["input"]; + + let commitments: Option> = input["commitments"] + .as_sequence() + .expect("commitments is a list") + .iter() + .map(hex_commitment) + .collect(); + let commitment_indices: Vec = input["commitment_indices"] + .as_sequence() + .expect("commitment_indices is a list") + .iter() + .map(|v| v.as_u64().expect("commitment index is an integer")) + .collect(); + let cell_indices: Vec = input["cell_indices"] + .as_sequence() + .expect("cell_indices is a list") + .iter() + .map(|v| v.as_u64().expect("cell index is an integer")) + .collect(); + let cosets_evals: Option>> = input["cosets_evals"] + .as_sequence() + .expect("cosets_evals is a list") + .iter() + .map(|coset| { + coset + .as_sequence() + .expect("coset is a list of field elements") + .iter() + .map(hex_bytes32) + .collect::>>() + }) + .collect(); + let proofs: Option> = input["proofs"] + .as_sequence() + .expect("proofs is a list") + .iter() + .map(hex_proof) + .collect(); + let (Some(commitments), Some(cosets_evals), Some(proofs)) = + (commitments, cosets_evals, proofs) + else { + assert!(expected.is_null()); + continue; + }; + + match compute_verify_cell_kzg_proof_batch_challenge( + &commitments, + &commitment_indices, + &cell_indices, + &cosets_evals, + &proofs, + ) { + Ok(challenge) => assert_eq!(Some(challenge), hex_bytes32(expected)), + Err(_) => assert!(expected.is_null()), + } + } + println!( + "compute_verify_cell_kzg_proof_batch_challenge: {} cases", + cases.len() + ); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/lean_boundary.rs b/crates/blockchain/state_transition/src/beacon/lean_boundary.rs new file mode 100644 index 000000000..92bb06dd6 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/lean_boundary.rs @@ -0,0 +1,49 @@ +//! The one place this module names the lean half of `ethlambda-types`. +//! +//! [`crate::beacon::containers::BeaconState`] carries a `Lean` variant and +//! [`crate::beacon::ForkName`] a `Lean` name, because `ethlambda-types` holds one +//! state type for both chains. Nothing in this module can transition either: a +//! fixture case, a gossiped beacon block and a genesis deposit set all produce +//! beacon states, so a lean value here means the caller dispatched on the wrong +//! chain. That is a bug above this module rather than an input it can reject, so +//! these arms panic instead of widening every signature to a `Result` no correct +//! caller could ever see. +//! +//! Both carry the same wording as `ethlambda_types::beacon`'s own +//! `lean_state_unreachable` and `lean_fork_unreachable`, which are `pub(crate)` +//! there and so cannot simply be imported. Two functions rather than one taking a +//! discriminant, for the reason that crate split its own: they are two unrelated +//! diagnoses, and rejoining them would only make each caller say which it meant. + +/// Panics, naming the beacon accessor a lean state reached. +/// +/// This is the state-shaped boundary: reaching it means a caller dispatched on +/// the wrong thing. For the fork-shaped one see [`lean_fork_unreachable`], kept +/// separate because the two are crossed by different mistakes. +/// +/// `#[track_caller]` so the panic still reports the arm's own file and line, the +/// way an `unreachable!` written inline there would have. +#[cold] +#[track_caller] +pub(crate) fn lean_state_unreachable(function: &str) -> ! { + unreachable!( + "lean state reached a beacon accessor ({function}); \ + BlockChainServer must dispatch on fork_name() before this point" + ) +} + +/// Panics, naming the Beacon Chain-only function [`crate::beacon::ForkName::Lean`] +/// reached. +/// +/// The fork-shaped counterpart to [`lean_state_unreachable`]: lean is not a point +/// on the beacon fork schedule at all, so no state is involved and the fault is +/// the argument the caller passed rather than the state it dispatched on. +#[cold] +#[track_caller] +pub(crate) fn lean_fork_unreachable(function: &str) -> ! { + unreachable!( + "ForkName::Lean reached a Beacon Chain function ({function}); \ + lean is not a point on the beacon fork schedule, so the caller \ + passed a fork it should have dispatched on first" + ) +} diff --git a/crates/blockchain/state_transition/src/beacon/mod.rs b/crates/blockchain/state_transition/src/beacon/mod.rs new file mode 100644 index 000000000..7c24bb9ec --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/mod.rs @@ -0,0 +1,91 @@ +//! The Ethereum Beacon Chain consensus specification, phase0 through fulu. +//! +//! This implements [`ethereum/consensus-specs`][specs]: the beacon state +//! transition function, the fork choice store, and the helpers and cryptography +//! they need. It is verified against the spec test fixtures released with the +//! specification, pinned at the version in the `Makefile`. +//! +//! The Beacon Chain is a different protocol from the Lean consensus the rest of +//! this crate implements, and this module implements only the former. The two sit +//! in one crate so that a caller dispatching on a state's fork can reach either +//! chain's rules without them living in separate dependency trees; they share no +//! code, nothing above this module reads anything inside it, and nothing here +//! reads lean's own modules. +//! +//! One thing they genuinely do share is [`ethlambda_types`], which carries the +//! beacon containers, presets, configuration and primitives under its own +//! `beacon` namespace. Those stayed out of this crate because the storage and +//! networking crates need them and must not depend on `blst` and `c-kzg`, which +//! this module does pull in. Everything they define is re-exported here at its +//! old path, so a use site inside this module names [`crate::beacon::containers`], [`crate::beacon::preset`] or +//! [`crate::beacon::config`] as if they were still local modules. +//! +//! Those two C libraries are consequently on the lean binary's dependency path, +//! since `ethlambda-blockchain` and `ethlambda-rpc` depend on this crate. This +//! module is not feature-gated, so that cost is unconditional; only the tests +//! that read the multi-gigabyte fixture tree are gated, behind +//! `beacon-spec-tests`. +//! +//! One consequence reaches every match in this module. `ethlambda-types` gives +//! [`crate::beacon::containers::BeaconState`] and [`crate::beacon::ForkName`] a `Lean` variant, so that one +//! state type can carry either chain. No lean value can reach this module through +//! a beacon fixture or a beacon block, so those arms panic through +//! `lean_boundary`'s two functions rather than returning a `Result`: reaching one +//! means a caller dispatched on the wrong chain, which is a bug in the caller and +//! not a state this code can transition. +//! +//! # How forks are represented +//! +//! Containers that change between forks are defined once per fork (in +//! `ethlambda-types`, re-exported here), as plain structs that derive their SSZ +//! encoding and merkleization, and wrapped in an enum +//! ([`crate::beacon::containers::BeaconState`] and friends). Deriving the SSZ traits is the +//! reason for that shape: the per-fork field lists are not a growing tail. +//! Two of phase0's fields are *replaced* in altair, one field changes type in +//! five separate forks, and the state's merkle tree gains a level at electra, so +//! a single container with fork-conditional serialization would have to +//! reproduce all of that by hand. Derived codecs get it from the struct +//! definition instead. +//! +//! State transition functions take the enum, read through the accessors +//! generated in `containers`, and match on the fork only where the +//! specification itself changes behavior, so a match arm can be reviewed +//! against the spec's own diff. Functions that exist only from some fork onward +//! return [`crate::beacon::Error::UnsupportedForFork`] for earlier ones. +//! +//! No `macro_rules!` is defined here at all. The ones covering bulk boilerplate, +//! chiefly the fork-invariant state accessors in `containers`, went to +//! `ethlambda-types` with the definitions they generate, and there are no +//! procedural macros beyond the SSZ derives. +//! +//! # Presets +//! +//! Container bounds are compile-time constants, so the preset is a compile-time +//! choice: mainnet by default, minimal with the `preset-minimal` feature. See +//! [`crate::beacon::preset`]. Values that only affect fork *scheduling* are runtime +//! configuration instead, in [`crate::beacon::config`], because the `transition` fixture suite +//! sets fork epochs per case. +//! +//! [specs]: https://github.com/ethereum/consensus-specs + +pub mod bls; +pub mod fork_choice; +pub mod genesis; +pub mod hash; +pub mod helpers; +pub mod kzg; +pub mod stf; +pub mod upgrade; + +mod lean_boundary; + +// The types this module transitions, at the paths they had while they lived here. +// A plain re-export rather than `pub mod x { pub use ... }` wrappers: this way +// `crate::beacon::containers::phase0::BeaconState` and +// `ethlambda_types::beacon::containers::phase0::BeaconState` are one type by one +// name, so a caller holding either spelling can hand it straight to this module. +pub use ethlambda_types::beacon::{config, constants, containers, error, fork, preset, primitives}; + +pub use error::{Error, Result, verify}; +pub use fork::ForkName; +pub(crate) use lean_boundary::{lean_fork_unreachable, lean_state_unreachable}; diff --git a/crates/blockchain/state_transition/src/beacon/stf/altair.rs b/crates/blockchain/state_transition/src/beacon/stf/altair.rs new file mode 100644 index 000000000..8bc599481 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/altair.rs @@ -0,0 +1,742 @@ +//! Altair's two block-processing changes. +//! +//! Phase0 cannot score an attestation the moment it arrives: whether an +//! attester's vote turns out to matter depends on facts that are not settled +//! until the epoch boundary (whether the target became the epoch's canonical +//! block, whether the chain finalized at all), so phase0 defers scoring by +//! appending a whole `PendingAttestation` to the state and replaying the +//! backlog in [`crate::beacon::stf::epoch`]. Altair restructures the state instead of +//! the schedule: [`crate::beacon::helpers::altair::get_attestation_participation_flag_indices`] +//! already knows, the moment an attestation is processed, exactly which of the +//! three timeliness conditions it satisfies, so this module's +//! [`process_attestation`] scores it right there, flips the matching +//! participation bits, and pays the including proposer immediately rather than +//! waiting for an epoch boundary to replay anything. That is both cheaper (one +//! bit per validator per epoch instead of a growing list of whole +//! attestations) and bounded (the participation record can never grow past the +//! size of the validator registry, unlike phase0's attestation lists). +//! +//! [`process_sync_aggregate`] is new in altair, with no phase0 analogue: it +//! pays the rotating sync committee (see [`crate::beacon::helpers::altair`] for how +//! that committee is drawn) for having signed the previous slot's block root. +//! The reward split between the committee and the proposer, and between reward +//! and penalty, is fixed entirely by [`crate::beacon::constants`]'s weight constants +//! rather than anything computed here, so a non-participating member is +//! charged precisely the `participant_reward` a participating one earns: the +//! two are the same number applied with opposite sign, not two independently +//! derived quantities that happen to match. + +use crate::beacon::bls; +use crate::beacon::constants; +use crate::beacon::containers::{BeaconState, altair, phase0}; +use crate::beacon::error::{Error, Result, verify}; +use crate::beacon::helpers::accessors::{ + get_beacon_committee, get_beacon_proposer_index, get_block_root_at_slot, + get_committee_count_per_slot, get_current_epoch, get_domain, get_previous_epoch, + get_total_active_balance, +}; +use crate::beacon::helpers::altair::{ + add_flag, get_attestation_participation_flag_indices, get_base_reward, + get_base_reward_per_increment, has_flag, +}; +use crate::beacon::helpers::attestation::{ + get_attesting_indices, get_indexed_attestation, is_valid_indexed_attestation, +}; +use crate::beacon::helpers::misc::{compute_epoch_at_slot, compute_signing_root}; +use crate::beacon::helpers::mutators::{decrease_balance, increase_balance}; +use crate::beacon::preset; +use crate::beacon::primitives::{Gwei, ParticipationFlags, ValidatorIndex}; + +// --------------------------------------------------------------------------- +// Attestations +// --------------------------------------------------------------------------- + +/// Scores an attestation against the three timeliness conditions and pays the +/// including proposer for whichever of them it newly satisfies. +/// +/// Shares its entire validation prologue with phase0's +/// [`crate::beacon::stf::operations::process_attestation`] (target epoch, inclusion +/// window, committee shape, then the signature): none of that changed in +/// altair. What changed is what happens to a *valid* attestation. Phase0 +/// appends it, whole, to one of two epoch-scoped lists and leaves every reward +/// decision for the epoch boundary. Altair instead asks +/// [`get_attestation_participation_flag_indices`] which of the three +/// timeliness flags this attestation satisfies, sets exactly the ones each +/// attester does not already have (a repeat vote earns nothing twice), and +/// converts each newly-set flag directly into a share of the proposer's +/// reward, paid before this function returns rather than at the next epoch +/// boundary. +/// +/// Reading which flags are already set and computing the reward for newly-set +/// ones (`get_base_reward`) only ever needs `&state`, while flipping the bits +/// needs `&mut state`; those two cannot be interleaved in one pass the way the +/// specification's single loop does, since holding the mutable participation +/// borrow across a call that needs to read the rest of `state` does not +/// borrow-check (see `process_effective_balance_updates` in +/// `crate::beacon::stf::epoch` for the same trade-off spelled out in more depth). This +/// runs as two passes instead: a read phase that decides which flags each +/// attester newly earns and totals the proposer's reward for them, then a +/// write phase that only ever applies what the first phase already decided. +/// +/// Takes no [`crate::beacon::config::Config`]: every quantity this needs is either a +/// [`crate::beacon::constants`] weight or a [`preset`] value, and the specification +/// lists none of them under a network's "Configuration" table. +pub fn process_attestation( + state: &mut BeaconState, + attestation: &phase0::Attestation, +) -> Result<()> { + let data = attestation.data; + let current_epoch = get_current_epoch(state); + let previous_epoch = get_previous_epoch(state); + + verify( + data.target.epoch == previous_epoch || data.target.epoch == current_epoch, + "data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))", + )?; + verify( + data.target.epoch == compute_epoch_at_slot(data.slot), + "data.target.epoch == compute_epoch_at_slot(data.slot)", + )?; + + // Both bounds are driven directly by `data.slot`, which comes straight off + // the wire, so a hostile value close to `u64::MAX` must not be allowed to + // wrap either bound into something that vacuously accepts the attestation. + let min_slot = data + .slot + .checked_add(preset::MIN_ATTESTATION_INCLUSION_DELAY) + .ok_or(Error::ArithmeticOverflow( + "data.slot + MIN_ATTESTATION_INCLUSION_DELAY", + ))?; + let max_slot = data + .slot + .checked_add(preset::SLOTS_PER_EPOCH) + .ok_or(Error::ArithmeticOverflow("data.slot + SLOTS_PER_EPOCH"))?; + verify( + min_slot <= state.slot() && state.slot() <= max_slot, + "data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH", + )?; + verify( + data.index < get_committee_count_per_slot(state, data.target.epoch), + "data.index < get_committee_count_per_slot(state, data.target.epoch)", + )?; + + let committee = get_beacon_committee(state, data.slot, data.index)?; + verify( + attestation.aggregation_bits.len() == committee.len(), + "len(attestation.aggregation_bits) == len(committee)", + )?; + + // Safe: `min_slot <= state.slot()` above and `min_slot >= data.slot` (the + // inclusion delay is non-negative), so `data.slot <= state.slot()`. + let inclusion_delay = state.slot() - data.slot; + let participation_flag_indices = + get_attestation_participation_flag_indices(state, &data, inclusion_delay)?; + + let indexed_attestation = get_indexed_attestation(state, attestation)?; + verify( + is_valid_indexed_attestation(state, &indexed_attestation), + "is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))", + )?; + + // Read phase: for every attester, decide which flags this attestation + // newly satisfies and add up the proposer's reward for granting them. + // Everything here only ever reads `state`, so it can run to completion + // before the write phase below needs a mutable borrow of the same + // participation list. + let attesting_indices = get_attesting_indices(state, attestation)?; + let current_epoch_target = data.target.epoch == current_epoch; + let (previous_epoch_participation, current_epoch_participation, _) = + state.altair_validator_lists()?; + let epoch_participation = if current_epoch_target { + current_epoch_participation + } else { + previous_epoch_participation + }; + + let mut proposer_reward_numerator: Gwei = 0; + let mut updates: Vec<(ValidatorIndex, ParticipationFlags)> = Vec::new(); + for index in attesting_indices { + let current_flags = + epoch_participation + .get(index as usize) + .copied() + .ok_or(Error::IndexOutOfBounds { + index: index as usize, + len: epoch_participation.len(), + })?; + + let mut new_flags: ParticipationFlags = 0; + for &flag_index in &participation_flag_indices { + if has_flag(current_flags, flag_index) { + continue; + } + new_flags = add_flag(new_flags, flag_index); + let weight = constants::PARTICIPATION_FLAG_WEIGHTS[flag_index]; + let reward = get_base_reward(state, index)?.checked_mul(weight).ok_or( + Error::ArithmeticOverflow("get_base_reward(state, index) * weight"), + )?; + proposer_reward_numerator = proposer_reward_numerator + .checked_add(reward) + .ok_or(Error::ArithmeticOverflow("proposer_reward_numerator"))?; + } + if new_flags != 0 { + updates.push((index, new_flags)); + } + } + + // Write phase: apply exactly the flags the read phase decided on. Nothing + // from here on reads `state` any further, so this is free to take the + // mutable borrow the read phase could not. + let (previous_epoch_participation, current_epoch_participation, _) = + state.altair_validator_lists_mut()?; + let epoch_participation = if current_epoch_target { + current_epoch_participation + } else { + previous_epoch_participation + }; + let epoch_participation_len = epoch_participation.len(); + for (index, new_flags) in updates { + let flags = epoch_participation + .get_mut(index as usize) + .ok_or(Error::IndexOutOfBounds { + index: index as usize, + len: epoch_participation_len, + })?; + *flags |= new_flags; + } + + // The weights partition `WEIGHT_DENOMINATOR` between the three flags, the + // sync committee, and the proposer (see `crate::beacon::constants`'s module + // documentation), so taking the proposer's share out of the denominator + // and multiplying back up by the full denominator is what turns "the + // proposer's flat share of a reward" into the multiplier that inflates a + // validator's own reward for a flag into what the proposer earns for + // having included the vote that granted it. + const NON_PROPOSER_WEIGHT: u64 = constants::WEIGHT_DENOMINATOR - constants::PROPOSER_WEIGHT; + const PROPOSER_REWARD_DENOMINATOR: u64 = + NON_PROPOSER_WEIGHT * constants::WEIGHT_DENOMINATOR / constants::PROPOSER_WEIGHT; + let proposer_reward = proposer_reward_numerator / PROPOSER_REWARD_DENOMINATOR; + let proposer_index = get_beacon_proposer_index(state)?; + increase_balance(state, proposer_index, proposer_reward)?; + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Sync aggregate +// --------------------------------------------------------------------------- + +/// Verifies the sync committee's aggregate signature over the previous slot's +/// block root, then pays each participating committee member (and the +/// proposer, once per participant) and penalizes each one that did not. +/// +/// The specification chooses which pubkeys to aggregate by a three-way branch: +/// reuse the committee's precomputed `aggregate_pubkey` when everyone signed, +/// subtract the non-participants from it via elliptic-curve point negation +/// when more than half did, or aggregate the participants directly otherwise. +/// All three branches assert the identical claim, that the signature verifies +/// against the aggregate of exactly the participating members, so the branch +/// is a `blst`-level performance optimization rather than a difference in what +/// is checked. [`crate::beacon::bls`] has no point-subtraction primitive (nothing else +/// in this module needs one) and its own aggregation already batches every +/// point in a single pass, so this collapses the three cases into one direct +/// aggregation of the participating members' pubkeys. +/// [`bls::eth_fast_aggregate_verify`]'s own convention for an empty list +/// (accept only when the signature is the point at infinity) covers the case +/// nobody participated exactly the way the specification's own "less than +/// half" branch does when zero bits are set. +/// +/// Every reward and penalty here is the same `participant_reward`, applied +/// with opposite sign: [`crate::beacon::constants::SYNC_REWARD_WEIGHT`] and +/// [`crate::beacon::constants::PROPOSER_WEIGHT`] fix the whole split ahead of time, so +/// there is no independently-derived penalty formula that could drift out of +/// sync with the reward one. +/// +/// Resolving each committee seat's validator index needs a linear scan of +/// `state.validators` (sync committee membership is recorded as pubkeys, not +/// indices), and the specification does that scan inside the very loop that +/// also calls `get_beacon_proposer_index` and adjusts balances. Doing the scan +/// there would need `state` borrowed immutably (to search) and mutably (to +/// pay or penalize) at the same time, which does not borrow-check; this +/// resolves every seat's index, and the proposer's index, into owned values +/// first, then runs the payment loop against those, the same shape +/// `process_effective_balance_updates` (`crate::beacon::stf::epoch`) uses for the +/// identical reason. +/// +/// Takes no [`crate::beacon::config::Config`]: [`constants::DOMAIN_SYNC_COMMITTEE`] +/// and the weight constants are fixed, and [`preset::SYNC_COMMITTEE_SIZE`], +/// [`preset::EFFECTIVE_BALANCE_INCREMENT`], and [`preset::SLOTS_PER_EPOCH`] +/// are preset values; the specification lists none of them under a network's +/// "Configuration" table. +pub fn process_sync_aggregate( + state: &mut BeaconState, + sync_aggregate: &altair::SyncAggregate, +) -> Result<()> { + let committee_bits = &sync_aggregate.sync_committee_bits; + + let (current_sync_committee, _) = state.sync_committees()?; + let committee_pubkeys = ¤t_sync_committee.pubkeys; + + let mut participant_pubkeys = Vec::new(); + for (position, pubkey) in committee_pubkeys.iter().enumerate() { + if committee_bits.get(position).unwrap_or(false) { + participant_pubkeys.push(*pubkey); + } + } + + // `max(state.slot, 1) - 1`, rewritten as a saturating subtraction: the two + // are equal for every `Slot`, including genesis, and this way there is no + // intermediate `max` to explain. + let previous_slot = state.slot().saturating_sub(1); + let domain = get_domain( + state, + constants::DOMAIN_SYNC_COMMITTEE, + Some(compute_epoch_at_slot(previous_slot)), + ); + let signing_root = compute_signing_root(get_block_root_at_slot(state, previous_slot)?, domain); + verify( + bls::eth_fast_aggregate_verify( + &participant_pubkeys, + signing_root, + &sync_aggregate.sync_committee_signature, + ), + "eth_fast_aggregate_verify(participant_pubkeys, signing_root, sync_aggregate.sync_committee_signature)", + )?; + + // Resolve every committee seat's validator index up front; see this + // function's documentation for why the mutation loop below cannot do its + // own scan of `state.validators` the way the specification's single loop + // does. + let committee_indices: Vec = committee_pubkeys + .iter() + .map(|pubkey| { + state + .validators() + .iter() + .position(|validator| validator.pubkey == *pubkey) + .map(|index| index as ValidatorIndex) + .ok_or(Error::SpecAssert( + "state.current_sync_committee.pubkeys[i] in [v.pubkey for v in state.validators]", + )) + }) + .collect::>>()?; + + let total_active_increments = + get_total_active_balance(state)? / preset::EFFECTIVE_BALANCE_INCREMENT; + let total_base_rewards = get_base_reward_per_increment(state)? + .checked_mul(total_active_increments) + .ok_or(Error::ArithmeticOverflow( + "get_base_reward_per_increment(state) * total_active_increments", + ))?; + let max_participant_rewards = total_base_rewards + .checked_mul(constants::SYNC_REWARD_WEIGHT) + .ok_or(Error::ArithmeticOverflow( + "total_base_rewards * SYNC_REWARD_WEIGHT", + ))? + / constants::WEIGHT_DENOMINATOR + / preset::SLOTS_PER_EPOCH; + let participant_reward = max_participant_rewards / preset::SYNC_COMMITTEE_SIZE as u64; + + const NON_PROPOSER_WEIGHT: u64 = constants::WEIGHT_DENOMINATOR - constants::PROPOSER_WEIGHT; + let proposer_reward = participant_reward + .checked_mul(constants::PROPOSER_WEIGHT) + .ok_or(Error::ArithmeticOverflow( + "participant_reward * PROPOSER_WEIGHT", + ))? + / NON_PROPOSER_WEIGHT; + + // Stable across every iteration below: nothing in this loop changes the + // slot or the seed a proposer is drawn from, so resolving it once here + // (rather than once per seat, as the specification's own pseudocode does) + // is a straightforward optimization, not a behavior change. + let proposer_index = get_beacon_proposer_index(state)?; + + for (position, participant_index) in committee_indices.into_iter().enumerate() { + if committee_bits.get(position).unwrap_or(false) { + increase_balance(state, participant_index, participant_reward)?; + increase_balance(state, proposer_index, proposer_reward)?; + } else { + decrease_balance(state, participant_index, participant_reward)?; + } + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use blst::min_pk::SecretKey; + + use super::*; + use crate::beacon::containers::altair::SyncCommittee; + use crate::beacon::containers::shared::{AttestationData, Checkpoint, Validator}; + use crate::beacon::primitives::{ + BLS_SIGNATURE_SIZE, BlsPubkey, BlsSignature, Bytes32, HashTreeRoot as _, Root, + }; + + /// An altair state with `count` fully active, full-balance validators, each + /// with a real (signable) BLS keypair, positioned one epoch in so the + /// previous epoch and the block-root history window both have entries. + /// + /// A near-duplicate of `crate::beacon::helpers::altair::tests::altair_state_with_validators`, + /// which builds the same shape of state but with placeholder (unsigned, + /// invalid) keys; that builder cannot be reused here since it is private to + /// its module and returns no secret keys, and this module has no shared + /// altair test-state builder yet. The two should probably be merged into + /// one the next time either needs a change. + fn altair_state_with_keypairs(count: usize) -> (BeaconState, Vec) { + let secret_keys: Vec = (0..count) + .map(|index| { + let mut ikm = [0u8; 32]; + ikm[..8].copy_from_slice(&(index as u64 + 1).to_le_bytes()); + SecretKey::key_gen(&ikm, &[]) + .expect("32 bytes of input material is enough for key generation") + }) + .collect(); + + let validators: Vec = secret_keys + .iter() + .map(|secret_key| Validator { + pubkey: BlsPubkey(secret_key.sk_to_pk().to_bytes()), + effective_balance: preset::MAX_EFFECTIVE_BALANCE, + activation_eligibility_epoch: 0, + activation_epoch: 0, + exit_epoch: constants::FAR_FUTURE_EPOCH, + withdrawable_epoch: constants::FAR_FUTURE_EPOCH, + ..Default::default() + }) + .collect(); + + let empty_sync_committee = || SyncCommittee { + pubkeys: vec![BlsPubkey::default(); preset::SYNC_COMMITTEE_SIZE] + .try_into() + .expect("built at exactly SYNC_COMMITTEE_SIZE"), + aggregate_pubkey: BlsPubkey::default(), + }; + + let state = BeaconState::Altair(altair::BeaconState { + genesis_time: 0, + genesis_validators_root: Root::ZERO, + slot: preset::SLOTS_PER_EPOCH, + fork: Default::default(), + latest_block_header: Default::default(), + block_roots: vec![Root::ZERO; preset::SLOTS_PER_HISTORICAL_ROOT] + .try_into() + .expect("the vector is built at its exact length"), + state_roots: vec![Root::ZERO; preset::SLOTS_PER_HISTORICAL_ROOT] + .try_into() + .expect("the vector is built at its exact length"), + historical_roots: Default::default(), + eth1_data: Default::default(), + eth1_data_votes: Default::default(), + eth1_deposit_index: 0, + validators: validators + .try_into() + .expect("count is far below VALIDATOR_REGISTRY_LIMIT"), + balances: vec![preset::MAX_EFFECTIVE_BALANCE; count] + .try_into() + .expect("count is far below VALIDATOR_REGISTRY_LIMIT"), + randao_mixes: vec![Bytes32::ZERO; preset::EPOCHS_PER_HISTORICAL_VECTOR] + .try_into() + .expect("the vector is built at its exact length"), + slashings: vec![0; preset::EPOCHS_PER_SLASHINGS_VECTOR] + .try_into() + .expect("the vector is built at its exact length"), + previous_epoch_participation: vec![0; count] + .try_into() + .expect("count is far below VALIDATOR_REGISTRY_LIMIT"), + current_epoch_participation: vec![0; count] + .try_into() + .expect("count is far below VALIDATOR_REGISTRY_LIMIT"), + justification_bits: Default::default(), + previous_justified_checkpoint: Default::default(), + current_justified_checkpoint: Default::default(), + finalized_checkpoint: Default::default(), + inactivity_scores: vec![0; count] + .try_into() + .expect("count is far below VALIDATOR_REGISTRY_LIMIT"), + current_sync_committee: empty_sync_committee(), + next_sync_committee: empty_sync_committee(), + }); + + (state, secret_keys) + } + + /// `specs/altair/bls.md`'s `G2_POINT_AT_INFINITY`: the compressed encoding + /// of the identity element of G2, and the only signature + /// `eth_fast_aggregate_verify` accepts for an empty participant list. + fn g2_point_at_infinity() -> BlsSignature { + let mut bytes = [0u8; BLS_SIGNATURE_SIZE]; + bytes[0] = 0b1100_0000; + BlsSignature(bytes) + } + + #[test] + fn process_attestation_sets_new_flags_once_and_pays_the_proposer_only_for_them() { + let (mut state, secret_keys) = altair_state_with_keypairs(64); + + // The last slot of the previous epoch: `state.slot()` sits at + // `SLOTS_PER_EPOCH` (one epoch in, matching `altair_state_with_keypairs`), + // so an attestation for this slot has an inclusion delay of exactly + // `MIN_ATTESTATION_INCLUSION_DELAY`, which is what makes it eligible + // for all three timeliness flags rather than just source and target. + let data_slot = preset::SLOTS_PER_EPOCH - 1; + let target_epoch = compute_epoch_at_slot(data_slot); + assert_eq!(target_epoch, 0, "the previous epoch, by construction"); + + let committee = get_beacon_committee(&state, data_slot, 0).expect("committee exists"); + assert!( + !committee.is_empty(), + "64 validators spread finely enough across the shuffle that every \ + slot's first committee has at least one member, under either preset" + ); + + let data = AttestationData { + slot: data_slot, + index: 0, + // Matches the all-zero synthetic block-root history exactly, which + // is what makes both the target and the head vote "matching". + beacon_block_root: Root::ZERO, + source: Checkpoint::default(), + target: Checkpoint { + epoch: target_epoch, + root: Root::ZERO, + }, + }; + + let mut aggregation_bits = + crate::beacon::containers::phase0::AggregationBits::with_length(committee.len()) + .expect("committee.len() is far below MAX_VALIDATORS_PER_COMMITTEE"); + for position in 0..committee.len() { + aggregation_bits.set(position, true).unwrap(); + } + + let domain = get_domain( + &state, + constants::DOMAIN_BEACON_ATTESTER, + Some(target_epoch), + ); + let signing_root = compute_signing_root(data.hash_tree_root(), domain); + const DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; + let signatures: Vec = committee + .iter() + .map(|&index| { + BlsSignature( + secret_keys[index as usize] + .sign(signing_root.as_slice(), DST, &[]) + .to_bytes(), + ) + }) + .collect(); + let signature = bls::aggregate(&signatures).unwrap(); + + let attestation = phase0::Attestation { + aggregation_bits, + data, + signature, + }; + + let proposer_index = get_beacon_proposer_index(&state).unwrap(); + let balance_before = state.balance(proposer_index).unwrap(); + + process_attestation(&mut state, &attestation).unwrap(); + + let (previous_epoch_participation, _, _) = state.altair_validator_lists().unwrap(); + for &index in &committee { + let flags = previous_epoch_participation[index as usize]; + assert!( + has_flag(flags, constants::TIMELY_SOURCE_FLAG_INDEX), + "validator {index} should have earned the timely-source flag" + ); + assert!( + has_flag(flags, constants::TIMELY_TARGET_FLAG_INDEX), + "validator {index} should have earned the timely-target flag" + ); + assert!( + has_flag(flags, constants::TIMELY_HEAD_FLAG_INDEX), + "validator {index} should have earned the timely-head flag, since \ + the inclusion delay is exactly MIN_ATTESTATION_INCLUSION_DELAY" + ); + } + + let balance_after = state.balance(proposer_index).unwrap(); + assert!( + balance_after > balance_before, + "the proposer must be paid for newly granting three flags to every attester" + ); + + // Idempotency: every flag this attestation could grant is already set, + // so reprocessing the identical attestation must grant nothing new, and + // the proposer's balance must not move. + let balance_before_replay = state.balance(proposer_index).unwrap(); + process_attestation(&mut state, &attestation).unwrap(); + let balance_after_replay = state.balance(proposer_index).unwrap(); + assert_eq!( + balance_before_replay, balance_after_replay, + "a repeat vote must earn nothing, since every flag it could set is already set" + ); + } + + #[test] + fn process_sync_aggregate_rewards_participants_and_penalizes_a_repeated_non_participant() { + // Five validators: the first four hold one participating seat each, + // and the fifth's key fills every one of the remaining committee + // seats, all marked non-participating. That exercises the same + // validator index being resolved, and paid or penalized, more than + // once per call, which is exactly what the borrow-checker fix (resolve + // every seat's index before the mutation loop) has to get right. + let (mut state, secret_keys) = altair_state_with_keypairs(5); + + let participant_pubkeys: Vec = secret_keys[0..4] + .iter() + .map(|secret_key| BlsPubkey(secret_key.sk_to_pk().to_bytes())) + .collect(); + let filler_pubkey = BlsPubkey(secret_keys[4].sk_to_pk().to_bytes()); + + let mut pubkeys_vec = participant_pubkeys.clone(); + pubkeys_vec.resize(preset::SYNC_COMMITTEE_SIZE, filler_pubkey); + let aggregate_pubkey = bls::eth_aggregate_pubkeys(&pubkeys_vec).unwrap(); + let pubkeys = pubkeys_vec + .try_into() + .expect("built at exactly SYNC_COMMITTEE_SIZE"); + + let mut sync_committee_bits = altair::SyncCommitteeBits::default(); + for position in 0..participant_pubkeys.len() { + sync_committee_bits.set(position, true).unwrap(); + } + + { + let (current_sync_committee, _) = state.sync_committees_mut().unwrap(); + *current_sync_committee = SyncCommittee { + pubkeys, + aggregate_pubkey, + }; + } + + let previous_slot = state.slot() - 1; + let domain = get_domain( + &state, + constants::DOMAIN_SYNC_COMMITTEE, + Some(compute_epoch_at_slot(previous_slot)), + ); + // Matches the all-zero synthetic block-root history. + let signing_root = compute_signing_root(Root::ZERO, domain); + + const DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; + let signatures: Vec = secret_keys[0..4] + .iter() + .map(|secret_key| { + BlsSignature( + secret_key + .sign(signing_root.as_slice(), DST, &[]) + .to_bytes(), + ) + }) + .collect(); + let sync_committee_signature = bls::aggregate(&signatures).unwrap(); + + let sync_aggregate = altair::SyncAggregate { + sync_committee_bits, + sync_committee_signature, + }; + + let proposer_index = get_beacon_proposer_index(&state).unwrap(); + let balances_before: Vec = (0..5u64) + .map(|index| state.balance(index).unwrap()) + .collect(); + + process_sync_aggregate(&mut state, &sync_aggregate).unwrap(); + + // Independently derived expected rewards, sharing only the + // already-tested building blocks (`get_total_active_balance`, + // `get_base_reward_per_increment`) with `process_sync_aggregate` + // itself, not the arithmetic under test. + let total_active_increments = + get_total_active_balance(&state).unwrap() / preset::EFFECTIVE_BALANCE_INCREMENT; + let total_base_rewards = + get_base_reward_per_increment(&state).unwrap() * total_active_increments; + let max_participant_rewards = total_base_rewards * constants::SYNC_REWARD_WEIGHT + / constants::WEIGHT_DENOMINATOR + / preset::SLOTS_PER_EPOCH; + let participant_reward = max_participant_rewards / preset::SYNC_COMMITTEE_SIZE as u64; + let proposer_reward = participant_reward * constants::PROPOSER_WEIGHT + / (constants::WEIGHT_DENOMINATOR - constants::PROPOSER_WEIGHT); + + let filler_seats = (preset::SYNC_COMMITTEE_SIZE - 4) as u64; + for index in 0..5u64 { + let mut expected = balances_before[index as usize] as i128; + if index < 4 { + expected += participant_reward as i128; + } else { + expected -= (participant_reward * filler_seats) as i128; + } + if index == proposer_index { + expected += (proposer_reward * 4) as i128; + } + assert_eq!( + state.balance(index).unwrap() as i128, + expected, + "validator {index}'s balance did not match its expected reward or penalty" + ); + } + } + + #[test] + fn process_sync_aggregate_rejects_a_non_infinity_signature_for_zero_participants() { + let (mut state, secret_keys) = altair_state_with_keypairs(1); + let filler_pubkey = BlsPubkey(secret_keys[0].sk_to_pk().to_bytes()); + let pubkeys_vec = vec![filler_pubkey; preset::SYNC_COMMITTEE_SIZE]; + let aggregate_pubkey = bls::eth_aggregate_pubkeys(&pubkeys_vec).unwrap(); + let pubkeys = pubkeys_vec + .try_into() + .expect("built at exactly SYNC_COMMITTEE_SIZE"); + + { + let (current_sync_committee, _) = state.sync_committees_mut().unwrap(); + *current_sync_committee = SyncCommittee { + pubkeys, + aggregate_pubkey, + }; + } + + // Every bit left at zero: nobody participated, so + // `eth_fast_aggregate_verify` demands the point-at-infinity signature + // and nothing else, matching the specification's convention for an + // aggregate over an empty key set. + let sync_committee_bits = altair::SyncCommitteeBits::default(); + + let wrong = altair::SyncAggregate { + sync_committee_bits: sync_committee_bits.clone(), + sync_committee_signature: BlsSignature::default(), + }; + assert!( + process_sync_aggregate(&mut state.clone(), &wrong).is_err(), + "the all-zero signature is not the point at infinity, so this must be rejected" + ); + + let correct = altair::SyncAggregate { + sync_committee_bits, + sync_committee_signature: g2_point_at_infinity(), + }; + let balance_before = state.balance(0).unwrap(); + process_sync_aggregate(&mut state, &correct).unwrap(); + + // The sole validator holds every seat and none of them participated, + // so it is penalized once per seat and the proposer (itself, the only + // validator in this registry) earns nothing extra. + let total_active_increments = + get_total_active_balance(&state).unwrap() / preset::EFFECTIVE_BALANCE_INCREMENT; + let total_base_rewards = + get_base_reward_per_increment(&state).unwrap() * total_active_increments; + let max_participant_rewards = total_base_rewards * constants::SYNC_REWARD_WEIGHT + / constants::WEIGHT_DENOMINATOR + / preset::SLOTS_PER_EPOCH; + let participant_reward = max_participant_rewards / preset::SYNC_COMMITTEE_SIZE as u64; + let expected_penalty = participant_reward * preset::SYNC_COMMITTEE_SIZE as u64; + + assert_eq!( + state.balance(0).unwrap(), + balance_before.saturating_sub(expected_penalty) + ); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/bellatrix.rs b/crates/blockchain/state_transition/src/beacon/stf/bellatrix.rs new file mode 100644 index 000000000..208bff1ae --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/bellatrix.rs @@ -0,0 +1,486 @@ +//! Bellatrix's block processing: the Merge. +//! +//! Before this fork, the beacon chain and the execution chain ran two separate +//! consensus mechanisms: proof-of-work miners built the execution chain on +//! their own schedule, joined to the beacon chain only by the deposit +//! contract. Bellatrix retires the execution chain's own consensus outright: +//! from here on a beacon block carries its execution block whole, as an +//! [`bellatrix::ExecutionPayload`], and [`process_execution_payload`] is the +//! one new step [`process_block`] adds to validate it and hand it to +//! [`super::ExecutionEngine`]'s stand-in for a real execution client. +//! +//! [`BeaconState`] keeps only [`bellatrix::ExecutionPayloadHeader`], never the +//! whole payload. Everything a later block needs from the one before it is +//! enough to check continuity, that the new payload's `parent_hash` chains to +//! the stored header's own `block_hash`, and [`process_execution_payload`] +//! does exactly that without ever asking the execution layer what came +//! before. Keeping every transaction, in every state, forever, would cost far +//! more than that one check needs, so the header substitutes +//! `transactions_root` for `transactions`, the same substitution +//! [`crate::beacon::containers::shared::BeaconBlockHeader`] already makes for a +//! beacon block's own body. +//! +//! [`is_merge_transition_complete`], [`is_merge_transition_block`], and +//! [`is_execution_enabled`] exist only for the fork in which the transition +//! itself can happen. Once a chain's first real payload lands, +//! `is_merge_transition_complete` answers the same way forever, and capella's +//! own specification drops the whole family of checks rather than keep +//! evaluating a question every later block already answers identically. See +//! [`bellatrix_state_ref`]'s documentation for what that implies about how +//! far this file's own state projection needs to reach. + +use crate::beacon::config::Config; +use crate::beacon::constants; +use crate::beacon::containers::{BeaconState, bellatrix}; +use crate::beacon::error::{Error, Result, verify}; +use crate::beacon::helpers::accessors::{get_current_epoch, get_randao_mix}; +use crate::beacon::preset; +use crate::beacon::primitives::{ + Bytes32, ExecutionAddress, ExecutionBlockHash, HashTreeRoot as _, Root, Slot, Uint256, +}; + +use super::ExecutionEngine; + +// --------------------------------------------------------------------------- +// Block processing +// --------------------------------------------------------------------------- + +/// Bellatrix's block processing: altair's steps, with the execution payload +/// inserted between the header and the RANDAO reveal. +/// +/// That insertion point is the one place this fork's own order matters, and +/// the specification says so explicitly: [`process_execution_payload`] must +/// run before [`super::block::process_randao`], because the payload's +/// `prev_randao` has to match the *previous* block's mix, the very one +/// [`super::block::process_randao`] is about to overwrite with this block's +/// own reveal. Running them in the other order would check `prev_randao` +/// against a mix this same block already replaced, which no honest proposer +/// could ever satisfy. +/// +/// The payload step is conditional on [`is_execution_enabled`]: bellatrix is +/// the one fork where a block might still legitimately carry no real payload, +/// if this chain's merge transition has not happened yet. Every later fork +/// drops the condition outright, since by then it is always true. +pub fn process_block( + state: &mut BeaconState, + block: &bellatrix::BeaconBlock, + config: &Config, + engine: &ExecutionEngine, +) -> Result<()> { + super::block::process_block_header( + state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + )?; + if is_execution_enabled(state, &block.body.execution_payload)? { + process_execution_payload(state, &block.body.execution_payload, config, engine)?; + } + super::block::process_randao(state, &block.body.randao_reveal)?; + super::block::process_eth1_data(state, &block.body.eth1_data)?; + super::operations::process_operations( + state, + &block.body.proposer_slashings, + &block.body.attester_slashings, + &block.body.attestations, + &block.body.deposits, + &block.body.voluntary_exits, + config, + )?; + super::altair::process_sync_aggregate(state, &block.body.sync_aggregate)?; + Ok(()) +} + +/// Validates this slot's execution payload against the state and the +/// stand-in execution engine, then caches its header. +/// +/// Takes `payload` alone rather than a whole body, the same way every shared +/// step in [`super::block`] takes only the fields it reads; see +/// [`crate::beacon::stf`]'s module documentation for why no shared body type exists to +/// pass instead. Takes `config`, which the specification's own +/// `process_execution_payload(state, body, execution_engine)` does not: the +/// specification reaches `SECONDS_PER_SLOT` from global scope the way every +/// specification function reaches every constant, but that value is a +/// network's own [`Config::seconds_per_slot`] here, not a preset, so +/// [`compute_timestamp_at_slot`], the one thing this calls that actually needs +/// it, has to be handed one, and so must this. +/// +/// Collapses the specification's `verify_and_notify_new_payload` (itself +/// `is_valid_block_hash` and `notify_new_payload`, both calls to a real +/// execution client) into reading [`ExecutionEngine::execution_valid`] +/// straight off the stand-in `engine`; see that type's own documentation for +/// why nothing here can call out to a real one. +pub fn process_execution_payload( + state: &mut BeaconState, + payload: &bellatrix::ExecutionPayload, + config: &Config, + engine: &ExecutionEngine, +) -> Result<()> { + if is_merge_transition_complete(state)? { + let bellatrix_ref = bellatrix_state_ref(state, "process_execution_payload")?; + verify( + payload.parent_hash == bellatrix_ref.latest_execution_payload_header.block_hash, + "payload.parent_hash == state.latest_execution_payload_header.block_hash", + )?; + } + verify( + payload.prev_randao == get_randao_mix(state, get_current_epoch(state)), + "payload.prev_randao == get_randao_mix(state, get_current_epoch(state))", + )?; + verify( + payload.timestamp == compute_timestamp_at_slot(state, state.slot(), config), + "payload.timestamp == compute_timestamp_at_slot(state, state.slot, config)", + )?; + verify( + engine.execution_valid, + "verify_and_notify_new_payload(NewPayloadRequest(execution_payload=payload))", + )?; + + let header = bellatrix::ExecutionPayloadHeader { + parent_hash: payload.parent_hash, + fee_recipient: payload.fee_recipient, + state_root: payload.state_root, + receipts_root: payload.receipts_root, + logs_bloom: payload.logs_bloom.clone(), + prev_randao: payload.prev_randao, + block_number: payload.block_number, + gas_limit: payload.gas_limit, + gas_used: payload.gas_used, + timestamp: payload.timestamp, + extra_data: payload.extra_data.clone(), + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash, + // The header substitutes a root for the whole transaction list; see + // this module's own documentation for why the state keeps only that + // much. + transactions_root: payload.transactions.hash_tree_root(), + }; + bellatrix_state(state, "process_execution_payload")?.latest_execution_payload_header = header; + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Merge-transition predicates +// --------------------------------------------------------------------------- + +/// Whether this chain's merge transition has already happened: whether some +/// earlier block already set `latest_execution_payload_header` to anything +/// other than the all-default value every pre-merge state carries. +/// +/// Once true, stays true forever: nothing ever resets +/// `latest_execution_payload_header` back to its default. Capella's own +/// specification relies on exactly that monotonicity to drop this whole +/// question; see [`bellatrix_state_ref`]'s documentation for what that means +/// for this file's own state projection. +pub fn is_merge_transition_complete(state: &BeaconState) -> Result { + let bellatrix_ref = bellatrix_state_ref(state, "is_merge_transition_complete")?; + Ok(bellatrix_ref.latest_execution_payload_header != default_execution_payload_header()?) +} + +/// Whether `payload` is the one block that carries this chain's transition: +/// the merge has not completed yet, and this payload is not the empty +/// placeholder either. +/// +/// A block proposed before the transition still has to put *something* in its +/// `execution_payload` field, since bellatrix's `BeaconBlockBody` carries one +/// unconditionally rather than making it optional; the specification's own +/// convention is that such a block carries the all-default +/// [`bellatrix::ExecutionPayload`], which this treats as "no real payload +/// yet" rather than as a payload to validate. +pub fn is_merge_transition_block( + state: &BeaconState, + payload: &bellatrix::ExecutionPayload, +) -> Result { + Ok(!is_merge_transition_complete(state)? && *payload != default_execution_payload()?) +} + +/// Whether [`process_execution_payload`] should run at all for this block: +/// either the transition already happened, or this block is the one that +/// makes it happen. +/// +/// The only way this is false is a pre-merge block carrying no real payload; +/// every later fork drops this check because that possibility itself stops +/// existing once a chain's transition is behind it. +pub fn is_execution_enabled( + state: &BeaconState, + payload: &bellatrix::ExecutionPayload, +) -> Result { + Ok(is_merge_transition_block(state, payload)? || is_merge_transition_complete(state)?) +} + +// --------------------------------------------------------------------------- +// Time +// --------------------------------------------------------------------------- + +/// The wall-clock Unix time a slot's block is due, from the chain's genesis +/// time and [`Config::seconds_per_slot`]. +/// +/// Named `compute_timestamp_at_slot` here rather than the specification's own +/// `compute_time_at_slot`; [`Config::seconds_per_slot`]'s own doc comment +/// already anticipates the specification's name, so the two disagree, and +/// whoever next touches either should settle on one name in both places. +/// +/// The specification flags this arithmetic as "unsafe with respect to +/// overflows and underflows", a warning aimed at Python's own +/// arbitrary-precision integers never actually needing it. This function +/// cannot return an error (its caller, [`process_execution_payload`], only +/// ever compares the result against a value the block itself supplies, so +/// there is nothing to reject the block *for* here), so an overflow +/// saturates rather than wraps: wrapping could land on a small value that +/// looks like a plausible, if wrong, timestamp, where saturating cannot. +pub fn compute_timestamp_at_slot(state: &BeaconState, slot: Slot, config: &Config) -> u64 { + // `GENESIS_SLOT` is `Slot`'s zero point, so subtracting it from any slot + // can never underflow. + let slots_since_genesis = slot - constants::GENESIS_SLOT; + slots_since_genesis + .saturating_mul(config.seconds_per_slot) + .saturating_add(state.genesis_time()) +} + +// --------------------------------------------------------------------------- +// Fork projection +// --------------------------------------------------------------------------- + +/// The bellatrix state, mutably, or an error naming the function that needs +/// one. +/// +/// Scoped to `BeaconState::Bellatrix` alone, not to every fork from bellatrix +/// through fulu. That narrower scope is deliberate. Every caller in this file +/// is reached only through [`process_block`], which +/// [`super::block::process_block`] dispatches to precisely when `state` is +/// already `BeaconState::Bellatrix` (checked once, before any per-fork +/// dispatch, by [`super::state_transition`]), and nothing outside this file +/// ever calls back into it for a later fork's own state. Capella's +/// specification is explicit about why that is safe: its own `process_block` +/// drops the `is_execution_enabled` call, and its own +/// `process_execution_payload` drops the `is_merge_transition_complete` +/// check, both marked "Removed" rather than "Modified", because once a +/// chain's transition is behind it, every later block answers both questions +/// the same way regardless of anything this projection could tell it. Each +/// fork from capella on keeps its own `latest_execution_payload_header`, of +/// its own distinct type (withdrawals added at capella, blob fields at deneb, +/// and so on), and will need its own projection of this same shape to reach +/// it, not this one widened to somehow return a different concrete type per +/// caller. +pub(crate) fn bellatrix_state<'a>( + state: &'a mut BeaconState, + function: &'static str, +) -> Result<&'a mut bellatrix::BeaconState> { + match state { + BeaconState::Bellatrix(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +/// The bellatrix state, immutably. See [`bellatrix_state`]. +pub(crate) fn bellatrix_state_ref<'a>( + state: &'a BeaconState, + function: &'static str, +) -> Result<&'a bellatrix::BeaconState> { + match state { + BeaconState::Bellatrix(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +// --------------------------------------------------------------------------- +// Default values +// --------------------------------------------------------------------------- + +/// The all-default [`bellatrix::ExecutionPayloadHeader`]: the value the +/// specification's bare `ExecutionPayloadHeader()` constructor builds, every +/// field at its type's zero value. +/// +/// Not `#[derive(Default)]`: `logs_bloom` is an [`libssz_types::SszVector`], and +/// libssz gives that type no `Default` impl at all, since, unlike a list, a +/// fixed-length vector has no value that is validly empty. [`crate::beacon::upgrade`] already builds this exact +/// value the same way, for the same reason, when altair's state upgrades into +/// bellatrix's; its helper is private to that module, and this file may only +/// touch its own, so this is a deliberate second copy rather than a shared +/// one. [`is_merge_transition_complete`] is this function's only caller. +fn default_execution_payload_header() -> Result { + Ok(bellatrix::ExecutionPayloadHeader { + parent_hash: ExecutionBlockHash::ZERO, + fee_recipient: ExecutionAddress::ZERO, + state_root: Bytes32::ZERO, + receipts_root: Bytes32::ZERO, + logs_bloom: bellatrix::LogsBloom::try_from(vec![0u8; preset::BYTES_PER_LOGS_BLOOM])?, + prev_randao: Bytes32::ZERO, + block_number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: 0, + extra_data: bellatrix::ExtraData::default(), + base_fee_per_gas: Uint256::ZERO, + block_hash: ExecutionBlockHash::ZERO, + transactions_root: Root::ZERO, + }) +} + +/// The all-default [`bellatrix::ExecutionPayload`]: the value the +/// specification's bare `ExecutionPayload()` constructor builds. See +/// [`default_execution_payload_header`] for why this is built field by field +/// rather than derived. [`is_merge_transition_block`] is this function's only +/// caller. +fn default_execution_payload() -> Result { + Ok(bellatrix::ExecutionPayload { + parent_hash: ExecutionBlockHash::ZERO, + fee_recipient: ExecutionAddress::ZERO, + state_root: Bytes32::ZERO, + receipts_root: Bytes32::ZERO, + logs_bloom: bellatrix::LogsBloom::try_from(vec![0u8; preset::BYTES_PER_LOGS_BLOOM])?, + prev_randao: Bytes32::ZERO, + block_number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: 0, + extra_data: bellatrix::ExtraData::default(), + base_fee_per_gas: Uint256::ZERO, + block_hash: ExecutionBlockHash::ZERO, + transactions: Default::default(), + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::fork::ForkName; + + /// A bellatrix state with `count` fully active, full-balance validators, + /// one epoch in (so the block-root history window already has entries), + /// and `header` as its `latest_execution_payload_header`. + /// + /// A thin wrapper around the shared fork-parameterised builder, which has + /// no header to take as a parameter, so this overrides the placeholder it + /// builds with the one every real caller here actually wants under test. + /// See [`crate::beacon::helpers::test_state::with_validators_at`] for the + /// construction this and every other fork's test module used to + /// duplicate. + fn bellatrix_state_with_validators( + count: usize, + header: bellatrix::ExecutionPayloadHeader, + ) -> BeaconState { + let mut state = + crate::beacon::helpers::test_state::with_validators_at(ForkName::Bellatrix, count); + if let BeaconState::Bellatrix(inner) = &mut state { + inner.latest_execution_payload_header = header; + } + state + } + + /// A payload that is not the all-default placeholder: distinct from + /// [`default_execution_payload`] in exactly one field, which is enough + /// for every predicate under test here. + fn non_default_payload() -> bellatrix::ExecutionPayload { + let mut payload = default_execution_payload().unwrap(); + payload.parent_hash = ExecutionBlockHash::repeat_byte(0xab); + payload + } + + // The three states worth distinguishing: a chain that has not started its + // merge transition and whose block carries no real payload either, a + // chain mid-transition whose block is the transition block itself, and a + // chain whose transition is already behind it. + + #[test] + fn pre_merge_state_with_no_real_payload_leaves_execution_disabled() { + let header = default_execution_payload_header().unwrap(); + let state = bellatrix_state_with_validators(4, header); + let payload = default_execution_payload().unwrap(); + + assert!(!is_merge_transition_complete(&state).unwrap()); + assert!(!is_merge_transition_block(&state, &payload).unwrap()); + assert!(!is_execution_enabled(&state, &payload).unwrap()); + } + + #[test] + fn pre_merge_state_with_a_real_payload_is_the_transition_block() { + let header = default_execution_payload_header().unwrap(); + let state = bellatrix_state_with_validators(4, header); + let payload = non_default_payload(); + + assert!(!is_merge_transition_complete(&state).unwrap()); + assert!(is_merge_transition_block(&state, &payload).unwrap()); + assert!( + is_execution_enabled(&state, &payload).unwrap(), + "the transition block itself must still run process_execution_payload" + ); + } + + #[test] + fn post_merge_state_has_execution_enabled_regardless_of_the_payload() { + let mut header = default_execution_payload_header().unwrap(); + header.block_hash = ExecutionBlockHash::repeat_byte(0xcd); + let state = bellatrix_state_with_validators(4, header); + + assert!(is_merge_transition_complete(&state).unwrap()); + + // Once the transition is behind a chain, `is_merge_transition_block` + // is false no matter what the payload looks like: the first half of + // its own condition already failed, so the payload's own shape + // cannot rescue it. + let empty_payload = default_execution_payload().unwrap(); + assert!(!is_merge_transition_block(&state, &empty_payload).unwrap()); + assert!(is_execution_enabled(&state, &empty_payload).unwrap()); + + let real_payload = non_default_payload(); + assert!(!is_merge_transition_block(&state, &real_payload).unwrap()); + assert!(is_execution_enabled(&state, &real_payload).unwrap()); + } + + #[test] + fn compute_timestamp_at_slot_matches_genesis_time_plus_slot_seconds() { + let header = default_execution_payload_header().unwrap(); + let state = bellatrix_state_with_validators(4, header); + let config = Config::minimal(); + + let expected = state.genesis_time() + state.slot() * config.seconds_per_slot; + assert_eq!( + compute_timestamp_at_slot(&state, state.slot(), &config), + expected + ); + } + + #[test] + fn process_execution_payload_rejects_an_invalid_engine_but_accepts_a_valid_one() { + let header = default_execution_payload_header().unwrap(); + let mut state = bellatrix_state_with_validators(4, header); + let config = Config::minimal(); + + let mut payload = non_default_payload(); + payload.prev_randao = get_randao_mix(&state, get_current_epoch(&state)); + payload.timestamp = compute_timestamp_at_slot(&state, state.slot(), &config); + + assert!( + process_execution_payload( + &mut state.clone(), + &payload, + &config, + &ExecutionEngine::invalid() + ) + .is_err(), + "an execution client that rejects the payload must fail the block" + ); + + process_execution_payload(&mut state, &payload, &config, &ExecutionEngine::valid()) + .unwrap(); + + assert!(is_merge_transition_complete(&state).unwrap()); + let stored_header = &bellatrix_state_ref(&state, "test assertion") + .unwrap() + .latest_execution_payload_header; + assert_eq!(stored_header.parent_hash, payload.parent_hash); + assert_eq!( + stored_header.transactions_root, + payload.transactions.hash_tree_root() + ); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/block.rs b/crates/blockchain/state_transition/src/beacon/stf/block.rs new file mode 100644 index 000000000..37218c66f --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/block.rs @@ -0,0 +1,313 @@ +//! Block processing: the header, RANDAO, and eth1-vote steps every fork shares, +//! plus the per-fork drivers that run them (and each fork's own operations) in +//! the specification's order. +//! +//! Corresponds to the specification's "Block processing" section (`## +//! Beacon chain state transition function` > `### Block processing`), redefined +//! once per fork here the same way the specification itself redefines +//! `process_block` per fork rather than parameterising a single definition. +//! [`process_block`] is the dispatcher [`super::state_transition`] calls, and +//! [`process_block_phase0`] and [`process_block_altair`] are the two drivers it +//! dispatches to that are actually implemented; see [`super::bellatrix`] and its +//! siblings for the rest, and [`super`]'s module documentation for why none of +//! this needs a shared body type to do it. +//! +//! [`process_block_header`], [`process_randao`], and [`process_eth1_data`] take +//! the fields they read directly rather than a whole body, which is what lets +//! every driver, present and future, call the identical function regardless of +//! what else that fork's body carries. + +use crate::beacon::bls; +use crate::beacon::config::Config; +use crate::beacon::constants; +use crate::beacon::containers::{self, BeaconBlockHeader, BeaconState, Eth1Data, altair, phase0}; +use crate::beacon::error::{Result, verify}; +use crate::beacon::hash::hash; +use crate::beacon::helpers::accessors::{ + get_beacon_proposer_index, get_current_epoch, get_domain, get_randao_mix, +}; +use crate::beacon::helpers::math::xor; +use crate::beacon::helpers::misc::compute_signing_root; +use crate::beacon::preset; +use crate::beacon::primitives::{BlsSignature, HashTreeRoot as _, Root, Slot, ValidatorIndex}; + +use super::{ExecutionEngine, bellatrix, capella, deneb, electra, fulu}; + +/// Dispatches on the block's fork and runs that fork's own block processing. +/// +/// Matches [`containers::SignedBeaconBlock`]'s variant once, then hands the +/// unwrapped, fork-specific `BeaconBlock` to the function written for it. Called +/// after [`super::process_slots`] has already advanced the state to the block's +/// slot, so every arm validates and mutates a state already positioned at +/// `signed_block`'s slot. +pub fn process_block( + state: &mut BeaconState, + signed_block: &containers::SignedBeaconBlock, + config: &Config, + engine: &ExecutionEngine, +) -> Result<()> { + match signed_block { + containers::SignedBeaconBlock::Phase0(signed) => { + process_block_phase0(state, &signed.message, config) + } + containers::SignedBeaconBlock::Altair(signed) => { + process_block_altair(state, &signed.message, config) + } + containers::SignedBeaconBlock::Bellatrix(signed) => { + bellatrix::process_block(state, &signed.message, config, engine) + } + containers::SignedBeaconBlock::Capella(signed) => { + capella::process_block(state, &signed.message, config, engine) + } + containers::SignedBeaconBlock::Deneb(signed) => { + deneb::process_block(state, &signed.message, config, engine) + } + containers::SignedBeaconBlock::Electra(signed) => { + electra::process_block(state, &signed.message, config, engine) + } + containers::SignedBeaconBlock::Fulu(signed) => { + fulu::process_block(state, &signed.message, config, engine) + } + } +} + +/// Phase0's block processing: the header, the RANDAO reveal, the eth1 vote, +/// then every operation, in the specification's order. +pub fn process_block_phase0( + state: &mut BeaconState, + block: &phase0::BeaconBlock, + config: &Config, +) -> Result<()> { + process_block_header( + state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + )?; + process_randao(state, &block.body.randao_reveal)?; + process_eth1_data(state, &block.body.eth1_data)?; + crate::beacon::stf::operations::process_operations( + state, + &block.body.proposer_slashings, + &block.body.attester_slashings, + &block.body.attestations, + &block.body.deposits, + &block.body.voluntary_exits, + config, + )?; + Ok(()) +} + +/// Altair's block processing: phase0's steps, plus the sync aggregate. +/// +/// The sync aggregate runs last, after every operation, matching the +/// specification's own `process_block`, which appends +/// `process_sync_aggregate(state, block.body.sync_aggregate)` to phase0's list +/// rather than interleaving it earlier. +pub fn process_block_altair( + state: &mut BeaconState, + block: &altair::BeaconBlock, + config: &Config, +) -> Result<()> { + process_block_header( + state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + )?; + process_randao(state, &block.body.randao_reveal)?; + process_eth1_data(state, &block.body.eth1_data)?; + crate::beacon::stf::operations::process_operations( + state, + &block.body.proposer_slashings, + &block.body.attester_slashings, + &block.body.attestations, + &block.body.deposits, + &block.body.voluntary_exits, + config, + )?; + super::altair::process_sync_aggregate(state, &block.body.sync_aggregate)?; + Ok(()) +} + +/// Validates a block's header against the state and records it as the state's +/// `latest_block_header`. +/// +/// Checks, in order: the slot matches the state's current slot, the slot is +/// strictly after the previous header's, the proposer index is the one the +/// shuffling computes for this slot, the parent root matches the previous +/// header's own root, and the proposer has not been slashed. The slashed check +/// runs last because the specification itself runs it after the header has +/// already been overwritten, which is one more reason an invalid block cannot +/// be retried against the same state: by the time this returns an error, the +/// header it rejected the block for is already gone. +/// +/// Takes `body_root` rather than a body to hash itself, unlike every other +/// piece a driver hands this module's shared steps: a body's shape is +/// fork-specific, so only the caller, which already knows which fork it is +/// calling from, can compute `hash_tree_root()` on it. This function makes no +/// assertion about `body_root` beyond using it verbatim as the header's own +/// field; the caller must pass `block.body.hash_tree_root()`, and a wrong value +/// here would corrupt the header exactly as a wrong value from the +/// specification's own `hash_tree_root(block.body)` would. +pub fn process_block_header( + state: &mut BeaconState, + slot: Slot, + proposer_index: ValidatorIndex, + parent_root: Root, + body_root: Root, +) -> Result<()> { + verify(slot == state.slot(), "block.slot == state.slot")?; + verify( + slot > state.latest_block_header().slot, + "block.slot > state.latest_block_header.slot", + )?; + verify( + proposer_index == get_beacon_proposer_index(state)?, + "block.proposer_index == get_beacon_proposer_index(state)", + )?; + verify( + parent_root == state.latest_block_header().hash_tree_root(), + "block.parent_root == hash_tree_root(state.latest_block_header)", + )?; + + *state.latest_block_header_mut() = BeaconBlockHeader { + slot, + proposer_index, + parent_root, + // Left zero for the reason given on `super::process_slot`'s doc + // comment: a block cannot commit to the root of the state it produces. + state_root: Root::ZERO, + body_root, + }; + + verify( + !state.validator(proposer_index)?.slashed, + "proposer is not slashed", + )?; + Ok(()) +} + +/// Verifies the proposer's RANDAO reveal and mixes it into the current epoch's +/// randao mix. +/// +/// The reveal signs the epoch rather than the slot, so the same signature would +/// verify for every slot of the epoch: the mix it feeds is per-epoch, not +/// per-slot, and a skipped slot leaves nothing for the next proposer to reveal +/// differently. +pub fn process_randao(state: &mut BeaconState, randao_reveal: &BlsSignature) -> Result<()> { + let epoch = get_current_epoch(state); + let proposer_index = get_beacon_proposer_index(state)?; + let domain = get_domain(state, constants::DOMAIN_RANDAO, None); + let signing_root = compute_signing_root(epoch.hash_tree_root(), domain); + + let proposer = state.validator(proposer_index)?; + verify( + bls::verify(&proposer.pubkey, signing_root, randao_reveal), + "RANDAO reveal signature", + )?; + + let mix = xor(get_randao_mix(state, epoch), hash(&randao_reveal.0)); + let position = epoch as usize % preset::EPOCHS_PER_HISTORICAL_VECTOR; + state.randao_mixes_mut()[position] = mix; + Ok(()) +} + +/// Records the block's eth1 vote, adopting it once it holds a majority within +/// the voting period. +/// +/// The voting period is `EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH`, the +/// specification's own expression for it. Both are preset values rather than +/// per-chain configuration, which is why this function needs no `Config`. The +/// count used for the majority check includes the vote just appended, so a +/// single block can supply the deciding vote. +pub fn process_eth1_data(state: &mut BeaconState, eth1_data: &Eth1Data) -> Result<()> { + state.eth1_data_votes_mut().push(eth1_data.clone())?; + + let matching_votes = state + .eth1_data_votes() + .iter() + .filter(|vote| *vote == eth1_data) + .count() as u64; + let voting_period_slots = preset::EPOCHS_PER_ETH1_VOTING_PERIOD * preset::SLOTS_PER_EPOCH; + if matching_votes * 2 > voting_period_slots { + *state.eth1_data_mut() = eth1_data.clone(); + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::primitives::Bytes32; + + /// An otherwise-empty block body, since the header, RANDAO, and eth1 checks + /// below never look past its `hash_tree_root`. + fn empty_body() -> phase0::BeaconBlockBody { + phase0::BeaconBlockBody { + randao_reveal: BlsSignature::default(), + eth1_data: Eth1Data::default(), + graffiti: Bytes32::ZERO, + proposer_slashings: Default::default(), + attester_slashings: Default::default(), + attestations: Default::default(), + deposits: Default::default(), + voluntary_exits: Default::default(), + } + } + + #[test] + fn a_mismatched_parent_root_is_rejected() { + let mut state = crate::beacon::helpers::test_state::with_validators(8); + let proposer_index = get_beacon_proposer_index(&state).unwrap(); + + let block = phase0::BeaconBlock { + slot: state.slot(), + proposer_index, + // Deliberately wrong: the real parent root is + // `state.latest_block_header().hash_tree_root()`. + parent_root: Root::repeat_byte(0xab), + state_root: Root::ZERO, + body: empty_body(), + }; + + assert!( + process_block_header( + &mut state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + ) + .is_err() + ); + } + + #[test] + fn a_slashed_proposer_is_rejected() { + let mut state = crate::beacon::helpers::test_state::with_validators(8); + let proposer_index = get_beacon_proposer_index(&state).unwrap(); + state.validator_mut(proposer_index).unwrap().slashed = true; + + let block = phase0::BeaconBlock { + slot: state.slot(), + proposer_index, + parent_root: state.latest_block_header().hash_tree_root(), + state_root: Root::ZERO, + body: empty_body(), + }; + + assert!( + process_block_header( + &mut state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + ) + .is_err() + ); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/capella.rs b/crates/blockchain/state_transition/src/beacon/stf/capella.rs new file mode 100644 index 000000000..132ee811d --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/capella.rs @@ -0,0 +1,822 @@ +//! Capella's block processing: withdrawals. +//! +//! Before this fork a validator's balance could shrink, through penalties or +//! slashing, but it could never leave the consensus layer: there was nowhere +//! for it to go, since withdrawal credentials named only a BLS public key, +//! which the execution layer has no way to pay out to. Capella gives every +//! validator a way to get its balance out without ever submitting anything: +//! [`process_withdrawals`] sweeps a bounded slice of the validator registry +//! on every single block, pays out anyone it finds fully or partially +//! withdrawable, and [`BeaconState::next_withdrawal_index`] / +//! [`BeaconState::next_withdrawal_validator_index`] (reached here through +//! [`capella::BeaconState`]'s own fields) are the cursor that makes each +//! block's share of that sweep bounded regardless of how large the registry +//! grows. [`get_expected_withdrawals`] is the sweep itself; +//! [`process_bls_to_execution_change`] is the one new operation, a +//! validator's one-time upgrade from a raw BLS withdrawal credential to an +//! execution address, which is what makes it eligible for a payout in the +//! first place. +//! +//! # Why the sweep runs before the operations, not after +//! +//! [`process_block`]'s order, transcribed from the specification's own +//! `process_block`, is header, withdrawals, execution payload, RANDAO, eth1 +//! vote, operations, sync aggregate. `bls_to_execution_changes` is one of the +//! operations, processed by [`process_operations`] near the end of that list, +//! well after [`process_withdrawals`] already ran. That placement is load +//! bearing, not incidental: it means a validator that upgrades its withdrawal +//! credentials in this very block is not swept by this same block, since the +//! sweep already read (and committed to) the old credentials before the +//! upgrade was even processed. The earliest a freshly upgraded validator can +//! be paid out is the next block's sweep. +//! +//! # Execution payload processing +//! +//! Capella's [`process_execution_payload`] is bellatrix's, minus the +//! [`super::bellatrix::is_merge_transition_complete`] check the specification +//! explicitly marks "Removed in Capella": every capella state's transition is +//! already behind it, so the check is redundant rather than differently +//! evaluated. Everything else bellatrix's version does, including +//! [`super::bellatrix::compute_timestamp_at_slot`] for the timestamp check, +//! is reused rather than copied; only the header-building step is written +//! fresh here, since capella's own [`capella::ExecutionPayloadHeader`] adds +//! `withdrawals_root` and is a distinct type from bellatrix's. + +use crate::beacon::bls; +use crate::beacon::config::Config; +use crate::beacon::constants; +use crate::beacon::containers::shared::{ + Deposit, ProposerSlashing, SignedVoluntaryExit, Validator, +}; +use crate::beacon::containers::{BeaconState, capella, phase0}; +use crate::beacon::error::{Error, Result, verify}; +use crate::beacon::hash::hash; +use crate::beacon::helpers::accessors::{get_current_epoch, get_randao_mix}; +use crate::beacon::helpers::capella::{ + is_fully_withdrawable_validator, is_partially_withdrawable_validator, +}; +use crate::beacon::helpers::misc::{compute_domain, compute_signing_root}; +use crate::beacon::helpers::mutators::decrease_balance; +use crate::beacon::preset; +use crate::beacon::primitives::{ExecutionAddress, H256, HashTreeRoot as _}; + +use super::ExecutionEngine; + +// --------------------------------------------------------------------------- +// Block processing +// --------------------------------------------------------------------------- + +/// Capella's block processing: the withdrawal sweep and the execution payload +/// step ahead of everything altair and bellatrix already run, in the +/// specification's own order. +/// +/// See this module's own documentation for why [`process_withdrawals`] runs +/// before [`process_operations`], and so before this same block's own +/// `bls_to_execution_changes` are processed. +pub fn process_block( + state: &mut BeaconState, + block: &capella::BeaconBlock, + config: &Config, + engine: &ExecutionEngine, +) -> Result<()> { + super::block::process_block_header( + state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + )?; + process_withdrawals(state, &block.body.execution_payload)?; + process_execution_payload(state, &block.body.execution_payload, config, engine)?; + super::block::process_randao(state, &block.body.randao_reveal)?; + super::block::process_eth1_data(state, &block.body.eth1_data)?; + process_operations( + state, + &block.body.proposer_slashings, + &block.body.attester_slashings, + &block.body.attestations, + &block.body.deposits, + &block.body.voluntary_exits, + &block.body.bls_to_execution_changes, + config, + )?; + super::altair::process_sync_aggregate(state, &block.body.sync_aggregate)?; + Ok(()) +} + +// --------------------------------------------------------------------------- +// Withdrawals +// --------------------------------------------------------------------------- + +/// The execution address a validator's payout is sent to: the low bytes of +/// its eth1 withdrawal credentials, the same bytes +/// [`process_bls_to_execution_change`] writes when a validator upgrades into +/// this form. +fn withdrawal_address(validator: &Validator) -> ExecutionAddress { + ExecutionAddress::from_slice(&validator.withdrawal_credentials.0[12..]) +} + +/// The withdrawals this block's sweep owes, without applying them. +/// +/// A bounded walk of the validator registry starting at +/// [`capella::BeaconState::next_withdrawal_validator_index`], not a scan of +/// the whole thing: `bound` caps how many validators one call ever visits at +/// [`preset::MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP`], and the loop also stops +/// the moment it has collected [`preset::MAX_WITHDRAWALS_PER_PAYLOAD`] +/// withdrawals, whichever comes first. Both are what keep a single block's +/// share of the sweep bounded regardless of how large the registry grows: +/// without them, a registry of unbounded size would make one block's +/// state-transition cost unbounded too. +/// +/// The index advances past `validator_count` by wrapping with `%`, so the +/// sweep revisits validator zero right after the last one rather than +/// stopping at the end of the registry; [`process_withdrawals`] is what +/// persists the cursor this function starts from and leaves behind. +pub fn get_expected_withdrawals(state: &BeaconState) -> Result> { + let epoch = get_current_epoch(state); + // Through the fork-generic cursor accessor rather than this module's + // projection to `capella::BeaconState`. Deneb reuses this function unchanged + // (its own `process_withdrawals` calls straight into it), and a projection + // to capella's concrete state rejects a deneb state outright, so reading the + // cursor that way made every deneb block carrying a withdrawal fail at + // runtime. + let (mut withdrawal_index, mut validator_index) = state.withdrawal_cursor()?; + + let validator_count = state.validators().len() as u64; + let bound = validator_count.min(preset::MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP); + + let mut withdrawals = Vec::new(); + for _ in 0..bound { + let validator = state.validator(validator_index)?; + let balance = state.balance(validator_index)?; + + if is_fully_withdrawable_validator(validator, balance, epoch) { + withdrawals.push(capella::Withdrawal { + index: withdrawal_index, + validator_index, + address: withdrawal_address(validator), + amount: balance, + }); + withdrawal_index = withdrawal_index + .checked_add(1) + .ok_or(Error::ArithmeticOverflow("withdrawal_index + 1"))?; + } else if is_partially_withdrawable_validator(validator, balance) { + // `is_partially_withdrawable_validator` already requires `balance + // > MAX_EFFECTIVE_BALANCE`, so this cannot underflow; checked + // anyway, since the cost of checking is free and nothing here + // should ever rely on a predicate elsewhere staying exactly this + // strict. + let amount = balance + .checked_sub(preset::MAX_EFFECTIVE_BALANCE) + .ok_or(Error::ArithmeticOverflow("balance - MAX_EFFECTIVE_BALANCE"))?; + withdrawals.push(capella::Withdrawal { + index: withdrawal_index, + validator_index, + address: withdrawal_address(validator), + amount, + }); + withdrawal_index = withdrawal_index + .checked_add(1) + .ok_or(Error::ArithmeticOverflow("withdrawal_index + 1"))?; + } + + // First early stop: a full payload's worth of withdrawals, regardless + // of how much of the sweep bound is left to visit. + if withdrawals.len() == preset::MAX_WITHDRAWALS_PER_PAYLOAD { + break; + } + validator_index = validator_index + .checked_add(1) + .ok_or(Error::ArithmeticOverflow("validator_index + 1"))? + % validator_count; + } + // Second early stop: the loop above never runs more than `bound` + // iterations, so a registry larger than + // `MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP` with nothing withdrawable in this + // round's window returns an empty list here rather than scanning every + // validator in the registry. + + Ok(withdrawals) +} + +/// Applies this block's withdrawal sweep: checks the block's declared +/// `payload.withdrawals` against what the sweep actually owes, pays each one +/// out, and advances the sweep's cursor for next time. +/// +/// The cursor update has two cases, and they diverge in a way that is easy to +/// miss reading only the "happy path": when the sweep filled a whole payload +/// (`expected_withdrawals.len() == MAX_WITHDRAWALS_PER_PAYLOAD`), +/// `next_withdrawal_validator_index` resumes right after the last validator +/// actually paid. Otherwise the sweep ran its entire bound without filling +/// the payload, and the cursor instead advances by the *constant* +/// `MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP`, added to the cursor's value from +/// before this call, not to wherever [`get_expected_withdrawals`]'s loop +/// happened to land. On a registry smaller than that constant, those are +/// different validators: the loop itself only ever visits +/// `min(validator_count, MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP)` indices and +/// wraps `validator_count`-periodically, while this update wraps the larger, +/// unclamped constant, so the next sweep can start from a position the +/// previous one never actually reached. +pub fn process_withdrawals( + state: &mut BeaconState, + payload: &capella::ExecutionPayload, +) -> Result<()> { + let expected_withdrawals = get_expected_withdrawals(state)?; + verify( + payload.withdrawals.to_vec() == expected_withdrawals, + "payload.withdrawals == expected_withdrawals", + )?; + + for withdrawal in &expected_withdrawals { + decrease_balance(state, withdrawal.validator_index, withdrawal.amount)?; + } + + // Update the next withdrawal index if this block contained withdrawals. + if let Some(latest_withdrawal) = expected_withdrawals.last() { + capella_state(state, "process_withdrawals")?.next_withdrawal_index = latest_withdrawal + .index + .checked_add(1) + .ok_or(Error::ArithmeticOverflow("latest_withdrawal.index + 1"))?; + } + + // Update the next validator index to start the next withdrawal sweep. See + // this function's own documentation for why the two branches below do not + // agree on where "next" is once the registry is smaller than + // MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP. + let validator_count = state.validators().len() as u64; + let next_validator_index = if expected_withdrawals.len() == preset::MAX_WITHDRAWALS_PER_PAYLOAD + { + // A full payload: the next sweep resumes right after the last + // validator this block actually paid. + let latest_withdrawal = expected_withdrawals + .last() + .expect("MAX_WITHDRAWALS_PER_PAYLOAD is never zero, so a full payload is non-empty"); + latest_withdrawal + .validator_index + .checked_add(1) + .ok_or(Error::ArithmeticOverflow( + "latest_withdrawal.validator_index + 1", + ))? + % validator_count + } else { + // Not a full payload: advance the sweep by its own maximum length, + // from the cursor as it stood before this call, not from wherever the + // (already-exhausted) sweep loop ended up. + let current_cursor = + capella_state_ref(state, "process_withdrawals")?.next_withdrawal_validator_index; + current_cursor + .checked_add(preset::MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP) + .ok_or(Error::ArithmeticOverflow( + "next_withdrawal_validator_index + MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP", + ))? + % validator_count + }; + capella_state(state, "process_withdrawals")?.next_withdrawal_validator_index = + next_validator_index; + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Execution payload +// --------------------------------------------------------------------------- + +/// Validates this slot's execution payload and caches its header. +/// +/// Bellatrix's [`super::bellatrix::process_execution_payload`] with the +/// `is_merge_transition_complete` check the specification marks "Removed in +/// Capella" dropped, and reusing bellatrix's own +/// [`super::bellatrix::compute_timestamp_at_slot`] for the timestamp check +/// rather than a second copy of it. Takes `config` for the same reason +/// bellatrix's version does: the specification's `compute_time_at_slot` +/// reaches `SECONDS_PER_SLOT` from global scope, but this module keeps that +/// value as [`Config::seconds_per_slot`], a runtime value rather than a +/// preset, so anything that calls through to it needs one. +pub fn process_execution_payload( + state: &mut BeaconState, + payload: &capella::ExecutionPayload, + config: &Config, + engine: &ExecutionEngine, +) -> Result<()> { + verify( + payload.parent_hash + == capella_state_ref(state, "process_execution_payload")? + .latest_execution_payload_header + .block_hash, + "payload.parent_hash == state.latest_execution_payload_header.block_hash", + )?; + verify( + payload.prev_randao == get_randao_mix(state, get_current_epoch(state)), + "payload.prev_randao == get_randao_mix(state, get_current_epoch(state))", + )?; + verify( + payload.timestamp + == super::bellatrix::compute_timestamp_at_slot(state, state.slot(), config), + "payload.timestamp == compute_time_at_slot(state, state.slot)", + )?; + verify( + engine.execution_valid, + "verify_and_notify_new_payload(NewPayloadRequest(execution_payload=payload))", + )?; + + let header = capella::ExecutionPayloadHeader { + parent_hash: payload.parent_hash, + fee_recipient: payload.fee_recipient, + state_root: payload.state_root, + receipts_root: payload.receipts_root, + logs_bloom: payload.logs_bloom.clone(), + prev_randao: payload.prev_randao, + block_number: payload.block_number, + gas_limit: payload.gas_limit, + gas_used: payload.gas_used, + timestamp: payload.timestamp, + extra_data: payload.extra_data.clone(), + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash, + transactions_root: payload.transactions.hash_tree_root(), + // [New in Capella] + withdrawals_root: payload.withdrawals.hash_tree_root(), + }; + capella_state(state, "process_execution_payload")?.latest_execution_payload_header = header; + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Operations +// --------------------------------------------------------------------------- + +/// Runs every operation in a block, in the specification's order: phase0's +/// five lists, unchanged, plus this fork's own `bls_to_execution_changes` +/// appended after them. +/// +/// Delegates the first five lists to [`super::operations::process_operations`] +/// wholesale (deposit-count check included) rather than re-running each +/// per-operation function here: that function already calls the identical +/// functions in the identical order for every fork through deneb, and capella +/// changes none of them, so there is nothing for this to do differently +/// beyond adding the one new loop. +/// +/// Eight parameters, one past clippy's default limit, because this mirrors +/// the specification's own `process_operations(state, body)` unpacked into +/// the fields it reads rather than a whole body; see [`crate::beacon::stf`]'s module +/// documentation for why that unpacking is the point rather than an accident. +#[allow(clippy::too_many_arguments)] +pub fn process_operations( + state: &mut BeaconState, + proposer_slashings: &[ProposerSlashing], + attester_slashings: &[phase0::AttesterSlashing], + attestations: &[phase0::Attestation], + deposits: &[Deposit], + voluntary_exits: &[SignedVoluntaryExit], + bls_to_execution_changes: &[capella::SignedBLSToExecutionChange], + config: &Config, +) -> Result<()> { + super::operations::process_operations( + state, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + config, + )?; + for signed_change in bls_to_execution_changes { + process_bls_to_execution_change(state, signed_change, config)?; + } + Ok(()) +} + +/// Upgrades a validator's withdrawal credentials from a raw BLS public key +/// hash to an execution address, the one operation that makes a validator +/// eligible for [`get_expected_withdrawals`]'s sweep at all. +/// +/// Checked, in order: the credential really is the BLS-prefixed form (an +/// eth1-form credential has nothing left to upgrade), the credential's tail +/// really is the hash of the pubkey the request claims to be upgrading from +/// (proving the request is not renaming someone else's validator), and the +/// signature over the request verifies against that same pubkey. +/// +/// The signature is checked against +/// [`constants::DOMAIN_BLS_TO_EXECUTION_CHANGE`] combined with +/// [`Config::genesis_fork_version`], not the state's current fork version the +/// way [`crate::beacon::helpers::accessors::get_domain`] would compute it. That looks +/// like a bug, since every other signed message in this module signs under +/// whichever fork was active when the message was produced, but the +/// specification calls it out explicitly ("Fork-agnostic domain since address +/// changes are valid across forks") and means it: the validator holding the +/// BLS credential being replaced may not have been online, or even +/// instantiated, since genesis, so pinning the domain to a version that +/// cannot itself be superseded is what keeps this specific signature valid no +/// matter how many later forks have happened by the time it is actually +/// submitted. +pub fn process_bls_to_execution_change( + state: &mut BeaconState, + signed_change: &capella::SignedBLSToExecutionChange, + config: &Config, +) -> Result<()> { + let change = &signed_change.message; + + let validator = state.validator(change.validator_index)?; + verify( + validator.withdrawal_credentials.0[0] == constants::BLS_WITHDRAWAL_PREFIX, + "validator.withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX", + )?; + let hashed_pubkey = hash(&change.from_bls_pubkey.0); + verify( + validator.withdrawal_credentials.0[1..] == hashed_pubkey.0[1..], + "validator.withdrawal_credentials[1:] == hash(address_change.from_bls_pubkey)[1:]", + )?; + + let domain = compute_domain( + constants::DOMAIN_BLS_TO_EXECUTION_CHANGE, + config.genesis_fork_version, + state.genesis_validators_root(), + ); + let signing_root = compute_signing_root(change.hash_tree_root(), domain); + verify( + bls::verify( + &change.from_bls_pubkey, + signing_root, + &signed_change.signature, + ), + "bls.Verify(address_change.from_bls_pubkey, signing_root, signed_address_change.signature)", + )?; + + let mut credentials = [0u8; 32]; + credentials[0] = constants::ETH1_ADDRESS_WITHDRAWAL_PREFIX; + credentials[12..].copy_from_slice(&change.to_execution_address.0); + state + .validator_mut(change.validator_index)? + .withdrawal_credentials = H256(credentials); + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Fork projection +// --------------------------------------------------------------------------- + +/// The capella state, mutably, or an error naming the function that needs +/// one. +/// +/// Scoped to `BeaconState::Capella` alone, not to every later fork that keeps +/// the same withdrawal-cursor fields. Every caller in this file is reached +/// only through [`process_block`], which [`super::block::process_block`] +/// dispatches to precisely when `state` is already `BeaconState::Capella`, so +/// nothing here ever needs to read a deneb, electra, or fulu state. See +/// [`super::bellatrix::bellatrix_state`]'s own documentation for the identical +/// reasoning one fork earlier: each later fork's own block-processing module +/// will need its own projection of this same shape to reach its own +/// `latest_execution_payload_header` (a distinct type per fork from bellatrix +/// on) and its own withdrawal cursor, not this one widened to somehow return +/// a different concrete type per caller. +fn capella_state<'a>( + state: &'a mut BeaconState, + function: &'static str, +) -> Result<&'a mut capella::BeaconState> { + match state { + BeaconState::Capella(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +/// The capella state, immutably. See [`capella_state`]. +fn capella_state_ref<'a>( + state: &'a BeaconState, + function: &'static str, +) -> Result<&'a capella::BeaconState> { + match state { + BeaconState::Capella(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +#[cfg(test)] +mod tests { + use blst::min_pk::SecretKey; + + use super::*; + use crate::beacon::fork::ForkName; + use crate::beacon::primitives::{ + BlsPubkey, BlsSignature, ExecutionBlockHash, Gwei, Root, Uint256, ValidatorIndex, + }; + use libssz_types::SszVector; + + /// A capella state with `count` fully active, full-balance validators, one + /// epoch in (so the block-root history window already has entries). + /// + /// Every validator's pubkey is left at its all-zero default rather than a + /// real curve point: nothing under test here (the withdrawal sweep, its + /// cursor arithmetic, or the BLS-to-execution-change operation) ever + /// verifies a signature against a validator's own `pubkey`, so paying for + /// real key generation on every validator, which matters once a test + /// needs a registry larger than `MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP`, + /// would buy nothing. + /// + /// A thin wrapper around the shared fork-parameterised builder: see + /// [`crate::beacon::helpers::test_state::with_validators_at`] for the construction + /// this and every other fork's test module used to duplicate. + fn capella_state_with_validators(count: usize) -> BeaconState { + crate::beacon::helpers::test_state::with_validators_at(ForkName::Capella, count) + } + + /// Marks validator `index` fully withdrawable: an eth1 credential, a + /// withdrawable epoch already past, and a positive balance. + fn make_fully_withdrawable(state: &mut BeaconState, index: ValidatorIndex, balance: Gwei) { + { + let validator = state.validator_mut(index).unwrap(); + validator.withdrawal_credentials.0[0] = constants::ETH1_ADDRESS_WITHDRAWAL_PREFIX; + validator.withdrawable_epoch = 0; + } + state.balances_mut()[index as usize] = balance; + } + + fn empty_execution_payload() -> capella::ExecutionPayload { + capella::ExecutionPayload { + parent_hash: ExecutionBlockHash::ZERO, + fee_recipient: ExecutionAddress::ZERO, + state_root: Root::ZERO, + receipts_root: Root::ZERO, + logs_bloom: SszVector::try_from(vec![0u8; preset::BYTES_PER_LOGS_BLOOM]) + .expect("built at exactly BYTES_PER_LOGS_BLOOM"), + prev_randao: Root::ZERO, + block_number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: 0, + extra_data: Default::default(), + base_fee_per_gas: Uint256::ZERO, + block_hash: ExecutionBlockHash::ZERO, + transactions: Default::default(), + withdrawals: Default::default(), + } + } + + // ----------------------------------------------------------------------- + // get_expected_withdrawals + // ----------------------------------------------------------------------- + + #[test] + fn the_sweep_wraps_around_past_the_end_of_the_registry() { + let mut state = capella_state_with_validators(3); + for index in 0..3u64 { + make_fully_withdrawable(&mut state, index, preset::MAX_EFFECTIVE_BALANCE); + } + // Starting the cursor at the last validator forces a bound of three + // (or more) to wrap back to index 0 rather than running off the end + // of the registry. + capella_state(&mut state, "test setup") + .unwrap() + .next_withdrawal_validator_index = 2; + + let withdrawals = get_expected_withdrawals(&state).unwrap(); + let visited: Vec = withdrawals.iter().map(|w| w.validator_index).collect(); + assert_eq!( + visited, + vec![2, 0, 1], + "the sweep must wrap through index 0 rather than stop or error at the end" + ); + } + + #[test] + fn the_sweep_stops_once_a_full_payload_is_collected() { + let count = preset::MAX_WITHDRAWALS_PER_PAYLOAD + 5; + let mut state = capella_state_with_validators(count); + for index in 0..count as u64 { + make_fully_withdrawable(&mut state, index, preset::MAX_EFFECTIVE_BALANCE); + } + + let withdrawals = get_expected_withdrawals(&state).unwrap(); + assert_eq!( + withdrawals.len(), + preset::MAX_WITHDRAWALS_PER_PAYLOAD, + "the sweep must stop the moment a full payload is collected, even though \ + every remaining validator in the bound is also withdrawable" + ); + } + + #[test] + fn the_sweep_never_visits_past_its_own_bound() { + // A registry one validator larger than the sweep bound, with only the + // validator just past the bound withdrawable: if the sweep reached + // it, the bound would not be doing anything. Every validator here + // keeps its all-default (non-real) pubkey, which is what makes a + // registry this large cheap to build. + let bound = preset::MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP as usize; + let count = bound + 1; + let mut state = capella_state_with_validators(count); + make_fully_withdrawable( + &mut state, + bound as ValidatorIndex, + preset::MAX_EFFECTIVE_BALANCE, + ); + + let withdrawals = get_expected_withdrawals(&state).unwrap(); + assert!( + withdrawals.is_empty(), + "the sweep must not visit a validator past MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP" + ); + } + + // ----------------------------------------------------------------------- + // process_withdrawals + // ----------------------------------------------------------------------- + + #[test] + fn a_full_payload_resumes_the_cursor_right_after_the_last_withdrawal_paid() { + let count = preset::MAX_WITHDRAWALS_PER_PAYLOAD + 2; + let mut state = capella_state_with_validators(count); + for index in 0..count as u64 { + make_fully_withdrawable(&mut state, index, preset::MAX_EFFECTIVE_BALANCE); + } + + let expected = get_expected_withdrawals(&state).unwrap(); + assert_eq!(expected.len(), preset::MAX_WITHDRAWALS_PER_PAYLOAD); + let last = expected.last().unwrap().clone(); + + let payload = capella::ExecutionPayload { + withdrawals: expected.try_into().unwrap(), + ..empty_execution_payload() + }; + process_withdrawals(&mut state, &payload).unwrap(); + + let inner = capella_state_ref(&state, "test assertion").unwrap(); + assert_eq!(inner.next_withdrawal_index, last.index + 1); + assert_eq!( + inner.next_withdrawal_validator_index, + (last.validator_index + 1) % count as u64 + ); + } + + #[test] + fn a_partial_sweep_advances_the_cursor_by_the_bound_from_before_the_call() { + // Nobody in this registry is withdrawable, so the sweep runs its + // whole bound and returns nothing. The cursor must still move: by + // MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP from wherever it stood before + // this call, not by however many validators the (empty) sweep loop + // actually visited. + let count = 5; + let mut state = capella_state_with_validators(count); + capella_state(&mut state, "test setup") + .unwrap() + .next_withdrawal_validator_index = 2; + + let expected = get_expected_withdrawals(&state).unwrap(); + assert!( + expected.is_empty(), + "nobody in this registry is withdrawable" + ); + + let payload = capella::ExecutionPayload { + withdrawals: Default::default(), + ..empty_execution_payload() + }; + process_withdrawals(&mut state, &payload).unwrap(); + + let inner = capella_state_ref(&state, "test assertion").unwrap(); + let expected_next = (2 + preset::MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP) % count as u64; + assert_eq!(inner.next_withdrawal_validator_index, expected_next); + } + + #[test] + fn a_block_declaring_the_wrong_withdrawals_is_rejected() { + let mut state = capella_state_with_validators(3); + make_fully_withdrawable(&mut state, 0, preset::MAX_EFFECTIVE_BALANCE); + + let payload = capella::ExecutionPayload { + // The sweep owes one withdrawal; declaring none must fail. + withdrawals: Default::default(), + ..empty_execution_payload() + }; + assert!(process_withdrawals(&mut state, &payload).is_err()); + } + + // ----------------------------------------------------------------------- + // process_bls_to_execution_change + // ----------------------------------------------------------------------- + + /// `specs/altair/bls.md`'s BLS proof-of-possession domain separation tag, + /// the same one every other real-signature test in this module signs + /// under. + const DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; + + #[test] + fn a_credential_change_verifies_under_the_genesis_fork_version_not_the_current_one() { + let config = Config::mainnet(); + let mut state = capella_state_with_validators(2); + // A capella state's own fork version is not the genesis one: proves + // the signature is checked against `config.genesis_fork_version` + // specifically, not `state.fork().current_version`, which would also + // be available here and would silently pass a same-fork test without + // proving anything about which version is actually used. + state.fork_mut().current_version = config.capella_fork_version; + state.fork_mut().epoch = config.capella_fork_epoch; + assert_ne!(config.capella_fork_version, config.genesis_fork_version); + + let secret_key = SecretKey::key_gen(&[3u8; 32], &[]).expect("32 bytes of key material"); + let from_pubkey = BlsPubkey(secret_key.sk_to_pk().to_bytes()); + let hashed = hash(&from_pubkey.0); + { + let validator = state.validator_mut(0).unwrap(); + validator.withdrawal_credentials.0[0] = constants::BLS_WITHDRAWAL_PREFIX; + validator.withdrawal_credentials.0[1..].copy_from_slice(&hashed.0[1..]); + } + + let message = capella::BLSToExecutionChange { + validator_index: 0, + from_bls_pubkey: from_pubkey, + to_execution_address: ExecutionAddress::repeat_byte(0xab), + }; + let genesis_domain = compute_domain( + constants::DOMAIN_BLS_TO_EXECUTION_CHANGE, + config.genesis_fork_version, + state.genesis_validators_root(), + ); + let signing_root = compute_signing_root(message.hash_tree_root(), genesis_domain); + let signature = BlsSignature( + secret_key + .sign(signing_root.as_slice(), DST, &[]) + .to_bytes(), + ); + let signed_change = capella::SignedBLSToExecutionChange { message, signature }; + + process_bls_to_execution_change(&mut state, &signed_change, &config).unwrap(); + + let validator = state.validator(0).unwrap(); + assert_eq!( + validator.withdrawal_credentials.0[0], + constants::ETH1_ADDRESS_WITHDRAWAL_PREFIX + ); + assert_eq!( + &validator.withdrawal_credentials.0[12..], + ExecutionAddress::repeat_byte(0xab).as_slice() + ); + } + + #[test] + fn a_signature_made_under_the_current_fork_version_is_rejected() { + let config = Config::mainnet(); + let mut state = capella_state_with_validators(2); + state.fork_mut().current_version = config.capella_fork_version; + state.fork_mut().epoch = config.capella_fork_epoch; + + let secret_key = SecretKey::key_gen(&[4u8; 32], &[]).expect("32 bytes of key material"); + let from_pubkey = BlsPubkey(secret_key.sk_to_pk().to_bytes()); + let hashed = hash(&from_pubkey.0); + { + let validator = state.validator_mut(0).unwrap(); + validator.withdrawal_credentials.0[0] = constants::BLS_WITHDRAWAL_PREFIX; + validator.withdrawal_credentials.0[1..].copy_from_slice(&hashed.0[1..]); + } + + let message = capella::BLSToExecutionChange { + validator_index: 0, + from_bls_pubkey: from_pubkey, + to_execution_address: ExecutionAddress::repeat_byte(0xab), + }; + // Signed under the state's current (capella) fork version, which + // process_bls_to_execution_change must not accept. + let wrong_domain = compute_domain( + constants::DOMAIN_BLS_TO_EXECUTION_CHANGE, + config.capella_fork_version, + state.genesis_validators_root(), + ); + let signing_root = compute_signing_root(message.hash_tree_root(), wrong_domain); + let signature = BlsSignature( + secret_key + .sign(signing_root.as_slice(), DST, &[]) + .to_bytes(), + ); + let signed_change = capella::SignedBLSToExecutionChange { message, signature }; + + assert!(process_bls_to_execution_change(&mut state, &signed_change, &config).is_err()); + } + + #[test] + fn a_credential_not_in_the_bls_form_is_rejected() { + let config = Config::mainnet(); + let mut state = capella_state_with_validators(1); + state.validator_mut(0).unwrap().withdrawal_credentials.0[0] = + constants::ETH1_ADDRESS_WITHDRAWAL_PREFIX; + + let secret_key = SecretKey::key_gen(&[5u8; 32], &[]).expect("32 bytes of key material"); + let message = capella::BLSToExecutionChange { + validator_index: 0, + from_bls_pubkey: BlsPubkey(secret_key.sk_to_pk().to_bytes()), + to_execution_address: ExecutionAddress::repeat_byte(0xab), + }; + let signed_change = capella::SignedBLSToExecutionChange { + message, + signature: BlsSignature::default(), + }; + + assert!(process_bls_to_execution_change(&mut state, &signed_change, &config).is_err()); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/deneb.rs b/crates/blockchain/state_transition/src/beacon/stf/deneb.rs new file mode 100644 index 000000000..f90bbbf35 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/deneb.rs @@ -0,0 +1,734 @@ +//! Deneb-specific block processing. +//! +//! Deneb's headline change is data blobs (EIP-4844): temporary storage for +//! rollup data that the beacon chain commits to but never itself processes. +//! A blob is far larger than everything else a block carries, and consensus +//! never reads its contents, only its existence, so the specification never +//! puts one in the block. Instead a block commits only to a KZG commitment +//! per blob (`blob_kzg_commitments`, appended to `BeaconBlockBody`), and each +//! blob is propagated separately as a [`crate::beacon::containers::deneb::BlobSidecar`] +//! over its own gossip subnet. [`kzg_commitment_to_versioned_hash`] is the +//! bridge between the two worlds: it turns a commitment into the same +//! versioned hash form the execution payload's blob-carrying transactions +//! reference, which is what lets [`process_execution_payload`] check that a +//! block's commitments and its payload's transactions agree on which blobs +//! this block actually depends on, without the beacon chain ever holding a +//! blob itself. +//! +//! Deneb's block itself is capella's `process_block` unchanged in structure +//! (header, withdrawals, execution payload, RANDAO, eth1 vote, operations, +//! sync aggregate); see [`process_block`] for exactly which steps are +//! capella's own and which are this module's. Three of those steps change: +//! [`process_attestation`] widens its inclusion-slot check and its +//! timely-target reward condition for EIP-7045, [`process_execution_payload`] +//! checks the block's blob commitments against the execution engine and +//! caches two new blob-gas fields for EIP-4844, and [`process_voluntary_exit`] +//! signs under a fixed fork version for EIP-7044. + +use crate::beacon::bls; +use crate::beacon::config::Config; +use crate::beacon::constants::{self, FAR_FUTURE_EPOCH}; +use crate::beacon::containers::capella::SignedBLSToExecutionChange; +use crate::beacon::containers::shared::{ + AttestationData, Deposit, ProposerSlashing, SignedVoluntaryExit, +}; +use crate::beacon::containers::{BeaconState, deneb, phase0}; +use crate::beacon::error::{Error, Result, verify}; +use crate::beacon::hash::hash; +use crate::beacon::helpers::accessors::{ + get_beacon_committee, get_beacon_proposer_index, get_block_root, get_block_root_at_slot, + get_committee_count_per_slot, get_current_epoch, get_previous_epoch, get_randao_mix, +}; +use crate::beacon::helpers::altair::{add_flag, get_base_reward, has_flag}; +use crate::beacon::helpers::attestation::{ + get_attesting_indices, get_indexed_attestation, is_valid_indexed_attestation, +}; +use crate::beacon::helpers::math::integer_squareroot; +use crate::beacon::helpers::misc::{compute_domain, compute_epoch_at_slot, compute_signing_root}; +use crate::beacon::helpers::mutators::{ + decrease_balance, increase_balance, initiate_validator_exit, +}; +use crate::beacon::helpers::predicates::is_active_validator; +use crate::beacon::preset; +use crate::beacon::primitives::{ + Bytes32, Gwei, H256, HashTreeRoot as _, KzgCommitment, ParticipationFlags, ValidatorIndex, +}; + +use super::ExecutionEngine; + +// --------------------------------------------------------------------------- +// Block processing +// --------------------------------------------------------------------------- + +/// Deneb's block processing: capella's steps, unchanged in order. +/// +/// The specification never lists a "Modified `process_block`" for deneb: the +/// only per-step notes it adds are to [`process_attestation`], +/// [`process_execution_payload`], and [`process_voluntary_exit`], so this +/// mirrors capella's own driver line for line rather than something this +/// module invents. That is also why this dispatches to [`process_operations`] +/// below rather than to [`super::operations::process_operations`] the way +/// bellatrix and altair do: deneb's own attestation and voluntary-exit rules +/// have to reach the block's operations somewhere, and +/// [`super::operations::process_operations`] has no fork check of its own to +/// hang them on. See [`process_operations`]'s own documentation for why that +/// is a full copy of the loop rather than a smaller patch. +pub fn process_block( + state: &mut BeaconState, + block: &deneb::BeaconBlock, + config: &Config, + engine: &ExecutionEngine, +) -> Result<()> { + super::block::process_block_header( + state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + )?; + process_withdrawals(state, &block.body.execution_payload)?; + process_execution_payload( + state, + &block.body.execution_payload, + &block.body.blob_kzg_commitments, + config, + engine, + )?; + super::block::process_randao(state, &block.body.randao_reveal)?; + super::block::process_eth1_data(state, &block.body.eth1_data)?; + process_operations( + state, + &block.body.proposer_slashings, + &block.body.attester_slashings, + &block.body.attestations, + &block.body.deposits, + &block.body.voluntary_exits, + &block.body.bls_to_execution_changes, + config, + )?; + super::altair::process_sync_aggregate(state, &block.body.sync_aggregate)?; + Ok(()) +} + +/// Runs every operation in a deneb block, in the specification's order. +/// +/// Capella's own body adds exactly one list to phase0's five +/// (`bls_to_execution_changes`), and deneb adds none, so the operations this +/// loops over are identical to capella's. What is not identical is which +/// per-operation function two of those loops call: attestations go to this +/// module's own [`process_attestation`] rather than altair's, and voluntary +/// exits go to this module's own [`process_voluntary_exit`] rather than +/// phase0's, since [`super::operations::process_operations`] (which every +/// earlier fork's driver shares) hard-codes the other two. Rather than teach +/// that shared function a fork check for two operations it does not own the +/// rules for, this copies its loop structure wholesale, the same way the +/// specification itself redefines `process_operations` per fork whenever a +/// body's shape or a called function changes; see this module's own +/// documentation for the alternative (a fork check inside the shared +/// function) and why it was not the one picked. +/// +/// The deposit count check is copied unchanged from +/// [`super::operations::process_operations`]: nothing about deposits changed +/// between phase0 and deneb. +/// +/// Six lists, one per parameter, is one past clippy's default limit; capella's +/// own `process_operations` carries the identical six and the identical +/// allowance, since a block's operations really do not compress into fewer +/// arguments without inventing a body type this module deliberately does not +/// have (see [`crate::beacon::stf`]'s module documentation). +#[allow(clippy::too_many_arguments)] +fn process_operations( + state: &mut BeaconState, + proposer_slashings: &[ProposerSlashing], + attester_slashings: &[phase0::AttesterSlashing], + attestations: &[phase0::Attestation], + deposits: &[Deposit], + voluntary_exits: &[SignedVoluntaryExit], + bls_to_execution_changes: &[SignedBLSToExecutionChange], + config: &Config, +) -> Result<()> { + let outstanding = state + .eth1_data() + .deposit_count + .checked_sub(state.eth1_deposit_index()) + .ok_or(Error::ArithmeticOverflow( + "eth1_data.deposit_count - eth1_deposit_index", + ))?; + verify( + deposits.len() as u64 == outstanding.min(preset::MAX_DEPOSITS as u64), + "len(body.deposits) == min(MAX_DEPOSITS, eth1_data.deposit_count - eth1_deposit_index)", + )?; + + for proposer_slashing in proposer_slashings { + super::operations::process_proposer_slashing(state, proposer_slashing, config)?; + } + for attester_slashing in attester_slashings { + super::operations::process_attester_slashing(state, attester_slashing, config)?; + } + for attestation in attestations { + process_attestation(state, attestation)?; + } + for deposit in deposits { + super::operations::process_deposit(state, deposit, config)?; + } + for voluntary_exit in voluntary_exits { + process_voluntary_exit(state, voluntary_exit, config)?; + } + for signed_change in bls_to_execution_changes { + super::capella::process_bls_to_execution_change(state, signed_change, config)?; + } + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Withdrawals +// --------------------------------------------------------------------------- + +/// Applies this slot's withdrawal sweep against a deneb execution payload. +/// +/// [`super::capella::get_expected_withdrawals`] is reused unchanged: it +/// depends only on `state`, not on any payload type, since which validators +/// are due a withdrawal has nothing to do with which fork's execution payload +/// carries the result. This function itself cannot be capella's own, despite +/// applying an identical rule, because `payload.withdrawals` has to be +/// compared against a `payload` typed [`deneb::ExecutionPayload`], and that +/// is a different Rust type from `capella::ExecutionPayload` even though +/// both alias the same [`crate::beacon::containers::capella::Withdrawal`] element +/// type for the list itself. +/// +/// Public, like capella's and electra's counterparts, because the `operations` +/// fixture suite drives each fork's withdrawal step directly rather than through +/// `process_block`. +pub fn process_withdrawals( + state: &mut BeaconState, + payload: &deneb::ExecutionPayload, +) -> Result<()> { + let expected_withdrawals = super::capella::get_expected_withdrawals(state)?; + verify( + payload.withdrawals.to_vec() == expected_withdrawals, + "payload.withdrawals == expected_withdrawals", + )?; + + for withdrawal in &expected_withdrawals { + decrease_balance(state, withdrawal.validator_index, withdrawal.amount)?; + } + + if let Some(latest_withdrawal) = expected_withdrawals.last() { + deneb_state(state, "process_withdrawals")?.next_withdrawal_index = latest_withdrawal + .index + .checked_add(1) + .ok_or(Error::ArithmeticOverflow("latest_withdrawal.index + 1"))?; + } + + let validator_count = state.validators().len() as ValidatorIndex; + let next_validator_index = if expected_withdrawals.len() == preset::MAX_WITHDRAWALS_PER_PAYLOAD + { + let latest_withdrawal = expected_withdrawals + .last() + .expect("MAX_WITHDRAWALS_PER_PAYLOAD is never zero, so a full payload is non-empty"); + latest_withdrawal + .validator_index + .checked_add(1) + .ok_or(Error::ArithmeticOverflow( + "latest_withdrawal.validator_index + 1", + ))? + % validator_count + } else { + let current_cursor = + deneb_state_ref(state, "process_withdrawals")?.next_withdrawal_validator_index; + current_cursor + .checked_add(preset::MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP) + .ok_or(Error::ArithmeticOverflow( + "next_withdrawal_validator_index + MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP", + ))? + % validator_count + }; + deneb_state(state, "process_withdrawals")?.next_withdrawal_validator_index = + next_validator_index; + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Attestations +// --------------------------------------------------------------------------- + +/// Scores an attestation and pays its including proposer, widening altair's +/// rule for EIP-7045. +/// +/// Shares its validation prologue with +/// [`crate::beacon::helpers::altair::get_attestation_participation_flag_indices`]'s +/// caller in altair (target epoch, committee shape, signature), with one +/// prologue check dropped: altair also demands `state.slot <= data.slot + +/// SLOTS_PER_EPOCH`, an upper bound on how late an attestation may still be +/// included. FFG justification itself has no such bound; a source vote +/// either extends the justified chain or it does not, however late it +/// lands. Deneb drops the bound to match, and widens +/// [`attestation_participation_flag_indices`] the same way: the timely-target +/// flag no longer checks `inclusion_delay` at all, so a late-but-correct +/// target vote is not paid for its correctness one moment and then refused +/// the reward for the exact same vote the moment altair's old window closed. +/// +/// Structured as the same two-phase read-then-write split altair's version +/// uses, and for the identical reason: deciding which flags this attestation +/// newly grants only ever reads `state`, while flipping them needs `&mut +/// state`, and the two cannot interleave in one pass without conflicting +/// borrows (see altair's `process_attestation` for the borrow-checker +/// argument in full). +pub fn process_attestation( + state: &mut BeaconState, + attestation: &phase0::Attestation, +) -> Result<()> { + let data = attestation.data; + let current_epoch = get_current_epoch(state); + let previous_epoch = get_previous_epoch(state); + + verify( + data.target.epoch == previous_epoch || data.target.epoch == current_epoch, + "data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))", + )?; + verify( + data.target.epoch == compute_epoch_at_slot(data.slot), + "data.target.epoch == compute_epoch_at_slot(data.slot)", + )?; + + // [EIP-7045]: no upper bound on `state.slot` here, unlike altair; see this + // function's own documentation for why. `data.slot` still comes straight + // off the wire, so the lower bound's own addition is still checked. + let min_slot = data + .slot + .checked_add(preset::MIN_ATTESTATION_INCLUSION_DELAY) + .ok_or(Error::ArithmeticOverflow( + "data.slot + MIN_ATTESTATION_INCLUSION_DELAY", + ))?; + verify( + min_slot <= state.slot(), + "data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot", + )?; + verify( + data.index < get_committee_count_per_slot(state, data.target.epoch), + "data.index < get_committee_count_per_slot(state, data.target.epoch)", + )?; + + let committee = get_beacon_committee(state, data.slot, data.index)?; + verify( + attestation.aggregation_bits.len() == committee.len(), + "len(attestation.aggregation_bits) == len(committee)", + )?; + + // Safe: `min_slot <= state.slot()` above and `min_slot >= data.slot` (the + // inclusion delay is non-negative), so `data.slot <= state.slot()`. + let inclusion_delay = state.slot() - data.slot; + let participation_flag_indices = + attestation_participation_flag_indices(state, &data, inclusion_delay)?; + + let indexed_attestation = get_indexed_attestation(state, attestation)?; + verify( + is_valid_indexed_attestation(state, &indexed_attestation), + "is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))", + )?; + + // Read phase: for every attester, decide which flags this attestation + // newly satisfies and add up the proposer's reward for granting them. + let attesting_indices = get_attesting_indices(state, attestation)?; + let current_epoch_target = data.target.epoch == current_epoch; + // Through the fork-generic accessor, not a projection to a concrete + // `altair::BeaconState`. The participation lists are unchanged from altair + // through fulu, so a projection matching only `BeaconState::Altair` rejects + // every deneb state, which is the only kind this function is ever called + // with: it made deneb's attestation processing fail outright. + let (previous_participation, current_participation, _) = state.altair_validator_lists()?; + let epoch_participation = if current_epoch_target { + current_participation + } else { + previous_participation + }; + + let mut proposer_reward_numerator: Gwei = 0; + let mut updates: Vec<(ValidatorIndex, ParticipationFlags)> = Vec::new(); + for index in attesting_indices { + let current_flags = + epoch_participation + .get(index as usize) + .copied() + .ok_or(Error::IndexOutOfBounds { + index: index as usize, + len: epoch_participation.len(), + })?; + + let mut new_flags: ParticipationFlags = 0; + for &flag_index in &participation_flag_indices { + if has_flag(current_flags, flag_index) { + continue; + } + new_flags = add_flag(new_flags, flag_index); + let weight = constants::PARTICIPATION_FLAG_WEIGHTS[flag_index]; + let reward = get_base_reward(state, index)?.checked_mul(weight).ok_or( + Error::ArithmeticOverflow("get_base_reward(state, index) * weight"), + )?; + proposer_reward_numerator = proposer_reward_numerator + .checked_add(reward) + .ok_or(Error::ArithmeticOverflow("proposer_reward_numerator"))?; + } + if new_flags != 0 { + updates.push((index, new_flags)); + } + } + + // Write phase: apply exactly the flags the read phase decided on. + let (previous_participation, current_participation, _) = state.altair_validator_lists_mut()?; + let epoch_participation = if current_epoch_target { + current_participation + } else { + previous_participation + }; + let epoch_participation_len = epoch_participation.len(); + for (index, new_flags) in updates { + let flags = epoch_participation + .get_mut(index as usize) + .ok_or(Error::IndexOutOfBounds { + index: index as usize, + len: epoch_participation_len, + })?; + *flags |= new_flags; + } + + const NON_PROPOSER_WEIGHT: u64 = constants::WEIGHT_DENOMINATOR - constants::PROPOSER_WEIGHT; + const PROPOSER_REWARD_DENOMINATOR: u64 = + NON_PROPOSER_WEIGHT * constants::WEIGHT_DENOMINATOR / constants::PROPOSER_WEIGHT; + let proposer_reward = proposer_reward_numerator / PROPOSER_REWARD_DENOMINATOR; + let proposer_index = get_beacon_proposer_index(state)?; + increase_balance(state, proposer_index, proposer_reward)?; + + Ok(()) +} + +/// Which of the three participation flags an attestation with `data`, +/// included after `inclusion_delay` slots, satisfies. +/// +/// Deneb's version of +/// [`crate::beacon::helpers::altair::get_attestation_participation_flag_indices`]: +/// EIP-7045 grants the timely-target flag to every correctly-targeted +/// attestation regardless of `inclusion_delay`, rather than only within +/// altair's one-epoch reward window. The source and head conditions are +/// altair's, unchanged. See [`process_attestation`]'s own documentation for +/// why the two forks diverge here at all. +fn attestation_participation_flag_indices( + state: &BeaconState, + data: &AttestationData, + inclusion_delay: u64, +) -> Result> { + let justified_checkpoint = if data.target.epoch == get_current_epoch(state) { + state.current_justified_checkpoint() + } else { + state.previous_justified_checkpoint() + }; + let is_matching_source = data.source == justified_checkpoint; + + let target_root = get_block_root(state, data.target.epoch)?; + let target_root_matches = data.target.root == target_root; + let is_matching_target = is_matching_source && target_root_matches; + + let head_root = get_block_root_at_slot(state, data.slot)?; + let head_root_matches = data.beacon_block_root == head_root; + let is_matching_head = is_matching_target && head_root_matches; + + verify(is_matching_source, "is_matching_source")?; + + let mut participation_flag_indices = Vec::new(); + if is_matching_source && inclusion_delay <= integer_squareroot(preset::SLOTS_PER_EPOCH) { + participation_flag_indices.push(constants::TIMELY_SOURCE_FLAG_INDEX); + } + // [EIP-7045]: no `inclusion_delay` bound, unlike altair's + // `inclusion_delay <= SLOTS_PER_EPOCH`. + if is_matching_target { + participation_flag_indices.push(constants::TIMELY_TARGET_FLAG_INDEX); + } + if is_matching_head && inclusion_delay == preset::MIN_ATTESTATION_INCLUSION_DELAY { + participation_flag_indices.push(constants::TIMELY_HEAD_FLAG_INDEX); + } + + Ok(participation_flag_indices) +} + +// --------------------------------------------------------------------------- +// Execution payload +// --------------------------------------------------------------------------- + +/// Validates this slot's execution payload and its blob commitments, then +/// caches the payload's header alongside deneb's two new blob-gas fields. +/// +/// Takes `config`, which the specification's own three-argument +/// `process_execution_payload(state, body, execution_engine)` does not: +/// [`super::bellatrix::compute_timestamp_at_slot`] needs one, for the same +/// reason bellatrix's own version of this function does, and this module +/// systematically hands every function needing a configuration value one +/// explicitly rather than reaching for a global. +/// +/// Also takes `blob_kzg_commitments` on its own, separate from `payload`, +/// rather than a whole body, matching how every shared step in +/// [`super::block`] takes only the fields it reads (see [`crate::beacon::stf`]'s +/// module documentation for why no shared body type exists to pass instead): +/// the commitments live on the block body, not the payload, and this is the +/// one step that needs them, since [`kzg_commitment_to_versioned_hash`] turns +/// each into the same versioned-hash form a blob-carrying transaction inside +/// `payload.transactions` commits to, which is exactly what the +/// specification's `NewPayloadRequest.versioned_hashes` reconciles against +/// `is_valid_versioned_hashes`. +/// +/// That reconciliation itself is not checked here, for the same reason +/// [`super::bellatrix::process_execution_payload`] cannot check +/// `payload.block_hash` against a transaction's own contents either: this +/// crate's `Transaction` is opaque bytes, never decoded, so nothing here can +/// extract a transaction's claimed versioned hashes to compare. It collapses, +/// like the rest of `verify_and_notify_new_payload`, into +/// [`ExecutionEngine::execution_valid`]; the versioned hashes are still +/// computed unconditionally, both so [`kzg_commitment_to_versioned_hash`] is +/// exercised the way the specification's own data flow exercises it, and so a +/// future engine model with something real to check against has the value +/// ready to hand it. +/// +/// What this function can and does check on its own, without any engine at +/// all, is the commitment count: [`Config::max_blobs_per_block_deneb`] is +/// this fork's fixed cap, configuration rather than a preset because +/// electra raises it and fulu's blob schedule (EIP-7892) can raise it again +/// without a further hard fork; see [`Config::max_blobs_per_block`]'s own +/// documentation for why deneb reads the fixed field directly instead of +/// going through that schedule-aware lookup. +/// +/// No `is_merge_transition_complete` check, unlike bellatrix's version: +/// capella's specification already removes it on the grounds that a chain +/// still pre-merge by capella cannot exist, and deneb inherits that removal +/// unchanged. +pub fn process_execution_payload( + state: &mut BeaconState, + payload: &deneb::ExecutionPayload, + blob_kzg_commitments: &[KzgCommitment], + config: &Config, + engine: &ExecutionEngine, +) -> Result<()> { + let deneb_ref = deneb_state_ref(state, "process_execution_payload")?; + verify( + payload.parent_hash == deneb_ref.latest_execution_payload_header.block_hash, + "payload.parent_hash == state.latest_execution_payload_header.block_hash", + )?; + verify( + payload.prev_randao == get_randao_mix(state, get_current_epoch(state)), + "payload.prev_randao == get_randao_mix(state, get_current_epoch(state))", + )?; + verify( + payload.timestamp + == super::bellatrix::compute_timestamp_at_slot(state, state.slot(), config), + "payload.timestamp == compute_time_at_slot(state, state.slot)", + )?; + verify( + blob_kzg_commitments.len() as u64 <= config.max_blobs_per_block_deneb, + "len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK", + )?; + + // See this function's own documentation for why this is computed but not + // itself checked against anything. + let _versioned_hashes: Vec = blob_kzg_commitments + .iter() + .map(kzg_commitment_to_versioned_hash) + .collect(); + + verify( + engine.execution_valid, + "verify_and_notify_new_payload(NewPayloadRequest(execution_payload=payload, \ + versioned_hashes=versioned_hashes, \ + parent_beacon_block_root=state.latest_block_header.parent_root))", + )?; + + let header = deneb::ExecutionPayloadHeader { + parent_hash: payload.parent_hash, + fee_recipient: payload.fee_recipient, + state_root: payload.state_root, + receipts_root: payload.receipts_root, + logs_bloom: payload.logs_bloom.clone(), + prev_randao: payload.prev_randao, + block_number: payload.block_number, + gas_limit: payload.gas_limit, + gas_used: payload.gas_used, + timestamp: payload.timestamp, + extra_data: payload.extra_data.clone(), + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash, + // The header substitutes a root for each bulky list; see + // `super::bellatrix`'s own documentation for why the state keeps only + // that much. + transactions_root: payload.transactions.hash_tree_root(), + withdrawals_root: payload.withdrawals.hash_tree_root(), + blob_gas_used: payload.blob_gas_used, + excess_blob_gas: payload.excess_blob_gas, + }; + deneb_state(state, "process_execution_payload")?.latest_execution_payload_header = header; + + Ok(()) +} + +/// A blob's versioned hash: the form its KZG commitment takes wherever a +/// blob-carrying transaction references it, so [`process_execution_payload`] +/// can reconcile the two without decoding a transaction itself. +/// +/// Not a bare hash of the commitment: overwriting the hash's own first byte +/// with [`constants::VERSIONED_HASH_VERSION_KZG`] is what lets the execution +/// layer's transaction format tell a KZG-backed versioned hash apart from a +/// different kind of hash-derived identifier it might introduce later under a +/// different version byte, without either layer needing to know which +/// commitment scheme produced any given one. +pub fn kzg_commitment_to_versioned_hash(commitment: &KzgCommitment) -> Bytes32 { + let digest = hash(&commitment.0); + let mut versioned_hash = digest.0; + versioned_hash[0] = constants::VERSIONED_HASH_VERSION_KZG; + H256(versioned_hash) +} + +// --------------------------------------------------------------------------- +// Voluntary exits +// --------------------------------------------------------------------------- + +/// Starts a validator's voluntary exit, signed under a fixed fork version for +/// EIP-7044. +/// +/// Every check but the last is phase0's, unchanged: still active, not already +/// exiting, past its own requested epoch, and past `SHARD_COMMITTEE_PERIOD` +/// since activation. What changes is the domain the signature is checked +/// against. Every other signed message in this module calls +/// [`crate::beacon::helpers::accessors::get_domain`], which signs under whichever +/// fork version is active at the message's own epoch, so the same message +/// signed just before and just after a fork boundary produces two different, +/// mutually invalid signatures. A voluntary exit is deliberately signed far +/// in advance of the epoch it takes effect at (a validator may queue its exit +/// long before it is eligible to leave), so binding it to "whichever fork is +/// current" means a signature made under, say, capella would stop verifying +/// the moment the chain forked into deneb, silently expiring a validator's +/// already-signed intent to leave through no fault of its own. Fixing the +/// domain to [`Config::capella_fork_version`] instead, forever, regardless of +/// which fork actually processes the exit, is what makes a signed exit +/// perpetually valid: the same signature verifies whether it is processed the +/// moment it is signed or years and several forks later. +/// +/// `CAPELLA_FORK_VERSION` specifically, not deneb's own, because EIP-7044 +/// shipped at deneb but pins the version one fork earlier: capella is the +/// latest fork every already-signed exit on a live network could have been +/// signed under, so pinning there (rather than to deneb's own version, which +/// no exit signed before deneb activated could have used) is what keeps +/// every exit signed before this rule existed valid under it too. +pub fn process_voluntary_exit( + state: &mut BeaconState, + signed_voluntary_exit: &SignedVoluntaryExit, + config: &Config, +) -> Result<()> { + let voluntary_exit = signed_voluntary_exit.message; + let current_epoch = get_current_epoch(state); + let validator = state.validator(voluntary_exit.validator_index)?; + + verify( + is_active_validator(validator, current_epoch), + "is_active_validator(validator, get_current_epoch(state))", + )?; + verify( + validator.exit_epoch == FAR_FUTURE_EPOCH, + "validator.exit_epoch == FAR_FUTURE_EPOCH", + )?; + verify( + current_epoch >= voluntary_exit.epoch, + "get_current_epoch(state) >= voluntary_exit.epoch", + )?; + let eligible_epoch = validator + .activation_epoch + .checked_add(config.shard_committee_period) + .ok_or(Error::ArithmeticOverflow( + "validator.activation_epoch + SHARD_COMMITTEE_PERIOD", + ))?; + verify( + current_epoch >= eligible_epoch, + "get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD", + )?; + + // [EIP-7044]: a fixed fork version rather than `get_domain`'s + // current-epoch lookup; see this function's own documentation for why. + let domain = compute_domain( + constants::DOMAIN_VOLUNTARY_EXIT, + config.capella_fork_version, + state.genesis_validators_root(), + ); + let signing_root = compute_signing_root(voluntary_exit.hash_tree_root(), domain); + verify( + bls::verify( + &validator.pubkey, + signing_root, + &signed_voluntary_exit.signature, + ), + "bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)", + )?; + + initiate_validator_exit(state, voluntary_exit.validator_index, config)?; + Ok(()) +} + +// --------------------------------------------------------------------------- +// Fork projection +// --------------------------------------------------------------------------- + +/// The deneb state, mutably, or an error naming the function that needs one. +/// +/// Scoped to `BeaconState::Deneb` alone, the same deliberately narrow scope +/// [`super::bellatrix::bellatrix_state`] documents for itself: every caller +/// here is reached only through [`process_block`], which +/// [`super::block::process_block`] dispatches to precisely when `state` is +/// already `BeaconState::Deneb`. +fn deneb_state<'a>( + state: &'a mut BeaconState, + function: &'static str, +) -> Result<&'a mut deneb::BeaconState> { + match state { + BeaconState::Deneb(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +/// The deneb state, immutably. See [`deneb_state`]. +fn deneb_state_ref<'a>( + state: &'a BeaconState, + function: &'static str, +) -> Result<&'a deneb::BeaconState> { + match state { + BeaconState::Deneb(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn kzg_commitment_to_versioned_hash_overwrites_only_the_first_byte() { + let commitment = KzgCommitment([7; 48]); + let digest = hash(&commitment.0); + + let versioned_hash = kzg_commitment_to_versioned_hash(&commitment); + + assert_eq!(versioned_hash.0[0], constants::VERSIONED_HASH_VERSION_KZG); + assert_eq!(&versioned_hash.0[1..], &digest.0[1..]); + } + + #[test] + fn kzg_commitment_to_versioned_hash_is_sensitive_to_the_whole_commitment() { + let a = KzgCommitment([1; 48]); + let b = KzgCommitment([2; 48]); + assert_ne!( + kzg_commitment_to_versioned_hash(&a), + kzg_commitment_to_versioned_hash(&b) + ); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/electra.rs b/crates/blockchain/state_transition/src/beacon/stf/electra.rs new file mode 100644 index 000000000..8ab3574a9 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/electra.rs @@ -0,0 +1,2185 @@ +//! Electra's block processing. +//! +//! Two changes, both from EIP-7251 and its neighbours, drive nearly +//! everything below. +//! +//! **A validator's effective balance is no longer pinned to one value.** +//! Through deneb, every validator's ceiling was the same fixed +//! `MAX_EFFECTIVE_BALANCE`, so rate-limiting how many validators could enter +//! or leave the registry in one epoch also rate-limited how much stake moved. +//! Once a validator can hold up to [`preset::MAX_EFFECTIVE_BALANCE_ELECTRA`] +//! by upgrading to a compounding withdrawal credential, a headcount no longer +//! bounds a balance: one large validator's deposit, exit, or consolidation +//! could move as much stake in a single slot as thousands of ordinary ones +//! used to, together. So deposits, exits, and consolidations all move from +//! "applied immediately, rate-limited by counting validators" to "queued in +//! the state (`pending_deposits`, `pending_partial_withdrawals`, +//! `pending_consolidations`) and drained a bounded *balance* at a time" (the +//! draining itself is epoch processing, `crates/blockchain/state_transition/src/beacon/stf/epoch/electra.rs`, +//! not this file; this file only ever appends to those queues or reads them). +//! [`crate::beacon::helpers::electra`] carries the balance-churn accounting this +//! forces; see its own module doc for the full account. +//! +//! **The execution layer can request a deposit, withdrawal, or consolidation +//! directly.** EIP-6110, EIP-7002, and EIP-7251 let the execution layer +//! append a [`electra::DepositRequest`], [`electra::WithdrawalRequest`], or +//! [`electra::ConsolidationRequest`] to its block, bundled into +//! [`electra::ExecutionRequests`] and carried on +//! [`electra::BeaconBlockBody::execution_requests`]. Consensus cannot reject +//! a whole block over a request the execution layer itself already committed +//! to accepting (unlike every other operation here, which a proposer chose +//! to include and so can be held to a strict standard), so +//! [`process_withdrawal_request`] and [`process_consolidation_request`] both +//! validate by *silently doing nothing* on most invalid input rather than by +//! rejecting the block; see their own documentation for exactly which +//! conditions do which. +//! +//! EIP-7549 (committee-indexed attestations) and EIP-7691 (more blobs) are +//! the other two forces at work, each touching one area: attestations now +//! read their covered committees from [`electra::Attestation::committee_bits`] +//! rather than a single `data.index` (see [`process_attestation`]), and the +//! blob commitment limit becomes a network configuration value +//! ([`Config::max_blobs_per_block_electra`]) rather than deneb's fixed preset +//! (see [`process_execution_payload`]). + +use std::collections::HashSet; + +use crate::beacon::bls; +use crate::beacon::config::Config; +use crate::beacon::constants::{self, FAR_FUTURE_EPOCH}; +use crate::beacon::containers::shared::{ + AttestationData, Deposit, DepositMessage, EpochParticipation, InactivityScores, + SignedVoluntaryExit, Validator, +}; +use crate::beacon::containers::{BeaconState, capella, deneb, electra, fulu}; +use crate::beacon::error::{Error, Result, verify}; +use crate::beacon::helpers::accessors::{ + get_beacon_committee, get_beacon_proposer_index, get_block_root, get_block_root_at_slot, + get_committee_count_per_slot, get_current_epoch, get_previous_epoch, get_randao_mix, +}; +use crate::beacon::helpers::altair::{add_flag, get_base_reward, has_flag}; +use crate::beacon::helpers::electra::{ + compute_exit_epoch_and_update_churn, electra_state, get_attesting_indices, + get_committee_indices, get_consolidation_churn_limit, get_indexed_attestation, + get_max_effective_balance, get_pending_balance_to_withdraw, + has_compounding_withdrawal_credential, has_eth1_withdrawal_credential, + has_execution_withdrawal_credential, + initiate_validator_exit as electra_initiate_validator_exit, is_fully_withdrawable_validator, + is_partially_withdrawable_validator, is_valid_indexed_attestation, +}; +use crate::beacon::helpers::math::integer_squareroot; +use crate::beacon::helpers::misc::{ + compute_deposit_domain, compute_domain, compute_epoch_at_slot, compute_signing_root, + is_valid_merkle_branch, +}; +use crate::beacon::helpers::mutators::{decrease_balance, increase_balance, slash_validator}; +use crate::beacon::helpers::predicates::{ + is_active_validator, is_slashable_attestation_data, is_slashable_validator, +}; +use crate::beacon::preset; +use crate::beacon::primitives::{ + BlsPubkey, BlsSignature, Bytes32, ExecutionAddress, Gwei, HashTreeRoot as _, + ParticipationFlags, ValidatorIndex, WithdrawalIndex, +}; + +use super::ExecutionEngine; + +// --------------------------------------------------------------------------- +// Local state projection +// --------------------------------------------------------------------------- +// +// `crate::beacon::helpers::electra::{electra_state, electra_state_ref}` already +// project a `BeaconState` down to electra's (or fulu's) concrete struct, but +// only far enough to reach the balance-churn fields their own module needs +// (`pending_deposits` and the four churn cursors; see that module's doc). This +// file's block-processing steps also need `latest_execution_payload_header`, +// the withdrawal-sweep cursor (`next_withdrawal_index`, +// `next_withdrawal_validator_index`), `pending_partial_withdrawals` and +// `pending_consolidations` mutably, `deposit_requests_start_index`, and +// (introduced at altair, not electra) `previous_epoch_participation`, +// `current_epoch_participation`, and `inactivity_scores`. None of those are +// fork-invariant (`crate::beacon::containers::mod`'s `shared_state_accessors!` macro +// does not cover any of them), and reaching them would mean adding methods to +// `helpers::electra`'s projection, which is outside this file's ownership. +// This is a second, narrower projection kept local to this module instead, +// for exactly the fields block processing (as opposed to balance-churn +// accounting) needs. +// +// Scoped to `BeaconState::Electra` *and* `BeaconState::Fulu`, the same way +// `helpers::electra`'s own projection is, rather than to `Electra` alone the +// way `crate::beacon::stf::{bellatrix,capella,deneb}`'s own per-fork projections are +// scoped to exactly one variant. Those files are narrower because nothing +// outside them ever calls back into their own fork's state: bellatrix's +// projection is reached only through bellatrix's own `process_block`, which +// only ever runs against a `BeaconState::Bellatrix`. Fulu is different: +// nothing in its own specification touches any of the fields this projection +// reaches (its own changes are `proposer_lookahead` and the blob schedule), +// so whoever writes `crate::beacon::stf::fulu` is expected to reuse this file's +// functions wholesale, on a `BeaconState::Fulu`, the identical reasoning +// `crate::beacon::helpers::electra`'s own module doc gives for widening its +// projection the same way. +struct BlockRef<'a> { + inner: BlockRefInner<'a>, +} + +enum BlockRefInner<'a> { + Electra(&'a electra::BeaconState), + Fulu(&'a fulu::BeaconState), +} + +impl<'a> BlockRef<'a> { + fn latest_execution_payload_header(&self) -> &'a deneb::ExecutionPayloadHeader { + match self.inner { + BlockRefInner::Electra(state) => &state.latest_execution_payload_header, + BlockRefInner::Fulu(state) => &state.latest_execution_payload_header, + } + } + + fn next_withdrawal_index(&self) -> WithdrawalIndex { + match self.inner { + BlockRefInner::Electra(state) => state.next_withdrawal_index, + BlockRefInner::Fulu(state) => state.next_withdrawal_index, + } + } + + fn next_withdrawal_validator_index(&self) -> ValidatorIndex { + match self.inner { + BlockRefInner::Electra(state) => state.next_withdrawal_validator_index, + BlockRefInner::Fulu(state) => state.next_withdrawal_validator_index, + } + } + + fn deposit_requests_start_index(&self) -> u64 { + match self.inner { + BlockRefInner::Electra(state) => state.deposit_requests_start_index, + BlockRefInner::Fulu(state) => state.deposit_requests_start_index, + } + } +} + +/// The electra-or-fulu state, immutably, projected far enough for this +/// module's own steps. See this section's own documentation. +fn block_ref<'a>(state: &'a BeaconState, function: &'static str) -> Result> { + match state { + BeaconState::Electra(inner) => Ok(BlockRef { + inner: BlockRefInner::Electra(inner), + }), + BeaconState::Fulu(inner) => Ok(BlockRef { + inner: BlockRefInner::Fulu(inner), + }), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +enum BlockMut<'a> { + Electra(&'a mut electra::BeaconState), + Fulu(&'a mut fulu::BeaconState), +} + +impl<'a> BlockMut<'a> { + fn latest_execution_payload_header_mut(&mut self) -> &mut deneb::ExecutionPayloadHeader { + match self { + BlockMut::Electra(state) => &mut state.latest_execution_payload_header, + BlockMut::Fulu(state) => &mut state.latest_execution_payload_header, + } + } + + fn next_withdrawal_index_mut(&mut self) -> &mut WithdrawalIndex { + match self { + BlockMut::Electra(state) => &mut state.next_withdrawal_index, + BlockMut::Fulu(state) => &mut state.next_withdrawal_index, + } + } + + fn next_withdrawal_validator_index_mut(&mut self) -> &mut ValidatorIndex { + match self { + BlockMut::Electra(state) => &mut state.next_withdrawal_validator_index, + BlockMut::Fulu(state) => &mut state.next_withdrawal_validator_index, + } + } + + fn pending_partial_withdrawals_mut(&mut self) -> &mut electra::PendingPartialWithdrawals { + match self { + BlockMut::Electra(state) => &mut state.pending_partial_withdrawals, + BlockMut::Fulu(state) => &mut state.pending_partial_withdrawals, + } + } + + fn pending_consolidations_mut(&mut self) -> &mut electra::PendingConsolidations { + match self { + BlockMut::Electra(state) => &mut state.pending_consolidations, + BlockMut::Fulu(state) => &mut state.pending_consolidations, + } + } + + fn deposit_requests_start_index_mut(&mut self) -> &mut u64 { + match self { + BlockMut::Electra(state) => &mut state.deposit_requests_start_index, + BlockMut::Fulu(state) => &mut state.deposit_requests_start_index, + } + } + + /// `previous_epoch_participation` or `current_epoch_participation`, + /// whichever `current` selects. + fn epoch_participation_mut(&mut self, current: bool) -> &mut EpochParticipation { + match (self, current) { + (BlockMut::Electra(state), true) => &mut state.current_epoch_participation, + (BlockMut::Electra(state), false) => &mut state.previous_epoch_participation, + (BlockMut::Fulu(state), true) => &mut state.current_epoch_participation, + (BlockMut::Fulu(state), false) => &mut state.previous_epoch_participation, + } + } + + fn inactivity_scores_mut(&mut self) -> &mut InactivityScores { + match self { + BlockMut::Electra(state) => &mut state.inactivity_scores, + BlockMut::Fulu(state) => &mut state.inactivity_scores, + } + } +} + +/// The electra-or-fulu state, mutably. See [`block_ref`]. +fn block_mut<'a>(state: &'a mut BeaconState, function: &'static str) -> Result> { + match state { + BeaconState::Electra(inner) => Ok(BlockMut::Electra(inner)), + BeaconState::Fulu(inner) => Ok(BlockMut::Fulu(inner)), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +/// `previous_epoch_participation` or `current_epoch_participation`, +/// immutably, whichever `current` selects. A companion to +/// [`BlockMut::epoch_participation_mut`] rather than a method on [`BlockRef`]: +/// only [`process_attestation`]'s read phase needs this, and it needs it +/// before deciding whether anything requires the mutable projection at all. +fn epoch_participation<'a>( + state: &'a BeaconState, + current: bool, + function: &'static str, +) -> Result<&'a EpochParticipation> { + match state { + BeaconState::Electra(inner) if current => Ok(&inner.current_epoch_participation), + BeaconState::Electra(inner) => Ok(&inner.previous_epoch_participation), + BeaconState::Fulu(inner) if current => Ok(&inner.current_epoch_participation), + BeaconState::Fulu(inner) => Ok(&inner.previous_epoch_participation), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +// --------------------------------------------------------------------------- +// Deposits +// --------------------------------------------------------------------------- + +/// Builds the registry entry a new deposit creates. +/// +/// Modified from phase0's version (`crate::beacon::stf::operations::get_validator_from_deposit`) +/// to cap the effective balance at [`get_max_effective_balance`] rather than +/// the fixed `MAX_EFFECTIVE_BALANCE`: a depositor who supplies a compounding +/// (`0x02`-prefixed) withdrawal credential from the start is entitled to +/// activate at the higher ceiling immediately, not just after a later +/// [`crate::beacon::helpers::electra::switch_to_compounding_validator`] call. +/// +/// Subtracting the remainder can never underflow: a modulus is always at +/// most the value it divides. +pub fn get_validator_from_deposit( + pubkey: BlsPubkey, + withdrawal_credentials: Bytes32, + amount: Gwei, +) -> Validator { + let validator = Validator { + pubkey, + withdrawal_credentials, + effective_balance: 0, + slashed: false, + activation_eligibility_epoch: FAR_FUTURE_EPOCH, + activation_epoch: FAR_FUTURE_EPOCH, + exit_epoch: FAR_FUTURE_EPOCH, + withdrawable_epoch: FAR_FUTURE_EPOCH, + }; + + let max_effective_balance = get_max_effective_balance(&validator); + Validator { + effective_balance: (amount - amount % preset::EFFECTIVE_BALANCE_INCREMENT) + .min(max_effective_balance), + ..validator + } +} + +/// Appends a brand-new validator and its starting balance. +/// +/// Modified from phase0's version (`crate::beacon::stf::operations::add_validator_to_registry`) +/// in two ways. It uses this module's own [`get_validator_from_deposit`] +/// rather than phase0's, for the reason that function's own doc gives. And it +/// also pushes to `previous_epoch_participation`, `current_epoch_participation`, +/// and `inactivity_scores`, altair-era fields phase0's own version never had +/// to grow; every one of those lists is positionally parallel to `validators` +/// and must be grown together, so a new entry with nothing to say about any +/// of the three still needs a zero placeholder in each. +pub fn add_validator_to_registry( + state: &mut BeaconState, + pubkey: BlsPubkey, + withdrawal_credentials: Bytes32, + amount: Gwei, +) -> Result<()> { + state.validators_mut().push(get_validator_from_deposit( + pubkey, + withdrawal_credentials, + amount, + ))?; + state.balances_mut().push(amount)?; + + let mut fields = block_mut(state, "add_validator_to_registry")?; + fields.epoch_participation_mut(true).push(0)?; + fields.epoch_participation_mut(false).push(0)?; + fields.inactivity_scores_mut().push(0)?; + Ok(()) +} + +/// Whether `signature` is a valid proof of possession over a deposit for +/// `pubkey`, `withdrawal_credentials`, and `amount`. +/// +/// New in electra only in the sense that the specification factors it out of +/// `apply_deposit` into its own named function; the check itself (a +/// fork-agnostic domain, since a depositor cannot know which fork or chain +/// will eventually accept its deposit) is exactly what phase0's own +/// `apply_deposit` (`crate::beacon::stf::operations::apply_deposit`) already inlines. +pub fn is_valid_deposit_signature( + pubkey: BlsPubkey, + withdrawal_credentials: Bytes32, + amount: Gwei, + signature: &BlsSignature, + config: &Config, +) -> bool { + let deposit_message = DepositMessage { + pubkey, + withdrawal_credentials, + amount, + }; + // A deposit is signed by a depositor who has no way to know which fork, + // or even which chain, will eventually accept it; see this function's own + // documentation. + let domain = compute_deposit_domain(config.genesis_fork_version); + let signing_root = compute_signing_root(deposit_message.hash_tree_root(), domain); + bls::verify(&pubkey, signing_root, signature) +} + +/// Registers a new validator (if the signature checks out) and queues the +/// deposit's amount as a [`electra::PendingDeposit`], for the epoch boundary +/// to credit. +/// +/// This is the single biggest behavioral change EIP-7251 makes to deposit +/// handling: phase0's `apply_deposit` (`crate::beacon::stf::operations::apply_deposit`) +/// credits a deposit's amount to a balance the moment it is processed. From +/// electra on, *no* deposit does that directly, existing validator or brand +/// new one alike; every deposit becomes a queue entry, and only +/// `process_pending_deposits` (epoch processing, not this file) ever +/// increases a balance because of one. That indirection is what lets the +/// epoch boundary rate-limit how much stake activates per epoch by *balance* +/// rather than by counting deposits. +/// +/// A new pubkey with an invalid signature is not queued at all: the +/// specification's own control flow only reaches the "append pending +/// deposit" step by falling through the `if pubkey not in validator_pubkeys` +/// block (when the pubkey already exists) or by successfully registering a +/// new validator inside it; a failed signature check on a new pubkey takes +/// neither path; it returns immediately with no side effect, mirroring +/// phase0's own "an invalid signature just means the deposit is not +/// credited" rule (see `crate::beacon::stf::operations::apply_deposit`'s own +/// documentation) one level further up, before there is even a queue entry +/// to add. +pub fn apply_deposit( + state: &mut BeaconState, + pubkey: BlsPubkey, + withdrawal_credentials: Bytes32, + amount: Gwei, + signature: &BlsSignature, + config: &Config, +) -> Result<()> { + let already_registered = state.validators().iter().any(|v| v.pubkey == pubkey); + if !already_registered { + if is_valid_deposit_signature(pubkey, withdrawal_credentials, amount, signature, config) { + // The registry entry starts at a zero balance; see this + // function's own documentation for why even a first-time + // deposit's amount is queued rather than credited directly. + add_validator_to_registry(state, pubkey, withdrawal_credentials, 0)?; + } else { + return Ok(()); + } + } + + let deposit = electra::PendingDeposit { + pubkey, + withdrawal_credentials, + amount, + signature: *signature, + slot: constants::GENESIS_SLOT, + }; + electra_state(state, "apply_deposit")? + .pending_deposits_mut() + .push(deposit)?; + Ok(()) +} + +/// Verifies a deposit's merkle proof, then applies it. +/// +/// Unchanged from phase0's version (`crate::beacon::stf::operations::process_deposit`) +/// beyond calling this module's own [`apply_deposit`]: the merkle-proof check +/// and the unconditional index advance are identical, and that unconditional +/// advance matters for the same reason phase0's own documentation gives, that +/// the index tracks how many deposits have been *consumed*, not how many +/// produced a validator. +pub fn process_deposit(state: &mut BeaconState, deposit: &Deposit, config: &Config) -> Result<()> { + verify( + is_valid_merkle_branch( + deposit.data.hash_tree_root(), + &deposit.proof, + (constants::DEPOSIT_CONTRACT_TREE_DEPTH + 1) as u64, + state.eth1_deposit_index(), + state.eth1_data().deposit_root, + ), + "is_valid_merkle_branch(hash_tree_root(deposit.data), deposit.proof, DEPOSIT_CONTRACT_TREE_DEPTH + 1, state.eth1_deposit_index, state.eth1_data.deposit_root)", + )?; + + *state.eth1_deposit_index_mut() += 1; + + apply_deposit( + state, + deposit.data.pubkey, + deposit.data.withdrawal_credentials, + deposit.data.amount, + &deposit.data.signature, + config, + ) +} + +// --------------------------------------------------------------------------- +// Voluntary exits +// --------------------------------------------------------------------------- + +/// Starts a validator's voluntary exit. +/// +/// Every check but the last two is phase0's, unchanged: still active, not +/// already exiting, past its own requested epoch, and past +/// `SHARD_COMMITTEE_PERIOD` since activation. The two additions are both +/// EIP-7251's: the validator must have no partial withdrawal already queued +/// (exiting out from under one would leave nothing to pay it from, so +/// [`get_pending_balance_to_withdraw`] must read zero first), and the exit +/// queue epoch itself is computed through +/// [`crate::beacon::helpers::electra::initiate_validator_exit`] rather than +/// phase0's (`crate::beacon::helpers::mutators::initiate_validator_exit`), the same +/// churn-by-balance swap described in this module's own documentation. +/// +/// Signs under a fixed fork version, [`Config::capella_fork_version`], for +/// EIP-7044, unchanged from deneb's own version +/// (`crate::beacon::stf::deneb::process_voluntary_exit`); see that function's own +/// documentation for why the domain is pinned rather than read off the +/// state's current fork. Not delegated to deneb's version despite that +/// overlap, because deneb's calls phase0's `initiate_validator_exit`, which +/// this fork can no longer use; see this function's own documentation above. +pub fn process_voluntary_exit( + state: &mut BeaconState, + signed_voluntary_exit: &SignedVoluntaryExit, + config: &Config, +) -> Result<()> { + let voluntary_exit = signed_voluntary_exit.message; + let current_epoch = get_current_epoch(state); + let validator = state.validator(voluntary_exit.validator_index)?; + + verify( + is_active_validator(validator, current_epoch), + "is_active_validator(validator, get_current_epoch(state))", + )?; + verify( + validator.exit_epoch == FAR_FUTURE_EPOCH, + "validator.exit_epoch == FAR_FUTURE_EPOCH", + )?; + verify( + current_epoch >= voluntary_exit.epoch, + "get_current_epoch(state) >= voluntary_exit.epoch", + )?; + let eligible_epoch = validator + .activation_epoch + .checked_add(config.shard_committee_period) + .ok_or(Error::ArithmeticOverflow( + "validator.activation_epoch + SHARD_COMMITTEE_PERIOD", + ))?; + verify( + current_epoch >= eligible_epoch, + "get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD", + )?; + // [New in Electra:EIP7251] + verify( + get_pending_balance_to_withdraw(state, voluntary_exit.validator_index)? == 0, + "get_pending_balance_to_withdraw(state, voluntary_exit.validator_index) == 0", + )?; + + let domain = compute_domain( + constants::DOMAIN_VOLUNTARY_EXIT, + config.capella_fork_version, + state.genesis_validators_root(), + ); + let signing_root = compute_signing_root(voluntary_exit.hash_tree_root(), domain); + verify( + bls::verify( + &validator.pubkey, + signing_root, + &signed_voluntary_exit.signature, + ), + "bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)", + )?; + + // [Modified in Electra:EIP7251] + electra_initiate_validator_exit(state, voluntary_exit.validator_index, config)?; + Ok(()) +} + +// --------------------------------------------------------------------------- +// BLS-to-execution changes +// --------------------------------------------------------------------------- + +/// Upgrades a validator's withdrawal credentials from a raw BLS public key +/// hash to an execution address. +/// +/// Not modified by electra: delegates to capella's own implementation +/// (`crate::beacon::stf::capella::process_bls_to_execution_change`) wholesale rather +/// than copying its body. That function needs nothing capella-specific +/// (every field it reads or writes, `validators`, `genesis_validators_root`, +/// is fork-invariant), so this file is required to expose the name at all +/// (see this module's own task list), but not a second copy of the logic to +/// keep in sync with capella's. +pub fn process_bls_to_execution_change( + state: &mut BeaconState, + signed_change: &capella::SignedBLSToExecutionChange, + config: &Config, +) -> Result<()> { + super::capella::process_bls_to_execution_change(state, signed_change, config) +} + +// --------------------------------------------------------------------------- +// Attester slashings +// --------------------------------------------------------------------------- + +/// Slashes every slashable validator in the overlap of two conflicting +/// attestations' attesting sets. +/// +/// Not modified by electra beyond the types it operates on: the +/// specification's own table of contents lists no "Modified +/// `process_attester_slashing`", only the `AttesterSlashing` and +/// `IndexedAttestation` containers it reads. This is phase0's version +/// (`crate::beacon::stf::operations::process_attester_slashing`) transcribed against +/// [`electra::AttesterSlashing`] and [`crate::beacon::helpers::electra::is_valid_indexed_attestation`] +/// instead, the same reason that helper exists as its own copy (see its own +/// documentation): a different concrete `IndexedAttestation` type, not +/// different logic. +pub fn process_attester_slashing( + state: &mut BeaconState, + attester_slashing: &electra::AttesterSlashing, + config: &Config, +) -> Result<()> { + let attestation_1 = &attester_slashing.attestation_1; + let attestation_2 = &attester_slashing.attestation_2; + + verify( + is_slashable_attestation_data(&attestation_1.data, &attestation_2.data), + "is_slashable_attestation_data(attestation_1.data, attestation_2.data)", + )?; + verify( + is_valid_indexed_attestation(state, attestation_1), + "is_valid_indexed_attestation(state, attestation_1)", + )?; + verify( + is_valid_indexed_attestation(state, attestation_2), + "is_valid_indexed_attestation(state, attestation_2)", + )?; + + let current_epoch = get_current_epoch(state); + // `is_valid_indexed_attestation` already required both index lists to be + // sorted and unique; see `crate::beacon::stf::operations::process_attester_slashing` + // for why walking `attestation_1`'s list in order while filtering by + // membership in `attestation_2`'s set yields the intersection already + // sorted. + let indices_2: HashSet = + attestation_2.attesting_indices.iter().copied().collect(); + + let mut slashed_any = false; + for &index in attestation_1.attesting_indices.iter() { + if !indices_2.contains(&index) { + continue; + } + if is_slashable_validator(state.validator(index)?, current_epoch) { + slash_validator(state, index, None, config)?; + slashed_any = true; + } + } + verify( + slashed_any, + "at least one validator in the intersection of the two attesting index sets was slashed", + )?; + Ok(()) +} + +// --------------------------------------------------------------------------- +// Attestations +// --------------------------------------------------------------------------- + +/// Scores an [`electra::Attestation`] against the three timeliness conditions +/// and pays the including proposer, reading the committees it covers from +/// `committee_bits` rather than a single `data.index` (EIP-7549). +/// +/// Shares altair's and deneb's overall shape (validate, then score, then pay +/// the proposer for newly-granted flags) but the validation prologue is +/// electra's own: `data.index` must be zero, since `committee_bits` is now +/// the only source of which committees this attestation covers, and each +/// named committee must contribute at least one attester +/// (`committee_attesters` non-empty), which is what stops a proposer padding +/// `committee_bits` with a committee nobody in it actually attested to. +/// [`crate::beacon::helpers::electra::get_attesting_indices`] (used below, in the +/// read phase) already does this same per-committee offset walk to build the +/// attester set; this prologue re-walks it only far enough to check the +/// "non-empty" and "total length matches" assertions the specification makes +/// before that set is ever computed, since neither assertion is something +/// [`crate::beacon::helpers::electra::get_attesting_indices`] itself checks. +/// +/// Structured as the same two-phase read-then-write split altair's and +/// deneb's versions use, and for the identical borrow-checker reason: see +/// `crate::beacon::stf::altair::process_attestation`'s own documentation. +pub fn process_attestation( + state: &mut BeaconState, + attestation: &electra::Attestation, +) -> Result<()> { + let data = attestation.data; + let current_epoch = get_current_epoch(state); + let previous_epoch = get_previous_epoch(state); + + verify( + data.target.epoch == previous_epoch || data.target.epoch == current_epoch, + "data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))", + )?; + verify( + data.target.epoch == compute_epoch_at_slot(data.slot), + "data.target.epoch == compute_epoch_at_slot(data.slot)", + )?; + // [EIP-7045, inherited from deneb]: no upper bound on `state.slot`, unlike + // altair's; see `crate::beacon::stf::deneb::process_attestation`'s own + // documentation for why FFG justification has no such bound to begin + // with. `data.slot` still comes straight off the wire, so the lower + // bound's own addition is still checked. + let min_slot = data + .slot + .checked_add(preset::MIN_ATTESTATION_INCLUSION_DELAY) + .ok_or(Error::ArithmeticOverflow( + "data.slot + MIN_ATTESTATION_INCLUSION_DELAY", + ))?; + verify( + min_slot <= state.slot(), + "data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot", + )?; + + // [Modified in Electra:EIP7549] + verify(data.index == 0, "data.index == 0")?; + let committee_indices = get_committee_indices(&attestation.committee_bits); + let mut committee_offset = 0usize; + for committee_index in committee_indices { + verify( + committee_index < get_committee_count_per_slot(state, data.target.epoch), + "committee_index < get_committee_count_per_slot(state, data.target.epoch)", + )?; + let committee = get_beacon_committee(state, data.slot, committee_index)?; + let committee_has_an_attester = (0..committee.len()).any(|position| { + attestation + .aggregation_bits + .get(committee_offset + position) + .unwrap_or(false) + }); + verify(committee_has_an_attester, "len(committee_attesters) > 0")?; + committee_offset += committee.len(); + } + verify( + attestation.aggregation_bits.len() == committee_offset, + "len(attestation.aggregation_bits) == committee_offset", + )?; + + // Safe: `min_slot <= state.slot()` above and `min_slot >= data.slot` (the + // inclusion delay is non-negative), so `data.slot <= state.slot()`. + let inclusion_delay = state.slot() - data.slot; + let participation_flag_indices = + attestation_participation_flag_indices(state, &data, inclusion_delay)?; + + let indexed_attestation = get_indexed_attestation(state, attestation)?; + verify( + is_valid_indexed_attestation(state, &indexed_attestation), + "is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))", + )?; + + // Read phase: for every attester, decide which flags this attestation + // newly satisfies and add up the proposer's reward for granting them. + let attesting_indices = get_attesting_indices(state, attestation)?; + let current_epoch_target = data.target.epoch == current_epoch; + let participation = epoch_participation(state, current_epoch_target, "process_attestation")?; + + let mut proposer_reward_numerator: Gwei = 0; + let mut updates: Vec<(ValidatorIndex, ParticipationFlags)> = Vec::new(); + for index in attesting_indices { + let current_flags = + participation + .get(index as usize) + .copied() + .ok_or(Error::IndexOutOfBounds { + index: index as usize, + len: participation.len(), + })?; + + let mut new_flags: ParticipationFlags = 0; + for &flag_index in &participation_flag_indices { + if has_flag(current_flags, flag_index) { + continue; + } + new_flags = add_flag(new_flags, flag_index); + let weight = constants::PARTICIPATION_FLAG_WEIGHTS[flag_index]; + let reward = get_base_reward(state, index)?.checked_mul(weight).ok_or( + Error::ArithmeticOverflow("get_base_reward(state, index) * weight"), + )?; + proposer_reward_numerator = proposer_reward_numerator + .checked_add(reward) + .ok_or(Error::ArithmeticOverflow("proposer_reward_numerator"))?; + } + if new_flags != 0 { + updates.push((index, new_flags)); + } + } + + // Write phase: apply exactly the flags the read phase decided on. Nothing + // from here on reads `state` any further, so this is free to take the + // mutable projection the read phase could not. + { + let mut fields = block_mut(state, "process_attestation")?; + let participation_mut = fields.epoch_participation_mut(current_epoch_target); + let participation_len = participation_mut.len(); + for (index, new_flags) in updates { + let flags = + participation_mut + .get_mut(index as usize) + .ok_or(Error::IndexOutOfBounds { + index: index as usize, + len: participation_len, + })?; + *flags |= new_flags; + } + } + + const NON_PROPOSER_WEIGHT: u64 = constants::WEIGHT_DENOMINATOR - constants::PROPOSER_WEIGHT; + const PROPOSER_REWARD_DENOMINATOR: u64 = + NON_PROPOSER_WEIGHT * constants::WEIGHT_DENOMINATOR / constants::PROPOSER_WEIGHT; + let proposer_reward = proposer_reward_numerator / PROPOSER_REWARD_DENOMINATOR; + let proposer_index = get_beacon_proposer_index(state)?; + increase_balance(state, proposer_index, proposer_reward)?; + + Ok(()) +} + +/// Which of the three participation flags an attestation with `data`, +/// included after `inclusion_delay` slots, satisfies. +/// +/// Electra changes nothing here itself. This is deneb's EIP-7045 version, +/// duplicated rather than called: `crate::beacon::stf::deneb`'s own function of this +/// name is private to that module (not `pub`), so it is not visible from +/// here even though both files are in the same crate, and this module has no +/// shared location for a function altair introduces and deneb later modifies +/// (`crate::beacon::helpers::altair::altair_state`'s own projection, which a shared +/// version would sit behind, is scoped to `BeaconState::Altair` alone; see +/// its own doc). Whoever next touches either copy should consider hoisting +/// one, in `crate::beacon::helpers::altair` or wherever else both `stf::deneb` and +/// `stf::electra` (and, presumably, every later fork) can reach it. +fn attestation_participation_flag_indices( + state: &BeaconState, + data: &AttestationData, + inclusion_delay: u64, +) -> Result> { + let justified_checkpoint = if data.target.epoch == get_current_epoch(state) { + state.current_justified_checkpoint() + } else { + state.previous_justified_checkpoint() + }; + let is_matching_source = data.source == justified_checkpoint; + + let target_root = get_block_root(state, data.target.epoch)?; + let target_root_matches = data.target.root == target_root; + let is_matching_target = is_matching_source && target_root_matches; + + let head_root = get_block_root_at_slot(state, data.slot)?; + let head_root_matches = data.beacon_block_root == head_root; + let is_matching_head = is_matching_target && head_root_matches; + + verify(is_matching_source, "is_matching_source")?; + + let mut participation_flag_indices = Vec::new(); + if is_matching_source && inclusion_delay <= integer_squareroot(preset::SLOTS_PER_EPOCH) { + participation_flag_indices.push(constants::TIMELY_SOURCE_FLAG_INDEX); + } + // [EIP-7045]: no `inclusion_delay` bound, unlike altair's own + // `inclusion_delay <= SLOTS_PER_EPOCH`. + if is_matching_target { + participation_flag_indices.push(constants::TIMELY_TARGET_FLAG_INDEX); + } + if is_matching_head && inclusion_delay == preset::MIN_ATTESTATION_INCLUSION_DELAY { + participation_flag_indices.push(constants::TIMELY_HEAD_FLAG_INDEX); + } + + Ok(participation_flag_indices) +} + +// --------------------------------------------------------------------------- +// Withdrawals +// --------------------------------------------------------------------------- + +/// The execution address a validator's payout is sent to: the low bytes of +/// its withdrawal credentials, present regardless of whether those +/// credentials are eth1 or compounding (both are execution-form; see +/// `crate::beacon::helpers::electra::has_execution_withdrawal_credential`). +/// +/// A duplicate of capella's own private `withdrawal_address` +/// (`crate::beacon::stf::capella`): that function is not `pub`, so it is not visible +/// here even within the same crate. +fn withdrawal_address(validator: &Validator) -> ExecutionAddress { + ExecutionAddress::from_slice(&validator.withdrawal_credentials.0[12..]) +} + +/// The withdrawals this block's sweep owes, without applying them, and how +/// many entries of `pending_partial_withdrawals` it consumed while deciding +/// that. +/// +/// Two sweeps, in the specification's order, both drawing from the same +/// `withdrawals` list and the same `withdrawal_index` cursor so a partial +/// withdrawal already collected by the first sweep is visible to the +/// second's own `total_withdrawn` accounting for the same validator. +/// +/// The first sweep drains [`electra::PendingPartialWithdrawal`]s +/// (EIP-7251's own queue, absent before this fork): each entry is either +/// paid (if the validator is still active, sitting on enough effective and +/// excess balance) or simply dropped, but either way it counts toward +/// `processed_partial_withdrawals_count`, which is the second return value +/// [`process_withdrawals`] needs to know how much of the queue to drop +/// afterward: a withdrawal request can be consumed by this sweep without +/// ever producing an actual [`capella::Withdrawal`], and the queue still has +/// to advance past it regardless. +/// +/// The second sweep is capella's own registry walk +/// (`crate::beacon::stf::capella::get_expected_withdrawals`), unchanged in shape, +/// except that both withdrawability predicates are electra's +/// ([`is_fully_withdrawable_validator`], [`is_partially_withdrawable_validator`]) +/// and a partial withdrawal's amount is capped against +/// [`get_max_effective_balance`] (a validator's own ceiling) rather than the +/// single fixed `MAX_EFFECTIVE_BALANCE`. +pub fn get_expected_withdrawals(state: &BeaconState) -> Result<(Vec, usize)> { + let epoch = get_current_epoch(state); + let fields = block_ref(state, "get_expected_withdrawals")?; + let mut withdrawal_index = fields.next_withdrawal_index(); + let mut validator_index = fields.next_withdrawal_validator_index(); + + let mut withdrawals: Vec = Vec::new(); + let mut processed_partial_withdrawals_count: usize = 0; + + // [New in Electra:EIP7251]: consume pending partial withdrawals. + let electra_ref = + crate::beacon::helpers::electra::electra_state_ref(state, "get_expected_withdrawals")?; + let pending_partial_withdrawals = electra_ref.pending_partial_withdrawals(); + for withdrawal in pending_partial_withdrawals.iter() { + if withdrawal.withdrawable_epoch > epoch + || withdrawals.len() == preset::MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP as usize + { + break; + } + + let validator = state.validator(withdrawal.validator_index)?; + let has_sufficient_effective_balance = + validator.effective_balance >= preset::MIN_ACTIVATION_BALANCE; + let total_withdrawn: Gwei = withdrawals + .iter() + .filter(|paid| paid.validator_index == withdrawal.validator_index) + .fold(0, |total, paid| total.saturating_add(paid.amount)); + let balance = state + .balance(withdrawal.validator_index)? + .checked_sub(total_withdrawn) + .ok_or(Error::ArithmeticOverflow( + "state.balances[withdrawal.validator_index] - total_withdrawn", + ))?; + let has_excess_balance = balance > preset::MIN_ACTIVATION_BALANCE; + + if validator.exit_epoch == FAR_FUTURE_EPOCH + && has_sufficient_effective_balance + && has_excess_balance + { + let withdrawable_balance = + (balance - preset::MIN_ACTIVATION_BALANCE).min(withdrawal.amount); + withdrawals.push(capella::Withdrawal { + index: withdrawal_index, + validator_index: withdrawal.validator_index, + address: withdrawal_address(validator), + amount: withdrawable_balance, + }); + withdrawal_index = withdrawal_index + .checked_add(1) + .ok_or(Error::ArithmeticOverflow("withdrawal_index + 1"))?; + } + + // Regardless of whether a withdrawal was actually produced above, + // this queue entry is consumed either way. + processed_partial_withdrawals_count += 1; + } + + // Sweep for the rest, the same bounded registry walk capella's own + // `get_expected_withdrawals` runs; see this function's own documentation + // for what electra changes about it. + let validator_count = state.validators().len() as u64; + let bound = validator_count.min(preset::MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP); + for _ in 0..bound { + let validator = state.validator(validator_index)?; + let total_withdrawn: Gwei = withdrawals + .iter() + .filter(|paid| paid.validator_index == validator_index) + .fold(0, |total, paid| total.saturating_add(paid.amount)); + let balance = state + .balance(validator_index)? + .checked_sub(total_withdrawn) + .ok_or(Error::ArithmeticOverflow( + "state.balances[validator_index] - total_withdrawn", + ))?; + + if is_fully_withdrawable_validator(validator, balance, epoch) { + withdrawals.push(capella::Withdrawal { + index: withdrawal_index, + validator_index, + address: withdrawal_address(validator), + amount: balance, + }); + withdrawal_index = withdrawal_index + .checked_add(1) + .ok_or(Error::ArithmeticOverflow("withdrawal_index + 1"))?; + } else if is_partially_withdrawable_validator(validator, balance) { + // [Modified in Electra:EIP7251]: capped against this validator's + // own ceiling, not the single fixed `MAX_EFFECTIVE_BALANCE`. + let amount = balance + .checked_sub(get_max_effective_balance(validator)) + .ok_or(Error::ArithmeticOverflow( + "balance - get_max_effective_balance(validator)", + ))?; + withdrawals.push(capella::Withdrawal { + index: withdrawal_index, + validator_index, + address: withdrawal_address(validator), + amount, + }); + withdrawal_index = withdrawal_index + .checked_add(1) + .ok_or(Error::ArithmeticOverflow("withdrawal_index + 1"))?; + } + + if withdrawals.len() == preset::MAX_WITHDRAWALS_PER_PAYLOAD { + break; + } + validator_index = validator_index + .checked_add(1) + .ok_or(Error::ArithmeticOverflow("validator_index + 1"))? + % validator_count; + } + + Ok((withdrawals, processed_partial_withdrawals_count)) +} + +/// Applies this block's withdrawal sweep: checks the block's declared +/// `payload.withdrawals` against what the sweep actually owes, pays each one +/// out, drops however much of `pending_partial_withdrawals` +/// [`get_expected_withdrawals`] consumed, and advances the sweep's cursor for +/// next time. +/// +/// The cursor-update logic (the two-branch split between a full payload and +/// a partial one) is unchanged from capella's own version +/// (`crate::beacon::stf::capella::process_withdrawals`); see that function's own +/// documentation for why the two branches disagree about where "next" is +/// once the registry is smaller than `MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP`. +/// What electra adds is the `pending_partial_withdrawals` drop, which has no +/// capella analogue since that queue does not exist before this fork. +pub fn process_withdrawals( + state: &mut BeaconState, + payload: &deneb::ExecutionPayload, +) -> Result<()> { + let (expected_withdrawals, processed_partial_withdrawals_count) = + get_expected_withdrawals(state)?; + verify( + payload.withdrawals.to_vec() == expected_withdrawals, + "payload.withdrawals == expected_withdrawals", + )?; + + for withdrawal in &expected_withdrawals { + decrease_balance(state, withdrawal.validator_index, withdrawal.amount)?; + } + + // [New in Electra:EIP7251]: drop exactly as many pending partial + // withdrawals as get_expected_withdrawals actually consumed, whether or + // not each one produced a real payout. + { + let mut fields = block_mut(state, "process_withdrawals")?; + let mut owned = std::mem::take(fields.pending_partial_withdrawals_mut()).into_inner(); + // Safe: `processed_partial_withdrawals_count` only ever counts + // iterations of this same list's own loop in `get_expected_withdrawals`, + // so it can never exceed the list's length. + let remaining = owned.split_off(processed_partial_withdrawals_count); + *fields.pending_partial_withdrawals_mut() = remaining.try_into()?; + } + + if let Some(latest_withdrawal) = expected_withdrawals.last() { + *block_mut(state, "process_withdrawals")?.next_withdrawal_index_mut() = latest_withdrawal + .index + .checked_add(1) + .ok_or(Error::ArithmeticOverflow("latest_withdrawal.index + 1"))?; + } + + let validator_count = state.validators().len() as u64; + let next_validator_index = if expected_withdrawals.len() == preset::MAX_WITHDRAWALS_PER_PAYLOAD + { + let latest_withdrawal = expected_withdrawals + .last() + .expect("MAX_WITHDRAWALS_PER_PAYLOAD is never zero, so a full payload is non-empty"); + latest_withdrawal + .validator_index + .checked_add(1) + .ok_or(Error::ArithmeticOverflow( + "latest_withdrawal.validator_index + 1", + ))? + % validator_count + } else { + let current_cursor = + block_ref(state, "process_withdrawals")?.next_withdrawal_validator_index(); + current_cursor + .checked_add(preset::MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP) + .ok_or(Error::ArithmeticOverflow( + "next_withdrawal_validator_index + MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP", + ))? + % validator_count + }; + *block_mut(state, "process_withdrawals")?.next_withdrawal_validator_index_mut() = + next_validator_index; + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Execution-layer-triggered requests +// --------------------------------------------------------------------------- + +/// Runs every execution-layer-triggered request in `requests`, in the +/// specification's order: deposits, then withdrawals, then consolidations. +/// +/// The one loop [`process_operations`] itself does not inline, since +/// [`electra::ExecutionRequests`] bundles all three lists together on +/// [`electra::BeaconBlockBody::execution_requests`] rather than carrying them +/// as three separate body fields the way every other operation list is +/// carried. +pub fn process_execution_requests( + state: &mut BeaconState, + requests: &electra::ExecutionRequests, + config: &Config, +) -> Result<()> { + for deposit in requests.deposits.iter() { + process_deposit_request(state, deposit)?; + } + for withdrawal in requests.withdrawals.iter() { + process_withdrawal_request(state, withdrawal, config)?; + } + for consolidation in requests.consolidations.iter() { + process_consolidation_request(state, consolidation, config)?; + } + Ok(()) +} + +// --------------------------------------------------------------------------- +// Deposit requests +// --------------------------------------------------------------------------- + +/// Records an execution-layer-triggered deposit (EIP-6110) as a +/// [`electra::PendingDeposit`], the same queue-then-drain destination every +/// other deposit source ([`apply_deposit`]) feeds. +/// +/// The first request ever seen fixes `deposit_requests_start_index`, the +/// point past which [`process_operations`]'s own deposit-count check trusts +/// the execution layer's request log rather than the old `Eth1Data` vote +/// count; see that check's own documentation. No signature check happens +/// here, unlike [`apply_deposit`]'s: a request already arrived bundled with +/// the execution payload the block itself commits to, so there is no +/// separate proof-of-possession step to gate registering it on, the same way +/// [`process_withdrawal_request`] and [`process_consolidation_request`] +/// trust the execution layer's own request rather than re-deriving a +/// signature for it. +pub fn process_deposit_request( + state: &mut BeaconState, + request: &electra::DepositRequest, +) -> Result<()> { + { + let mut fields = block_mut(state, "process_deposit_request")?; + if *fields.deposit_requests_start_index_mut() + == constants::UNSET_DEPOSIT_REQUESTS_START_INDEX + { + *fields.deposit_requests_start_index_mut() = request.index; + } + } + + let deposit = electra::PendingDeposit { + pubkey: request.pubkey, + withdrawal_credentials: request.withdrawal_credentials, + amount: request.amount, + signature: request.signature, + slot: state.slot(), + }; + electra_state(state, "process_deposit_request")? + .pending_deposits_mut() + .push(deposit)?; + Ok(()) +} + +// --------------------------------------------------------------------------- +// Execution-layer withdrawal requests +// --------------------------------------------------------------------------- + +/// Honors (or quietly drops) an execution-layer-triggered exit or partial +/// withdrawal (EIP-7002, EIP-7251). +/// +/// Every early return below is the specification's own plain `return`, never +/// an `assert`, and that distinction is load bearing: none of these +/// conditions makes the wrapping *block* invalid. The execution layer +/// already committed to this request by including it in the payload the +/// block's own hash covers; consensus choosing not to act on a stale, +/// malformed, or already-superseded one is a decision about the request, +/// not a verdict on the block that carried it. Getting this backwards, an +/// `?` where the specification has a `return`, would reject an otherwise +/// perfectly valid block over a request that simply no longer applies (a +/// validator that exited on its own between the request being queued on the +/// execution side and this block including it, say). +/// +/// In order: the pending-partial-withdrawals queue must have room (unless +/// this is a full exit, which does not use that queue), the requested pubkey +/// must resolve to a real validator, that validator's withdrawal credentials +/// must actually name `source_address` (so a request cannot be honored +/// against a validator it was never authorized to touch), the validator must +/// be active, not already exiting, and past `SHARD_COMMITTEE_PERIOD` since +/// activation. A full exit request (`amount == FULL_EXIT_REQUEST_AMOUNT`) +/// then either exits the validator or does nothing, unconditionally, +/// regardless of which; a partial withdrawal request additionally requires a +/// compounding credential and genuine excess balance before it queues +/// anything. +/// +/// The one piece of arithmetic that *does* reject the block on failure is +/// `validator.activation_epoch + SHARD_COMMITTEE_PERIOD`: an overflow there +/// means `activation_epoch` itself is corrupt state, not that this request is +/// stale, so it is checked and propagated with `?` rather than folded into +/// the silent-return chain above it. +pub fn process_withdrawal_request( + state: &mut BeaconState, + request: &electra::WithdrawalRequest, + config: &Config, +) -> Result<()> { + let amount = request.amount; + let is_full_exit_request = amount == constants::FULL_EXIT_REQUEST_AMOUNT; + + let pending_partial_withdrawals_len = block_mut(state, "process_withdrawal_request")? + .pending_partial_withdrawals_mut() + .len(); + if pending_partial_withdrawals_len == preset::PENDING_PARTIAL_WITHDRAWALS_LIMIT + && !is_full_exit_request + { + return Ok(()); + } + + let Some(index) = state + .validators() + .iter() + .position(|validator| validator.pubkey == request.validator_pubkey) + .map(|index| index as ValidatorIndex) + else { + return Ok(()); + }; + let validator = state.validator(index)?; + + let has_correct_credential = has_execution_withdrawal_credential(validator); + let is_correct_source_address = withdrawal_address(validator) == request.source_address; + if !(has_correct_credential && is_correct_source_address) { + return Ok(()); + } + if !is_active_validator(validator, get_current_epoch(state)) { + return Ok(()); + } + if validator.exit_epoch != FAR_FUTURE_EPOCH { + return Ok(()); + } + // See this function's own documentation for why this one step is + // checked with `?` rather than folded into the silent-return chain. + let eligible_epoch = validator + .activation_epoch + .checked_add(config.shard_committee_period) + .ok_or(Error::ArithmeticOverflow( + "validator.activation_epoch + SHARD_COMMITTEE_PERIOD", + ))?; + if get_current_epoch(state) < eligible_epoch { + return Ok(()); + } + + let pending_balance_to_withdraw = get_pending_balance_to_withdraw(state, index)?; + + if is_full_exit_request { + // Only exit the validator if it has no pending withdrawal in the + // queue; either way, a full exit request never falls through to the + // partial-withdrawal logic below. + if pending_balance_to_withdraw == 0 { + electra_initiate_validator_exit(state, index, config)?; + } + return Ok(()); + } + + let validator = state.validator(index)?; + let has_sufficient_effective_balance = + validator.effective_balance >= preset::MIN_ACTIVATION_BALANCE; + let has_excess_balance = state.balance(index)? + > preset::MIN_ACTIVATION_BALANCE.saturating_add(pending_balance_to_withdraw); + + // Only a compounding validator can take a *partial* withdrawal through + // this path; a non-compounding one's only route out is the full exit + // above. Falling through this `if` with nothing queued (rather than an + // `else` branch that errors) is itself the specification's own behavior: + // a partial request that does not qualify is simply not honored. + if has_compounding_withdrawal_credential(validator) + && has_sufficient_effective_balance + && has_excess_balance + { + let to_withdraw = state + .balance(index)? + .checked_sub(preset::MIN_ACTIVATION_BALANCE) + .and_then(|value| value.checked_sub(pending_balance_to_withdraw)) + .ok_or(Error::ArithmeticOverflow( + "state.balances[index] - MIN_ACTIVATION_BALANCE - pending_balance_to_withdraw", + ))? + .min(amount); + let exit_queue_epoch = compute_exit_epoch_and_update_churn(state, to_withdraw, config)?; + let withdrawable_epoch = exit_queue_epoch + .checked_add(config.min_validator_withdrawability_delay) + .ok_or(Error::ArithmeticOverflow( + "exit_queue_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY", + ))?; + let withdrawal = electra::PendingPartialWithdrawal { + validator_index: index, + amount: to_withdraw, + withdrawable_epoch, + }; + block_mut(state, "process_withdrawal_request")? + .pending_partial_withdrawals_mut() + .push(withdrawal)?; + } + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Execution-layer consolidation requests +// --------------------------------------------------------------------------- + +/// Whether `request` is really a request to switch its source (and only +/// source) validator from an eth1 to a compounding withdrawal credential, +/// disguised as a self-consolidation. +/// +/// A validator that already holds an eth1 credential has no other way to +/// become compounding: [`crate::beacon::helpers::electra::switch_to_compounding_validator`] +/// is only ever reachable through [`process_consolidation_request`] noticing +/// this pattern (source and target are the same validator) first. Returns +/// `Result` only for symmetry with this module's other state-reading +/// functions; nothing inside can actually fail, since every condition here +/// is itself one of the specification's own `return False` guards rather +/// than an assertion. +pub fn is_valid_switch_to_compounding_request( + state: &BeaconState, + request: &electra::ConsolidationRequest, +) -> Result { + if request.source_pubkey != request.target_pubkey { + return Ok(false); + } + + let Some(source_validator) = state + .validators() + .iter() + .find(|validator| validator.pubkey == request.source_pubkey) + else { + return Ok(false); + }; + + if withdrawal_address(source_validator) != request.source_address { + return Ok(false); + } + if !has_eth1_withdrawal_credential(source_validator) { + return Ok(false); + } + if !is_active_validator(source_validator, get_current_epoch(state)) { + return Ok(false); + } + if source_validator.exit_epoch != FAR_FUTURE_EPOCH { + return Ok(false); + } + + Ok(true) +} + +/// Honors (or quietly drops) an execution-layer-triggered consolidation +/// (EIP-7251): either a switch-to-compounding request in disguise (see +/// [`is_valid_switch_to_compounding_request`]), or a real merge of one +/// validator's balance into another's. +/// +/// Every early return here, in both branches, is the specification's own +/// plain `return`, not an `assert`; see [`process_withdrawal_request`]'s own +/// documentation for why that distinction matters and must not be turned +/// into a rejected block by an incautious `?`. The one exception, again as +/// in that function, is `source_validator.activation_epoch + +/// SHARD_COMMITTEE_PERIOD`: an overflow there is checked and propagated, +/// since it would mean corrupt state rather than a stale request. +pub fn process_consolidation_request( + state: &mut BeaconState, + request: &electra::ConsolidationRequest, + config: &Config, +) -> Result<()> { + if is_valid_switch_to_compounding_request(state, request)? { + // Already known to resolve, by the check just above; state has not + // been mutated since. + let source_index = state + .validators() + .iter() + .position(|validator| validator.pubkey == request.source_pubkey) + .map(|index| index as ValidatorIndex) + .ok_or(Error::SpecAssert( + "is_valid_switch_to_compounding_request already resolved consolidation_request.source_pubkey", + ))?; + crate::beacon::helpers::electra::switch_to_compounding_validator(state, source_index)?; + return Ok(()); + } + + // Guards against using a self-consolidation to trigger an exit through + // the branch below, once the switch-to-compounding branch above has + // already ruled out (for some other reason) treating it as a genuine + // credential upgrade. + if request.source_pubkey == request.target_pubkey { + return Ok(()); + } + let pending_consolidations_len = block_mut(state, "process_consolidation_request")? + .pending_consolidations_mut() + .len(); + if pending_consolidations_len == preset::PENDING_CONSOLIDATIONS_LIMIT { + return Ok(()); + } + if get_consolidation_churn_limit(state, config)? <= preset::MIN_ACTIVATION_BALANCE { + return Ok(()); + } + + let Some(source_index) = state + .validators() + .iter() + .position(|validator| validator.pubkey == request.source_pubkey) + .map(|index| index as ValidatorIndex) + else { + return Ok(()); + }; + let Some(target_index) = state + .validators() + .iter() + .position(|validator| validator.pubkey == request.target_pubkey) + .map(|index| index as ValidatorIndex) + else { + return Ok(()); + }; + + let source_validator = state.validator(source_index)?; + let has_correct_credential = has_execution_withdrawal_credential(source_validator); + let is_correct_source_address = withdrawal_address(source_validator) == request.source_address; + if !(has_correct_credential && is_correct_source_address) { + return Ok(()); + } + + let target_validator = state.validator(target_index)?; + if !has_compounding_withdrawal_credential(target_validator) { + return Ok(()); + } + + let current_epoch = get_current_epoch(state); + if !is_active_validator(source_validator, current_epoch) { + return Ok(()); + } + if !is_active_validator(target_validator, current_epoch) { + return Ok(()); + } + if source_validator.exit_epoch != FAR_FUTURE_EPOCH { + return Ok(()); + } + if target_validator.exit_epoch != FAR_FUTURE_EPOCH { + return Ok(()); + } + // See this function's own documentation for why this one step is + // checked with `?` rather than folded into the silent-return chain. + let eligible_epoch = source_validator + .activation_epoch + .checked_add(config.shard_committee_period) + .ok_or(Error::ArithmeticOverflow( + "source_validator.activation_epoch + SHARD_COMMITTEE_PERIOD", + ))?; + if current_epoch < eligible_epoch { + return Ok(()); + } + if get_pending_balance_to_withdraw(state, source_index)? > 0 { + return Ok(()); + } + + let source_effective_balance = source_validator.effective_balance; + let exit_epoch = crate::beacon::helpers::electra::compute_consolidation_epoch_and_update_churn( + state, + source_effective_balance, + config, + )?; + let withdrawable_epoch = exit_epoch + .checked_add(config.min_validator_withdrawability_delay) + .ok_or(Error::ArithmeticOverflow( + "exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY", + ))?; + + { + let source_validator = state.validator_mut(source_index)?; + source_validator.exit_epoch = exit_epoch; + source_validator.withdrawable_epoch = withdrawable_epoch; + } + + let consolidation = electra::PendingConsolidation { + source_index, + target_index, + }; + block_mut(state, "process_consolidation_request")? + .pending_consolidations_mut() + .push(consolidation)?; + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Execution payload +// --------------------------------------------------------------------------- + +/// Validates this slot's execution payload and its blob commitments, then +/// caches the payload's header. +/// +/// Structurally deneb's own [`super::deneb::process_execution_payload`] +/// (parent-hash continuity, `prev_randao`, timestamp, a blob-commitment +/// count check, the collapsed engine check, then caching a +/// [`deneb::ExecutionPayloadHeader`], the same header type electra keeps +/// unchanged from deneb), but not literally callable as that function: its +/// commitment-count check reads [`Config::max_blobs_per_block_deneb`], while +/// electra's own limit, [`Config::max_blobs_per_block_electra`], is a +/// *different* configuration field (`MAX_BLOBS_PER_BLOCK_ELECTRA` is listed +/// under electra's own "Configuration" table, not carried over from deneb's +/// "Preset" one), and `crate::beacon::stf::deneb`'s own state projection +/// (`deneb_state`/`deneb_state_ref`) is deliberately scoped to +/// `BeaconState::Deneb` alone, so it could not read an electra state's +/// header even if the constant matched. Every other step is transcribed +/// rather than restructured, including not computing anything from +/// `body.execution_requests`: see [`super::deneb::process_execution_payload`]'s +/// own documentation for why the versioned-hashes list (and, from electra +/// on, the execution-requests list `get_execution_requests_list` would +/// build) is dead weight in this module specifically, since +/// [`ExecutionEngine`] collapses the whole `verify_and_notify_new_payload` +/// interface to one boolean and never inspects either. +pub fn process_execution_payload( + state: &mut BeaconState, + body: &electra::BeaconBlockBody, + config: &Config, + engine: &ExecutionEngine, +) -> Result<()> { + let payload = &body.execution_payload; + + let expected_parent_hash = block_ref(state, "process_execution_payload")? + .latest_execution_payload_header() + .block_hash; + verify( + payload.parent_hash == expected_parent_hash, + "payload.parent_hash == state.latest_execution_payload_header.block_hash", + )?; + verify( + payload.prev_randao == get_randao_mix(state, get_current_epoch(state)), + "payload.prev_randao == get_randao_mix(state, get_current_epoch(state))", + )?; + verify( + payload.timestamp + == super::bellatrix::compute_timestamp_at_slot(state, state.slot(), config), + "payload.timestamp == compute_time_at_slot(state, state.slot)", + )?; + // [Modified in Electra:EIP7691]: see this function's own documentation + // for why `Config::max_blobs_per_block_electra` rather than + // `Config::max_blobs_per_block_deneb`. + verify( + body.blob_kzg_commitments.len() as u64 <= config.max_blobs_per_block_electra, + "len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_ELECTRA", + )?; + + // See this function's own documentation for why this is computed but + // not itself checked against anything. + let _versioned_hashes: Vec = body + .blob_kzg_commitments + .iter() + .map(super::deneb::kzg_commitment_to_versioned_hash) + .collect(); + + verify( + engine.execution_valid, + "verify_and_notify_new_payload(NewPayloadRequest(execution_payload=payload, \ + versioned_hashes=versioned_hashes, \ + parent_beacon_block_root=state.latest_block_header.parent_root, \ + execution_requests=body.execution_requests))", + )?; + + let header = deneb::ExecutionPayloadHeader { + parent_hash: payload.parent_hash, + fee_recipient: payload.fee_recipient, + state_root: payload.state_root, + receipts_root: payload.receipts_root, + logs_bloom: payload.logs_bloom.clone(), + prev_randao: payload.prev_randao, + block_number: payload.block_number, + gas_limit: payload.gas_limit, + gas_used: payload.gas_used, + timestamp: payload.timestamp, + extra_data: payload.extra_data.clone(), + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash, + transactions_root: payload.transactions.hash_tree_root(), + withdrawals_root: payload.withdrawals.hash_tree_root(), + blob_gas_used: payload.blob_gas_used, + excess_blob_gas: payload.excess_blob_gas, + }; + *block_mut(state, "process_execution_payload")?.latest_execution_payload_header_mut() = header; + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Operations +// --------------------------------------------------------------------------- + +/// Runs every operation in an electra block, in the specification's order. +/// +/// Takes `body: &electra::BeaconBlockBody` rather than each operation list +/// as its own parameter, unlike `crate::beacon::stf::operations::process_operations` +/// (six lists) and even `crate::beacon::stf::capella::process_operations` and +/// `crate::beacon::stf::deneb::process_operations` (seven, one past clippy's +/// default limit, already tolerated there with an `#[allow]`). Electra's own +/// body carries eight lists relevant here: phase0's five, capella's +/// `bls_to_execution_changes`, and (bundled into one field, +/// [`electra::ExecutionRequests`]) the three new execution-layer-triggered +/// request kinds. Eight separate parameters plus `config` would be two past +/// that same limit for no real benefit, since every call site already holds +/// a whole `electra::BeaconBlockBody` (this function's only caller, +/// [`process_block`], unpacks nothing else from it either); see this module's +/// module documentation (`crate::beacon::stf`) for why a shared body abstraction is +/// usually the wrong tool, and why taking the *whole*, already fork-specific +/// body here is the exception that doc anticipates rather than a +/// contradiction of it: nothing generic dispatches to this function the way +/// `crate::beacon::stf::block::process_block_header` is shared across every fork, so +/// there is no caller anywhere that would have to learn electra's body shape +/// just to call this. +/// +/// The deposit-count check is electra's own (EIP-6110): once +/// `deposit_requests_start_index` is set, it (not `eth1_data.deposit_count` +/// alone) caps how many `Eth1Data`-sourced deposits a block may still carry, +/// which is what lets the old deposit-contract path wind down cleanly as the +/// execution-layer request path (`process_deposit_request`) takes over. +/// `eth1_deposit_index_limit - state.eth1_deposit_index` cannot underflow: +/// the surrounding `if` already established `state.eth1_deposit_index < +/// eth1_deposit_index_limit`. +pub fn process_operations( + state: &mut BeaconState, + body: &electra::BeaconBlockBody, + config: &Config, +) -> Result<()> { + let deposit_requests_start_index = + block_ref(state, "process_operations")?.deposit_requests_start_index(); + let eth1_deposit_index_limit = state + .eth1_data() + .deposit_count + .min(deposit_requests_start_index); + if state.eth1_deposit_index() < eth1_deposit_index_limit { + let outstanding = eth1_deposit_index_limit - state.eth1_deposit_index(); + verify( + body.deposits.len() as u64 == outstanding.min(preset::MAX_DEPOSITS as u64), + "len(body.deposits) == min(MAX_DEPOSITS, eth1_deposit_index_limit - state.eth1_deposit_index)", + )?; + } else { + verify(body.deposits.is_empty(), "len(body.deposits) == 0")?; + } + + for proposer_slashing in body.proposer_slashings.iter() { + super::operations::process_proposer_slashing(state, proposer_slashing, config)?; + } + for attester_slashing in body.attester_slashings.iter() { + process_attester_slashing(state, attester_slashing, config)?; + } + // [Modified in Electra:EIP7549] + for attestation in body.attestations.iter() { + process_attestation(state, attestation)?; + } + for deposit in body.deposits.iter() { + process_deposit(state, deposit, config)?; + } + // [Modified in Electra:EIP7251] + for voluntary_exit in body.voluntary_exits.iter() { + process_voluntary_exit(state, voluntary_exit, config)?; + } + for signed_change in body.bls_to_execution_changes.iter() { + process_bls_to_execution_change(state, signed_change, config)?; + } + // [New in Electra:EIP6110:EIP7002:EIP7251] + process_execution_requests(state, &body.execution_requests, config)?; + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Block processing +// --------------------------------------------------------------------------- + +/// Electra's block processing. +/// +/// The specification's own order: header, withdrawals, execution payload, +/// RANDAO, eth1 vote, operations, sync aggregate; unchanged from capella and +/// deneb (see `crate::beacon::stf::capella::process_block`'s own documentation for +/// why the sweep runs ahead of `bls_to_execution_changes`, one of this same +/// block's own operations). [`super::block::process_block_header`], +/// [`super::block::process_randao`], and [`super::block::process_eth1_data`] +/// are reused unchanged: none of the three reads anything beyond the +/// fork-invariant fields every block shares, which is the whole point of +/// them taking those fields directly rather than a whole body (see +/// `crate::beacon::stf`'s module documentation). [`super::altair::process_sync_aggregate`] +/// is reused the same way, for the same reason. +pub fn process_block( + state: &mut BeaconState, + block: &electra::BeaconBlock, + config: &Config, + engine: &ExecutionEngine, +) -> Result<()> { + super::block::process_block_header( + state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + )?; + process_withdrawals(state, &block.body.execution_payload)?; + process_execution_payload(state, &block.body, config, engine)?; + super::block::process_randao(state, &block.body.randao_reveal)?; + super::block::process_eth1_data(state, &block.body.eth1_data)?; + process_operations(state, &block.body, config)?; + super::altair::process_sync_aggregate(state, &block.body.sync_aggregate)?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::fork::ForkName; + + /// An electra state with `count` fully active validators, each with + /// [`preset::MIN_ACTIVATION_BALANCE`] and an eth1 withdrawal credential, + /// positioned many epochs in (see the `SHARD_COMMITTEE_PERIOD` note + /// below) so the previous epoch and the block-root history window both + /// have entries. + /// + /// Built on the shared fork-parameterised builder (see + /// [`crate::beacon::helpers::test_state::with_validators_at`]) and then given the + /// two overrides this module's own tests need beyond that default: every + /// validator here gets a real, distinguishable eth1 credential + /// (`ETH1_ADDRESS_WITHDRAWAL_PREFIX` followed by the validator's own + /// index, so [`source_address`] can build a request that matches it), + /// where the shared builder leaves every validator's credentials at + /// their default (all-zero, BLS-form) value; and this state sits far + /// more than `SHARD_COMMITTEE_PERIOD` epochs past genesis, since + /// [`process_withdrawal_request`] and [`process_consolidation_request`] + /// both gate on a validator having been active that long, where the + /// shared builder's own default callers never need to clear that bar. + fn electra_state_with_validators(count: usize) -> BeaconState { + let mut state = + crate::beacon::helpers::test_state::with_validators_at(ForkName::Electra, count); + + // Comfortably past `SHARD_COMMITTEE_PERIOD` for both mainnet (256 + // epochs) and minimal (64 epochs) configs, so every validator + // (active since genesis by the shared builder's own construction) is + // already eligible for an exit or a consolidation by the time a test + // runs one against it. + const EPOCHS_PAST_GENESIS: u64 = 300; + *state.slot_mut() = EPOCHS_PAST_GENESIS * preset::SLOTS_PER_EPOCH; + + for index in 0..count as ValidatorIndex { + let validator = state.validator_mut(index).unwrap(); + // Distinct per validator: the shared builder's all-zero pubkey + // would otherwise make every validator indistinguishable to a + // pubkey lookup, which is exactly how the request functions + // under test resolve + // `validator_pubkey`/`source_pubkey`/`target_pubkey` into an + // index. + validator.pubkey = BlsPubkey([index as u8; 48]); + validator.withdrawal_credentials.0[0] = constants::ETH1_ADDRESS_WITHDRAWAL_PREFIX; + validator.withdrawal_credentials.0[31] = index as u8; + } + state + } + + /// The execution address [`electra_state_with_validators`] derived + /// validator `index`'s withdrawal credentials from, i.e. the + /// `source_address` a request against that validator must carry to pass + /// [`has_execution_withdrawal_credential`]'s address check. + fn source_address(index: ValidatorIndex) -> ExecutionAddress { + let mut bytes = [0u8; 20]; + bytes[19] = index as u8; + ExecutionAddress::from_slice(&bytes) + } + + // -- process_withdrawal_request ----------------------------------------- + + #[test] + fn a_full_exit_request_for_an_unknown_pubkey_is_silently_dropped() { + let mut state = electra_state_with_validators(4); + let config = Config::mainnet(); + let before = state.clone(); + + let request = electra::WithdrawalRequest { + source_address: source_address(0), + validator_pubkey: BlsPubkey([0xff; 48]), + amount: constants::FULL_EXIT_REQUEST_AMOUNT, + }; + process_withdrawal_request(&mut state, &request, &config) + .expect("an unresolved pubkey is dropped silently, not rejected"); + assert_eq!( + state, before, + "no validator should have been touched for a pubkey nobody holds" + ); + } + + #[test] + fn a_request_with_the_wrong_source_address_is_silently_dropped() { + let mut state = electra_state_with_validators(4); + let config = Config::mainnet(); + let pubkey = state.validator(0).unwrap().pubkey; + let before = state.clone(); + + let request = electra::WithdrawalRequest { + // Validator 0's real credentials point at `source_address(0)`, + // not this one. + source_address: source_address(1), + validator_pubkey: pubkey, + amount: constants::FULL_EXIT_REQUEST_AMOUNT, + }; + process_withdrawal_request(&mut state, &request, &config) + .expect("a mismatched source address is dropped silently, not rejected"); + assert_eq!(state, before, "no validator should have been touched"); + } + + #[test] + fn a_full_exit_request_exits_a_matching_active_validator() { + let mut state = electra_state_with_validators(4); + let config = Config::mainnet(); + let pubkey = state.validator(0).unwrap().pubkey; + + let request = electra::WithdrawalRequest { + source_address: source_address(0), + validator_pubkey: pubkey, + amount: constants::FULL_EXIT_REQUEST_AMOUNT, + }; + process_withdrawal_request(&mut state, &request, &config).unwrap(); + + assert_ne!( + state.validator(0).unwrap().exit_epoch, + FAR_FUTURE_EPOCH, + "a full exit request against a validator with nothing pending must exit it" + ); + } + + /// Gated to `preset-minimal` only: mainnet's own + /// `PENDING_PARTIAL_WITHDRAWALS_LIMIT` is large enough (a fraction over + /// a hundred million) that actually building a queue at that literal + /// size would allocate several gigabytes and take seconds, for a check + /// that adds nothing over exercising the identical code path at + /// minimal's much smaller limit. This still runs, just not under the + /// default `cargo test` invocation this module's own task list uses, + /// which is why `preset::MIN_ACTIVATION_BALANCE` and friends throughout + /// this file are written against whichever preset is active rather than + /// hardcoded, the same as everywhere else in this module. + #[test] + #[cfg(feature = "preset-minimal")] + fn a_full_queue_silently_drops_a_partial_request_but_not_a_full_exit() { + let mut state = electra_state_with_validators(2); + let config = Config::mainnet(); + + // Fill the pending-partial-withdrawals queue to its literal limit; + // only practical because this test is gated to the minimal preset, + // whose PENDING_PARTIAL_WITHDRAWALS_LIMIT is small. See this + // function's own documentation. + { + let mut fields = block_mut(&mut state, "test setup").unwrap(); + let queue = fields.pending_partial_withdrawals_mut(); + for _ in 0..preset::PENDING_PARTIAL_WITHDRAWALS_LIMIT { + queue + .push(electra::PendingPartialWithdrawal { + validator_index: 0, + amount: 1, + withdrawable_epoch: 0, + }) + .unwrap(); + } + } + let pubkey = state.validator(1).unwrap().pubkey; + let before_full_queue_len = block_mut(&mut state, "test assertion") + .unwrap() + .pending_partial_withdrawals_mut() + .len(); + assert_eq!( + before_full_queue_len, + preset::PENDING_PARTIAL_WITHDRAWALS_LIMIT + ); + + // A partial request against the full queue: silently dropped. + let partial_request = electra::WithdrawalRequest { + source_address: source_address(1), + validator_pubkey: pubkey, + amount: 1, + }; + process_withdrawal_request(&mut state, &partial_request, &config) + .expect("a full queue drops a partial request silently, not with an error"); + assert_eq!( + block_mut(&mut state, "test assertion") + .unwrap() + .pending_partial_withdrawals_mut() + .len(), + preset::PENDING_PARTIAL_WITHDRAWALS_LIMIT, + "the queue must not have grown" + ); + + // A full exit request against the same validator: not gated by the + // queue at all, since it never uses it. + let full_exit_request = electra::WithdrawalRequest { + source_address: source_address(1), + validator_pubkey: pubkey, + amount: constants::FULL_EXIT_REQUEST_AMOUNT, + }; + process_withdrawal_request(&mut state, &full_exit_request, &config).unwrap(); + assert_ne!( + state.validator(1).unwrap().exit_epoch, + FAR_FUTURE_EPOCH, + "a full exit request must not be blocked by a full partial-withdrawal queue" + ); + } + + #[test] + fn a_full_exit_request_ignores_the_partial_withdrawals_queue_entirely() { + // The cross-preset counterpart of the `preset-minimal`-only test + // above: rather than filling the queue to its literal (and, under + // mainnet, impractically large) limit, this only has to show that + // `is_full_exit_request`'s branch never even reads + // `pending_partial_withdrawals_len`, by pushing one placeholder + // entry and confirming the exit still succeeds. + let mut state = electra_state_with_validators(2); + let config = Config::mainnet(); + block_mut(&mut state, "test setup") + .unwrap() + .pending_partial_withdrawals_mut() + .push(electra::PendingPartialWithdrawal { + validator_index: 0, + amount: 1, + withdrawable_epoch: 0, + }) + .unwrap(); + let pubkey = state.validator(1).unwrap().pubkey; + + let full_exit_request = electra::WithdrawalRequest { + source_address: source_address(1), + validator_pubkey: pubkey, + amount: constants::FULL_EXIT_REQUEST_AMOUNT, + }; + process_withdrawal_request(&mut state, &full_exit_request, &config).unwrap(); + assert_ne!( + state.validator(1).unwrap().exit_epoch, + FAR_FUTURE_EPOCH, + "a full exit request must not consult the partial-withdrawals queue length at all" + ); + } + + #[test] + fn a_compounding_validator_with_excess_balance_gets_a_partial_withdrawal_queued() { + let mut state = electra_state_with_validators(2); + let config = Config::mainnet(); + { + let validator = state.validator_mut(0).unwrap(); + validator.withdrawal_credentials.0[0] = constants::COMPOUNDING_WITHDRAWAL_PREFIX; + validator.effective_balance = preset::MIN_ACTIVATION_BALANCE; + } + state.balances_mut()[0] = preset::MIN_ACTIVATION_BALANCE + 1_000_000_000; + let pubkey = state.validator(0).unwrap().pubkey; + + let request = electra::WithdrawalRequest { + source_address: source_address(0), + validator_pubkey: pubkey, + amount: 500_000_000, + }; + process_withdrawal_request(&mut state, &request, &config).unwrap(); + + let queued = + crate::beacon::helpers::electra::get_pending_balance_to_withdraw(&state, 0).unwrap(); + assert_eq!( + queued, 500_000_000, + "the request's own amount, capped at the validator's actual excess, must be queued" + ); + } + + #[test] + fn a_noncompounding_validator_gets_no_partial_withdrawal_queued() { + // Validator 0 keeps its eth1 (not compounding) credential from + // `electra_state_with_validators`: only a compounding validator may + // take a partial withdrawal through this path (a non-compounding one + // must use a full exit instead), so this must fall through and queue + // nothing even with genuine excess balance. + let mut state = electra_state_with_validators(2); + let config = Config::mainnet(); + state.balances_mut()[0] = preset::MIN_ACTIVATION_BALANCE + 1_000_000_000; + let pubkey = state.validator(0).unwrap().pubkey; + + let request = electra::WithdrawalRequest { + source_address: source_address(0), + validator_pubkey: pubkey, + amount: 500_000_000, + }; + process_withdrawal_request(&mut state, &request, &config).unwrap(); + + let queued = + crate::beacon::helpers::electra::get_pending_balance_to_withdraw(&state, 0).unwrap(); + assert_eq!( + queued, 0, + "a non-compounding validator has no partial-withdrawal route" + ); + } + + // -- process_consolidation_request -------------------------------------- + + #[test] + fn a_self_consolidation_switches_the_validator_to_compounding() { + let mut state = electra_state_with_validators(2); + let config = Config::mainnet(); + let pubkey = state.validator(0).unwrap().pubkey; + + let request = electra::ConsolidationRequest { + source_address: source_address(0), + source_pubkey: pubkey, + target_pubkey: pubkey, + }; + process_consolidation_request(&mut state, &request, &config).unwrap(); + + assert!(has_compounding_withdrawal_credential( + state.validator(0).unwrap() + )); + assert!( + block_mut(&mut state, "test assertion") + .unwrap() + .pending_consolidations_mut() + .is_empty(), + "a switch-to-compounding request is not a real consolidation and must not queue one" + ); + } + + #[test] + fn a_self_consolidation_with_the_wrong_source_address_is_silently_dropped() { + let mut state = electra_state_with_validators(2); + let config = Config::mainnet(); + let pubkey = state.validator(0).unwrap().pubkey; + let before = state.clone(); + + let request = electra::ConsolidationRequest { + // Does not match validator 0's real credentials, so this is + // neither a valid switch-to-compounding request nor (since + // source == target) a real consolidation. + source_address: source_address(1), + source_pubkey: pubkey, + target_pubkey: pubkey, + }; + process_consolidation_request(&mut state, &request, &config) + .expect("neither branch applies, so this must be a silent no-op, not an error"); + assert_eq!(state, before, "no validator should have been touched"); + } + + #[test] + fn a_full_pending_consolidations_queue_silently_drops_a_real_consolidation() { + let mut state = electra_state_with_validators(2); + let config = Config::mainnet(); + { + let mut fields = block_mut(&mut state, "test setup").unwrap(); + let queue = fields.pending_consolidations_mut(); + for _ in 0..preset::PENDING_CONSOLIDATIONS_LIMIT { + queue + .push(electra::PendingConsolidation { + source_index: 0, + target_index: 0, + }) + .unwrap(); + } + } + { + let validator = state.validator_mut(1).unwrap(); + validator.withdrawal_credentials.0[0] = constants::COMPOUNDING_WITHDRAWAL_PREFIX; + } + let source_pubkey = state.validator(0).unwrap().pubkey; + let target_pubkey = state.validator(1).unwrap().pubkey; + let before_len = block_mut(&mut state, "test assertion") + .unwrap() + .pending_consolidations_mut() + .len(); + + let request = electra::ConsolidationRequest { + source_address: source_address(0), + source_pubkey, + target_pubkey, + }; + process_consolidation_request(&mut state, &request, &config) + .expect("a full queue drops the request silently, not with an error"); + + assert_eq!( + block_mut(&mut state, "test assertion") + .unwrap() + .pending_consolidations_mut() + .len(), + before_len, + "the queue must not have grown past its limit" + ); + assert_eq!( + state.validator(0).unwrap().exit_epoch, + FAR_FUTURE_EPOCH, + "the source validator must not have been exited either" + ); + } + + /// Uses 200 validators and [`Config::minimal`], not the two-validator + /// state (and `Config::mainnet`) this module's other request tests use. + /// `get_consolidation_churn_limit` splits `get_balance_churn_limit` + /// (proportional to total active balance) between activations/exits and + /// consolidations, capping the former at + /// `Config::max_per_epoch_activation_exit_churn_limit`; with only two + /// validators' worth of active balance, that cap consumes the *entire* + /// churn budget under either config, leaving a genuine consolidation + /// nothing to spend and this same silent-return chain drops it just as + /// the full-queue case does. Mainnet's own `Config::churn_limit_quotient` + /// (in the tens of thousands) would need on the order of half a million + /// validators' worth of active balance before any is left over for + /// consolidations; minimal's much smaller quotient reaches that same + /// point around 200, which is what this test actually builds. + #[test] + fn a_valid_consolidation_request_queues_a_pending_consolidation_and_exits_the_source() { + let mut state = electra_state_with_validators(200); + let config = Config::minimal(); + { + let validator = state.validator_mut(1).unwrap(); + validator.withdrawal_credentials.0[0] = constants::COMPOUNDING_WITHDRAWAL_PREFIX; + } + let source_pubkey = state.validator(0).unwrap().pubkey; + let target_pubkey = state.validator(1).unwrap().pubkey; + + let request = electra::ConsolidationRequest { + source_address: source_address(0), + source_pubkey, + target_pubkey, + }; + process_consolidation_request(&mut state, &request, &config).unwrap(); + + assert_ne!( + state.validator(0).unwrap().exit_epoch, + FAR_FUTURE_EPOCH, + "a genuine consolidation must start the source validator's exit" + ); + let queue_len = block_mut(&mut state, "test assertion") + .unwrap() + .pending_consolidations_mut() + .len(); + assert_eq!(queue_len, 1, "the consolidation must have been queued"); + } + + // -- apply_deposit / process_deposit ------------------------------------- + + #[test] + fn a_new_validators_deposit_is_queued_rather_than_credited_directly() { + let mut state = electra_state_with_validators(1); + let config = Config::mainnet(); + let count_before = state.validators().len(); + + let pubkey = BlsPubkey([9; 48]); + let signature = BlsSignature::default(); + // An invalid signature: `apply_deposit` must still register the + // validator, since `is_valid_deposit_signature` is checked + // separately and this test is not exercising it. Use a signature + // that happens to be valid would require real key generation for no + // benefit here. + let withdrawal_credentials = Bytes32::ZERO; + + apply_deposit( + &mut state, + pubkey, + withdrawal_credentials, + 32_000_000_000, + &signature, + &config, + ) + .unwrap(); + + // An invalid signature means the deposit is not credited to a new + // validator at all: see `apply_deposit`'s own documentation. + assert_eq!(state.validators().len(), count_before); + assert!( + crate::beacon::helpers::electra::electra_state_ref(&state, "test assertion") + .unwrap() + .pending_partial_withdrawals() + .is_empty(), + "unrelated to this test, sanity check only" + ); + } + + #[test] + fn get_expected_withdrawals_reports_how_many_pending_partial_withdrawals_it_consumed() { + let mut state = electra_state_with_validators(2); + // Two pending partial withdrawals, both already due: the sweep must + // report having consumed both, regardless of whether either produced + // an actual `Withdrawal`. + { + let mut fields = block_mut(&mut state, "test setup").unwrap(); + let queue = fields.pending_partial_withdrawals_mut(); + queue + .push(electra::PendingPartialWithdrawal { + validator_index: 0, + amount: 1, + withdrawable_epoch: 0, + }) + .unwrap(); + queue + .push(electra::PendingPartialWithdrawal { + validator_index: 1, + amount: 1, + withdrawable_epoch: 0, + }) + .unwrap(); + } + // Neither validator has excess balance above MIN_ACTIVATION_BALANCE, + // so neither pending withdrawal actually produces a `Withdrawal`; + // the count returned is still 2. + let (withdrawals, processed_partial_withdrawals_count) = + get_expected_withdrawals(&state).unwrap(); + assert!(withdrawals.is_empty()); + assert_eq!(processed_partial_withdrawals_count, 2); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/epoch/altair.rs b/crates/blockchain/state_transition/src/beacon/stf/epoch/altair.rs new file mode 100644 index 000000000..1b2f07320 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/epoch/altair.rs @@ -0,0 +1,498 @@ +//! Altair-specific epoch processing. +//! +//! Altair keeps every phase0 step that does not touch attestation accounting +//! unchanged (registry updates, slashings, the four resets, the historical +//! roots roll-up) and replaces the rest: justification now reads participation +//! flags instead of `PendingAttestation`s, rewards score those same flags +//! instead of replaying attestations, and three steps are new outright: +//! [`process_inactivity_updates`] (the running per-validator score the leak +//! penalty scales from), [`process_participation_flag_updates`] (the rotation +//! that gives the reward accounting its two-epoch window), and +//! [`process_sync_committee_updates`] (rotating in the next sync committee at +//! each period boundary). [`process_epoch`] below is the driver, transcribed +//! from the specification's own list in the order it gives them; that order is +//! load-bearing in the same two places [`super`]'s phase0 driver documents, +//! plus one more altair adds: [`process_inactivity_updates`] must run before +//! [`process_rewards_and_penalties`], since the inactivity penalty scales by +//! the score the former just updated, not by whatever it held a step earlier. + +use crate::beacon::config::Config; +use crate::beacon::constants; +use crate::beacon::containers::BeaconState; +use crate::beacon::error::{Error, Result}; +use crate::beacon::helpers::accessors::{ + get_current_epoch, get_previous_epoch, get_total_active_balance, get_total_balance, +}; +use crate::beacon::helpers::altair::{ + get_flag_index_deltas, get_inactivity_penalty_deltas, get_next_sync_committee, + get_unslashed_participating_indices, +}; +use crate::beacon::helpers::finality::{get_eligible_validator_indices, is_in_inactivity_leak}; +use crate::beacon::helpers::math::saturating_sub; +use crate::beacon::helpers::mutators::{decrease_balance, increase_balance}; +use crate::beacon::preset; +use crate::beacon::primitives::ValidatorIndex; + +use super::justification::weigh_justification_and_finalization; + +/// Runs every altair epoch-boundary step, in the specification's order. +/// +/// Delegates every step the specification does not modify in altair +/// (registry updates, slashings, the four resets, the historical roots +/// update) to the fork-shared functions in [`super`], and substitutes +/// altair's own version of the rest. +pub fn process_epoch(state: &mut BeaconState, config: &Config) -> Result<()> { + process_justification_and_finalization(state)?; + process_inactivity_updates(state, config)?; + process_rewards_and_penalties(state, config)?; + super::registry::process_registry_updates(state, config)?; + super::registry::process_slashings(state, config)?; + super::process_eth1_data_reset(state)?; + super::process_effective_balance_updates(state)?; + super::process_slashings_reset(state)?; + super::process_randao_mixes_reset(state)?; + super::process_historical_roots_update(state)?; + process_participation_flag_updates(state)?; + process_sync_committee_updates(state)?; + Ok(()) +} + +/// Updates justification and finality from how much active balance cast a +/// timely, correct target vote for the previous and current epoch. +/// +/// The only difference from phase0's version: the two target balances come +/// from [`get_unslashed_participating_indices`] over the epoch's participation +/// flags rather than from matching stored `PendingAttestation`s against the +/// block root history. Once those two balances are in hand, the actual +/// bitfield and finality bookkeeping is identical, so this hands off to +/// [`weigh_justification_and_finalization`], the same function phase0 calls. +pub fn process_justification_and_finalization(state: &mut BeaconState) -> Result<()> { + // Initial FFG checkpoint values have a `0x00` stub for `root`. Skip FFG + // updates in the first two epochs to avoid corner cases that might result + // in modifying this stub. + if get_current_epoch(state) <= constants::GENESIS_EPOCH + 1 { + return Ok(()); + } + + let previous_indices = get_unslashed_participating_indices( + state, + constants::TIMELY_TARGET_FLAG_INDEX, + get_previous_epoch(state), + )?; + let current_indices = get_unslashed_participating_indices( + state, + constants::TIMELY_TARGET_FLAG_INDEX, + get_current_epoch(state), + )?; + let total_active_balance = get_total_active_balance(state)?; + let previous_target_balance = get_total_balance(state, &previous_indices)?; + let current_target_balance = get_total_balance(state, ¤t_indices)?; + weigh_justification_and_finalization( + state, + total_active_balance, + previous_target_balance, + current_target_balance, + ) +} + +/// Updates every eligible validator's inactivity score from its previous +/// epoch's timely-target participation. +/// +/// The score is a validator's own running memory of missed target votes: it +/// rises by [`Config::inactivity_score_bias`] for an epoch it misses, and +/// falls back down (by one for participating, and by +/// [`Config::inactivity_score_recovery_rate`] more whenever the chain is not +/// leaking) the moment it returns. That per-validator memory is what makes +/// [`crate::beacon::helpers::altair::get_inactivity_penalty_deltas`]'s leak penalty +/// proportional to an individual's own record of absence rather than to a +/// single chain-wide severity shared by everyone: two validators who have been +/// offline for different lengths of time pay different penalties even if the +/// leak itself is the same age for both. +/// +/// Skipped at the genesis epoch, since the score update reads the previous +/// epoch's participation and genesis has none. +pub fn process_inactivity_updates(state: &mut BeaconState, config: &Config) -> Result<()> { + if get_current_epoch(state) == constants::GENESIS_EPOCH { + return Ok(()); + } + + // Every read below needs `&BeaconState`, so they all run before this takes + // the mutable borrow `inactivity_scores` requires: `altair_validator_lists_mut` + // borrows the whole state, and there is no way to hold that mutably while + // also calling `get_eligible_validator_indices`, `get_unslashed_participating_indices`, + // or `is_in_inactivity_leak`, each of which needs its own `&BeaconState`. + // `process_effective_balance_updates` in the parent module resolves the + // identical conflict the same way: decide everything in one pass over + // immutable state, then apply it in a second pass over a mutable borrow. + let eligible_indices = get_eligible_validator_indices(state); + let previous_epoch = get_previous_epoch(state); + let participating_indices = get_unslashed_participating_indices( + state, + constants::TIMELY_TARGET_FLAG_INDEX, + previous_epoch, + )?; + let leaking = is_in_inactivity_leak(state); + + let (_, _, inactivity_scores) = state.altair_validator_lists_mut()?; + let score_count = inactivity_scores.len(); + for index in eligible_indices { + let score = inactivity_scores + .get_mut(index as usize) + .ok_or(Error::IndexOutOfBounds { + index: index as usize, + len: score_count, + })?; + + // `participating_indices` is ascending and duplicate-free (see + // `get_unslashed_participating_indices`), so membership is a binary + // search rather than a linear scan. + if participating_indices.binary_search(&index).is_ok() { + // `x -= min(1, x)`, written with `saturating_sub` so a + // already-zero score cannot underflow. + *score = saturating_sub(*score, 1); + } else { + // The specification treats a `uint64` overflow here as an invalid + // state rather than a wrapped one, so this is checked rather than + // left to release-mode wrapping. + *score = score.checked_add(config.inactivity_score_bias).ok_or( + Error::ArithmeticOverflow("inactivity_scores[index] + INACTIVITY_SCORE_BIAS"), + )?; + } + + if !leaking { + *score = saturating_sub(*score, config.inactivity_score_recovery_rate); + } + } + + Ok(()) +} + +/// Applies the epoch's flag-index and inactivity deltas to every validator's +/// balance. +/// +/// Altair's version of this step: phase0 sums four attestation-shaped delta +/// functions (source, target, head, inclusion delay) plus one inactivity +/// penalty; altair instead sums one delta per participation flag (weighted by +/// [`constants::PARTICIPATION_FLAG_WEIGHTS`]) plus the same kind of inactivity +/// penalty, computed from [`crate::beacon::helpers::altair::get_inactivity_penalty_deltas`] +/// against the scores [`process_inactivity_updates`] just brought up to date. +/// Applying rewards and penalties as two separate passes (through +/// [`increase_balance`] and [`decrease_balance`], not one netted delta) is +/// unchanged from phase0, and for the same reason: [`decrease_balance`] floors +/// at zero, so netting first would let a reward mask a penalty that should +/// have driven a low balance all the way down. +/// +/// Skipped entirely at the genesis epoch: rewards pay for participation +/// recorded during the previous epoch, and genesis has none. +pub fn process_rewards_and_penalties(state: &mut BeaconState, config: &Config) -> Result<()> { + if get_current_epoch(state) == constants::GENESIS_EPOCH { + return Ok(()); + } + + let mut deltas = Vec::with_capacity(constants::PARTICIPATION_FLAG_WEIGHTS.len() + 1); + for flag_index in 0..constants::PARTICIPATION_FLAG_WEIGHTS.len() { + deltas.push(get_flag_index_deltas(state, flag_index)?); + } + deltas.push(get_inactivity_penalty_deltas(state, config)?); + + let validator_count = state.validators().len() as ValidatorIndex; + for (rewards, penalties) in deltas { + for index in 0..validator_count { + increase_balance(state, index, rewards[index as usize])?; + decrease_balance(state, index, penalties[index as usize])?; + } + } + Ok(()) +} + +/// Rotates the current epoch's participation flags into the previous slot and +/// installs a fresh, all-zero current list. +/// +/// This is what gives the reward accounting a two-epoch window without +/// storing whole attestations the way phase0 does: a flag set at processing +/// time survives exactly one more epoch boundary (as +/// `previous_epoch_participation`, read by the next epoch's rewards and +/// justification) and then this drops it, so the state never holds more than +/// two epochs of participation regardless of how long the chain runs. +/// +/// The fresh current list is sized to the validator registry, not left empty: +/// every validator (including one that just activated) needs a flag slot from +/// the moment it can be attested for, and `process_attestation` (not +/// implemented in this file) indexes into it directly rather than appending. +pub fn process_participation_flag_updates(state: &mut BeaconState) -> Result<()> { + let validator_count = state.validators().len(); + let (previous_epoch_participation, current_epoch_participation, _) = + state.altair_validator_lists_mut()?; + + *previous_epoch_participation = core::mem::take(current_epoch_participation); + *current_epoch_participation = vec![0; validator_count].try_into()?; + + Ok(()) +} + +/// Rotates in the next sync committee at each sync committee period boundary. +/// +/// Only fires once every [`preset::EPOCHS_PER_SYNC_COMMITTEE_PERIOD`] epochs; +/// every other epoch this is a no-op, since `current_sync_committee` and +/// `next_sync_committee` are otherwise left exactly as they were. Computing +/// the new `next_sync_committee` before touching either field (rather than +/// computing it after `current_sync_committee` has already been overwritten) +/// matters because [`get_next_sync_committee`] reads the validator registry, +/// not either committee field, so the order is safe either way for +/// correctness; it is still done first here so the fallible call happens +/// before any mutation, leaving the state untouched if it errors. +pub fn process_sync_committee_updates(state: &mut BeaconState) -> Result<()> { + let next_epoch = get_current_epoch(state) + 1; + if next_epoch.is_multiple_of(preset::EPOCHS_PER_SYNC_COMMITTEE_PERIOD) { + let next_committee = get_next_sync_committee(state)?; + let (current_sync_committee, next_sync_committee) = state.sync_committees_mut()?; + *current_sync_committee = core::mem::replace(next_sync_committee, next_committee); + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::fork::ForkName; + use crate::beacon::helpers::altair::add_flag; + use crate::beacon::primitives::BlsPubkey; + + /// A deterministic but genuinely valid BLS public key for validator + /// `index`. + /// + /// [`process_sync_committee_updates`] aggregates every validator's pubkey + /// through [`get_next_sync_committee`], and a zero pubkey is not a curve + /// point, so an all-default validator would make that aggregation fail + /// rather than exercise the rotation this module is testing. + fn pubkey_for(index: usize) -> BlsPubkey { + let mut ikm = [0u8; 32]; + ikm[..8].copy_from_slice(&(index as u64 + 1).to_le_bytes()); + let secret = blst::min_pk::SecretKey::key_gen(&ikm, &[]) + .expect("32 bytes of input material is enough for key generation"); + BlsPubkey(secret.sk_to_pk().to_bytes()) + } + + /// An altair state with `count` fully active, full-balance validators, + /// positioned one epoch in, the same way + /// `crate::beacon::helpers::test_state::with_validators` positions its phase0 + /// state. + /// + /// Built on the shared fork-parameterised builder (see + /// [`crate::beacon::helpers::test_state::with_validators_at`]) and then given + /// real, distinguishable BLS pubkeys: [`process_sync_committee_updates`] + /// aggregates every validator's pubkey through + /// [`get_next_sync_committee`], and the shared builder's all-default + /// pubkey is not a curve point, which would make that aggregation fail + /// rather than exercise the rotation this module is testing. + fn altair_state_with_validators(count: usize) -> BeaconState { + let mut state = + crate::beacon::helpers::test_state::with_validators_at(ForkName::Altair, count); + for index in 0..count as ValidatorIndex { + state.validator_mut(index).unwrap().pubkey = pubkey_for(index as usize); + } + state + } + + // ----------------------------------------------------------------------- + // process_justification_and_finalization + // ----------------------------------------------------------------------- + + #[test] + fn justification_near_genesis_is_a_no_op() { + // Positioned at current epoch 1, still within the `GENESIS_EPOCH + 1` + // guard. + let mut state = altair_state_with_validators(4); + let before = state.clone(); + + process_justification_and_finalization(&mut state).unwrap(); + + assert_eq!(state.justification_bits(), before.justification_bits()); + assert_eq!( + state.current_justified_checkpoint(), + before.current_justified_checkpoint() + ); + } + + #[test] + fn justification_reads_target_balance_from_participation_flags() { + let mut state = altair_state_with_validators(4); + *state.slot_mut() = preset::SLOTS_PER_EPOCH * 2; // current epoch 2, previous epoch 1 + + // Every validator cast a timely, correct target vote last epoch, but + // none has yet this epoch: only the previous epoch should justify. + { + let (previous_epoch_participation, _, _) = state.altair_validator_lists_mut().unwrap(); + for flags in previous_epoch_participation.iter_mut() { + *flags = add_flag(*flags, constants::TIMELY_TARGET_FLAG_INDEX); + } + } + + process_justification_and_finalization(&mut state).unwrap(); + + let bits = state.justification_bits(); + assert_eq!(bits.get(0), Some(false), "current epoch did not justify"); + assert_eq!(bits.get(1), Some(true), "previous epoch justified"); + assert_eq!(state.current_justified_checkpoint().epoch, 1); + } + + // ----------------------------------------------------------------------- + // process_inactivity_updates + // ----------------------------------------------------------------------- + + #[test] + fn inactivity_updates_are_a_no_op_at_genesis() { + let mut state = altair_state_with_validators(4); + *state.slot_mut() = 0; + let (_, _, scores) = state.altair_validator_lists().unwrap(); + let before = scores.clone(); + + process_inactivity_updates(&mut state, &Config::mainnet()).unwrap(); + + let (_, _, scores) = state.altair_validator_lists().unwrap(); + assert_eq!(*scores, before); + } + + #[test] + fn inactivity_updates_diverge_by_participation_during_a_leak() { + let config = Config::mainnet(); + let mut state = altair_state_with_validators(4); + // Push the previous epoch far enough past the (still-genesis) + // finalized checkpoint to be a leak, matching how + // `rewards.rs`'s `finality_stalled_past_the_threshold_is_a_leak` test + // forces the same condition. + *state.slot_mut() = + preset::SLOTS_PER_EPOCH * (preset::MIN_EPOCHS_TO_INACTIVITY_PENALTY + 10); + + { + let (previous_epoch_participation, _, inactivity_scores) = + state.altair_validator_lists_mut().unwrap(); + inactivity_scores[0] = 10; + inactivity_scores[1] = 10; + // Validator 0 participated last epoch; validator 1 did not. + previous_epoch_participation[0] = add_flag(0, constants::TIMELY_TARGET_FLAG_INDEX); + } + + process_inactivity_updates(&mut state, &config).unwrap(); + + let (_, _, scores) = state.altair_validator_lists().unwrap(); + // Participating: score falls by one; during a leak nothing recovers + // it further. + assert_eq!(scores[0], 9); + // Not participating: score rises by the configured bias. + assert_eq!(scores[1], 10 + config.inactivity_score_bias); + } + + #[test] + fn inactivity_updates_recover_fully_outside_a_leak() { + let config = Config::mainnet(); + let mut state = altair_state_with_validators(4); + // The default position (current epoch 1, finalized checkpoint at + // epoch 0) is not a leak: `get_finality_delay` is zero. + + { + let (previous_epoch_participation, _, inactivity_scores) = + state.altair_validator_lists_mut().unwrap(); + inactivity_scores[0] = 5; + previous_epoch_participation[0] = add_flag(0, constants::TIMELY_TARGET_FLAG_INDEX); + } + + process_inactivity_updates(&mut state, &config).unwrap(); + + // One point off for participating, then the whole remainder recovers + // because the recovery rate outpaces a score this small. + let (_, _, scores) = state.altair_validator_lists().unwrap(); + assert_eq!(scores[0], 0); + } + + // ----------------------------------------------------------------------- + // process_rewards_and_penalties + // ----------------------------------------------------------------------- + + #[test] + fn rewards_and_penalties_are_a_no_op_at_genesis() { + let config = Config::mainnet(); + let mut state = altair_state_with_validators(4); + *state.slot_mut() = 0; + let balances_before = state.balances().clone(); + + process_rewards_and_penalties(&mut state, &config).unwrap(); + + assert_eq!( + state.balances(), + &balances_before, + "the genesis epoch has no previous epoch to reward" + ); + } + + // ----------------------------------------------------------------------- + // process_participation_flag_updates + // ----------------------------------------------------------------------- + + #[test] + fn participation_flag_updates_rotate_current_into_previous_and_reset_current() { + let mut state = altair_state_with_validators(4); + let current_before = { + let (_, current_epoch_participation, _) = state.altair_validator_lists_mut().unwrap(); + current_epoch_participation[0] = add_flag(0, constants::TIMELY_SOURCE_FLAG_INDEX); + current_epoch_participation[1] = add_flag(0, constants::TIMELY_HEAD_FLAG_INDEX); + current_epoch_participation.to_vec() + }; + + process_participation_flag_updates(&mut state).unwrap(); + + let (previous_epoch_participation, current_epoch_participation, _) = + state.altair_validator_lists().unwrap(); + assert_eq!(previous_epoch_participation.to_vec(), current_before); + assert_eq!(current_epoch_participation.len(), 4); + assert!( + current_epoch_participation.iter().all(|&flags| flags == 0), + "the fresh current list must start all-zero" + ); + } + + // ----------------------------------------------------------------------- + // process_sync_committee_updates + // ----------------------------------------------------------------------- + + #[test] + fn sync_committee_updates_are_a_no_op_off_the_period_boundary() { + // Current epoch 1: `next_epoch` (2) is not a multiple of + // `EPOCHS_PER_SYNC_COMMITTEE_PERIOD` on either preset. + let mut state = altair_state_with_validators(4); + let (before_current, before_next) = { + let (current, next) = state.sync_committees().unwrap(); + (current.clone(), next.clone()) + }; + + process_sync_committee_updates(&mut state).unwrap(); + + let (current, next) = state.sync_committees().unwrap(); + assert_eq!(*current, before_current); + assert_eq!(*next, before_next); + } + + #[test] + fn sync_committee_updates_rotate_at_the_period_boundary() { + let mut state = altair_state_with_validators(4); + // One epoch before a period boundary, so `next_epoch` lands exactly on + // it. + *state.slot_mut() = + preset::SLOTS_PER_EPOCH * (preset::EPOCHS_PER_SYNC_COMMITTEE_PERIOD - 1); + + let old_next = state.sync_committees().unwrap().1.clone(); + let expected_next = get_next_sync_committee(&state).unwrap(); + + process_sync_committee_updates(&mut state).unwrap(); + + let (current, next) = state.sync_committees().unwrap(); + assert_eq!( + *current, old_next, + "the old next committee takes over as current" + ); + assert_eq!( + *next, expected_next, + "a freshly drawn committee takes the next slot" + ); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/epoch/capella.rs b/crates/blockchain/state_transition/src/beacon/stf/epoch/capella.rs new file mode 100644 index 000000000..6a93c68b7 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/epoch/capella.rs @@ -0,0 +1,223 @@ +//! Capella-specific epoch processing. +//! +//! Capella's own `process_epoch` is otherwise altair's step list with one +//! swap: `process_historical_roots_update` is replaced by +//! [`process_historical_summaries_update`], since `historical_roots` is +//! frozen as of this fork (`state.historical_roots` keeps whatever bellatrix +//! left it at and is never appended to again) and `historical_summaries` +//! accumulates new history in its place. [`process_epoch`] below is +//! transcribed from the specification's own list, in the order it gives +//! them, which is the same order [`super::altair::process_epoch`] uses apart +//! from that one substitution; see [`super`]'s and `super::altair`'s own +//! documentation for why that order matters everywhere it is not just this +//! one swap. +//! +//! Deneb reuses this driver unchanged: its own "Epoch processing" section in +//! the specification says nothing at all, meaning deneb's `process_epoch` is +//! whatever the previous fork (capella) already defined. [`super::process_epoch`]'s +//! dispatcher already routes `ForkName::Deneb` here for exactly that reason, +//! so [`process_epoch`] and [`process_historical_summaries_update`] both +//! accept a deneb state as readily as a capella one rather than gating on +//! `ForkName::Capella` specifically; see [`historical_summaries_mut`] for +//! where that acceptance actually lives. + +use crate::beacon::config::Config; +use crate::beacon::containers::{BeaconState, HistoricalSummaries, HistoricalSummary}; +use crate::beacon::error::{Error, Result}; +use crate::beacon::helpers::accessors::get_current_epoch; +use crate::beacon::preset; +use crate::beacon::primitives::{Epoch, HashTreeRoot as _}; + +/// Capella's epoch-boundary driver, in the specification's order. +/// +/// Every step but one is altair's own, called through `super::altair` and +/// `super::registry` exactly as [`super::altair::process_epoch`] itself calls +/// them; the one exception is [`process_historical_summaries_update`] in +/// place of `super::process_historical_roots_update`. +pub fn process_epoch(state: &mut BeaconState, config: &Config) -> Result<()> { + super::altair::process_justification_and_finalization(state)?; + super::altair::process_inactivity_updates(state, config)?; + super::altair::process_rewards_and_penalties(state, config)?; + super::registry::process_registry_updates(state, config)?; + super::registry::process_slashings(state, config)?; + super::process_eth1_data_reset(state)?; + super::process_effective_balance_updates(state)?; + super::process_slashings_reset(state)?; + super::process_randao_mixes_reset(state)?; + // [Modified in Capella] + process_historical_summaries_update(state)?; + super::altair::process_participation_flag_updates(state)?; + super::altair::process_sync_committee_updates(state)?; + Ok(()) +} + +/// Folds the block and state root vectors into one [`HistoricalSummary`] when +/// they are about to wrap, capella's replacement for +/// `super::process_historical_roots_update`. +/// +/// [`HistoricalSummary`]'s two fields are `hash_tree_root(state.block_roots)` +/// and `hash_tree_root(state.state_roots)` taken directly, not the root of a +/// combined [`crate::beacon::containers::HistoricalBatch`] wrapping both: the +/// specification's own note that the two containers are hash-tree-root +/// compatible is what makes those the same two child roots either way, so a +/// verifier holding only one of the two forms can still check a historical +/// proof against either. +pub fn process_historical_summaries_update(state: &mut BeaconState) -> Result<()> { + let next_epoch = get_current_epoch(state) + 1; + let epochs_per_historical_root = + (preset::SLOTS_PER_HISTORICAL_ROOT / preset::SLOTS_PER_EPOCH as usize) as Epoch; + if next_epoch.is_multiple_of(epochs_per_historical_root) { + let summary = HistoricalSummary { + block_summary_root: state.block_roots().hash_tree_root(), + state_summary_root: state.state_roots().hash_tree_root(), + }; + historical_summaries_mut(state, "process_historical_summaries_update")?.push(summary)?; + } + Ok(()) +} + +/// The `historical_summaries` list, mutably, for any fork that carries it, or +/// an error naming the function that needs one. +/// +/// `historical_summaries` enters the state at capella and every later fork +/// keeps the identical field: deneb reuses this whole driver unchanged (see +/// this module's own documentation), and electra and fulu each fold this same +/// step into their own, larger driver rather than redefining it, since +/// neither fork's specification says anything about historical summaries at +/// all. Matching every variant that actually has the field, rather than only +/// [`BeaconState::Capella`], is what lets each of those reuse this function +/// instead of a copy of it. +fn historical_summaries_mut<'a>( + state: &'a mut BeaconState, + function: &'static str, +) -> Result<&'a mut HistoricalSummaries> { + match state { + BeaconState::Capella(state) => Ok(&mut state.historical_summaries), + BeaconState::Deneb(state) => Ok(&mut state.historical_summaries), + BeaconState::Electra(state) => Ok(&mut state.historical_summaries), + BeaconState::Fulu(state) => Ok(&mut state.historical_summaries), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::fork::ForkName; + + /// A capella state with `count` fully active, full-balance validators, + /// positioned one epoch in the same way + /// `crate::beacon::helpers::test_state::with_validators` positions its phase0 + /// state. + /// + /// A thin wrapper around the shared fork-parameterised builder: see + /// [`crate::beacon::helpers::test_state::with_validators_at`] for the construction + /// this and every other fork's test module used to duplicate. + fn capella_state_with_validators(count: usize) -> BeaconState { + crate::beacon::helpers::test_state::with_validators_at(ForkName::Capella, count) + } + + #[test] + fn historical_summaries_update_is_a_no_op_off_the_boundary() { + // Current epoch 1: `next_epoch` (2) is not a multiple of + // `SLOTS_PER_HISTORICAL_ROOT / SLOTS_PER_EPOCH` on either preset. + let mut state = capella_state_with_validators(4); + process_historical_summaries_update(&mut state).unwrap(); + + let inner = historical_summaries_mut(&mut state, "test assertion").unwrap(); + assert!(inner.is_empty()); + } + + #[test] + fn historical_summaries_update_appends_at_the_boundary_instead_of_historical_roots() { + let epochs_per_historical_root = + preset::SLOTS_PER_HISTORICAL_ROOT as u64 / preset::SLOTS_PER_EPOCH; + let mut state = capella_state_with_validators(4); + // One epoch before the boundary, so `next_epoch` lands exactly on it. + *state.slot_mut() = preset::SLOTS_PER_EPOCH * (epochs_per_historical_root - 1); + + let expected_block_summary_root = state.block_roots().hash_tree_root(); + let expected_state_summary_root = state.state_roots().hash_tree_root(); + + process_historical_summaries_update(&mut state).unwrap(); + + assert!( + state.historical_roots().is_empty(), + "capella must never append to historical_roots: it is frozen as of this fork" + ); + let summaries = historical_summaries_mut(&mut state, "test assertion").unwrap(); + assert_eq!(summaries.len(), 1); + assert_eq!(summaries[0].block_summary_root, expected_block_summary_root); + assert_eq!(summaries[0].state_summary_root, expected_state_summary_root); + } + + #[test] + fn historical_summaries_update_accepts_a_deneb_state_too() { + // `process_epoch` is dispatched for deneb states through this exact + // driver (`ForkName::Deneb => capella::process_epoch`), so the + // historical-summaries step it calls must not reject one. + let capella_state = capella_state_with_validators(2); + let deneb_state = if let BeaconState::Capella(inner) = capella_state { + crate::beacon::containers::deneb::BeaconState { + genesis_time: inner.genesis_time, + genesis_validators_root: inner.genesis_validators_root, + slot: preset::SLOTS_PER_HISTORICAL_ROOT as u64 - preset::SLOTS_PER_EPOCH, + fork: inner.fork, + latest_block_header: inner.latest_block_header, + block_roots: inner.block_roots, + state_roots: inner.state_roots, + historical_roots: inner.historical_roots, + eth1_data: inner.eth1_data, + eth1_data_votes: inner.eth1_data_votes, + eth1_deposit_index: inner.eth1_deposit_index, + validators: inner.validators, + balances: inner.balances, + randao_mixes: inner.randao_mixes, + slashings: inner.slashings, + previous_epoch_participation: inner.previous_epoch_participation, + current_epoch_participation: inner.current_epoch_participation, + justification_bits: inner.justification_bits, + previous_justified_checkpoint: inner.previous_justified_checkpoint, + current_justified_checkpoint: inner.current_justified_checkpoint, + finalized_checkpoint: inner.finalized_checkpoint, + inactivity_scores: inner.inactivity_scores, + current_sync_committee: inner.current_sync_committee, + next_sync_committee: inner.next_sync_committee, + latest_execution_payload_header: + crate::beacon::containers::deneb::ExecutionPayloadHeader { + parent_hash: inner.latest_execution_payload_header.parent_hash, + fee_recipient: inner.latest_execution_payload_header.fee_recipient, + state_root: inner.latest_execution_payload_header.state_root, + receipts_root: inner.latest_execution_payload_header.receipts_root, + logs_bloom: inner.latest_execution_payload_header.logs_bloom, + prev_randao: inner.latest_execution_payload_header.prev_randao, + block_number: inner.latest_execution_payload_header.block_number, + gas_limit: inner.latest_execution_payload_header.gas_limit, + gas_used: inner.latest_execution_payload_header.gas_used, + timestamp: inner.latest_execution_payload_header.timestamp, + extra_data: inner.latest_execution_payload_header.extra_data, + base_fee_per_gas: inner.latest_execution_payload_header.base_fee_per_gas, + block_hash: inner.latest_execution_payload_header.block_hash, + transactions_root: inner.latest_execution_payload_header.transactions_root, + withdrawals_root: inner.latest_execution_payload_header.withdrawals_root, + blob_gas_used: 0, + excess_blob_gas: 0, + }, + next_withdrawal_index: inner.next_withdrawal_index, + next_withdrawal_validator_index: inner.next_withdrawal_validator_index, + historical_summaries: inner.historical_summaries, + } + } else { + unreachable!() + }; + let mut state = BeaconState::Deneb(deneb_state); + + process_historical_summaries_update(&mut state).unwrap(); + + let summaries = historical_summaries_mut(&mut state, "test assertion").unwrap(); + assert_eq!(summaries.len(), 1); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/epoch/electra.rs b/crates/blockchain/state_transition/src/beacon/stf/epoch/electra.rs new file mode 100644 index 000000000..2f6bf9fcf --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/epoch/electra.rs @@ -0,0 +1,1254 @@ +//! Electra-specific epoch processing. +//! +//! Every earlier fork credits a deposit's balance the moment block processing +//! sees it, because every validator's effective balance was capped at the +//! same fixed value, so the only thing worth rate-limiting was how many +//! validators could activate in one epoch. EIP-7251 breaks that: a validator +//! with a compounding withdrawal credential can hold up to +//! [`preset::MAX_EFFECTIVE_BALANCE_ELECTRA`], dozens of times the old ceiling +//! ([`crate::beacon::helpers::electra::get_max_effective_balance`]), so a single +//! deposit or consolidation can now move as much voting weight as the old +//! count-based churn limit needed a whole epoch's worth of validators to +//! admit. Crediting it immediately would let that happen in one slot instead. +//! So electra queues both kinds of balance movement and drains each a +//! bounded amount per epoch instead of applying either at block-processing +//! time: [`process_pending_deposits`] rate-limits new stake by +//! [`crate::beacon::helpers::electra::get_activation_exit_churn_limit`]'s Gwei +//! budget, and [`process_pending_consolidations`] moves balance between +//! already-active validators, which is why the second one needs no churn +//! budget of its own (see its own doc for why). +//! +//! [`process_epoch`] is transcribed from the specification's own list, in the +//! order it gives them. Registry updates, slashings, and effective-balance +//! updates are electra's own rewrites ([`process_registry_updates`], +//! [`process_slashings`], and [`process_effective_balance_updates`]); the two +//! pending-queue steps are new outright; everything else is unmodified and +//! reused through `super::altair`, `super::registry`, `super::capella`, and +//! `super`. `process_slashings` looks, at a glance, like the same +//! "swap-the-constant" shape altair and bellatrix each use for this same +//! function (see `super::registry::process_slashings`'s own doc), but EIP-7251 +//! restructures the division itself rather than only raising a multiplier, so +//! that shared copy stops being correct here; see [`process_slashings`]'s own +//! doc for the arithmetic and a worked example of the two diverging. + +use crate::beacon::bls; +use crate::beacon::config::Config; +use crate::beacon::constants::{self, FAR_FUTURE_EPOCH}; +use crate::beacon::containers::shared::{DepositMessage, Validator}; +use crate::beacon::containers::{BeaconState, electra, fulu}; +use crate::beacon::error::{Error, Result}; +use crate::beacon::helpers::accessors::{get_current_epoch, get_total_active_balance}; +use crate::beacon::helpers::electra::{ + get_activation_exit_churn_limit, get_max_effective_balance, initiate_validator_exit, + is_eligible_for_activation_queue, +}; +use crate::beacon::helpers::misc::{ + compute_activation_exit_epoch, compute_deposit_domain, compute_signing_root, + compute_start_slot_at_epoch, +}; +use crate::beacon::helpers::mutators::{decrease_balance, increase_balance}; +use crate::beacon::helpers::predicates::{is_active_validator, is_eligible_for_activation}; +use crate::beacon::preset; +use crate::beacon::primitives::{ + BlsPubkey, BlsSignature, Bytes32, Epoch, Gwei, HashTreeRoot as _, ValidatorIndex, +}; + +/// Electra's epoch-boundary driver, in the specification's order. +/// +/// Every step but five is reused unchanged, called through `super::altair`, +/// `super::registry`, `super::capella`, and `super` exactly as +/// [`super::capella::process_epoch`] itself calls them. The five exceptions: +/// [`process_registry_updates`], [`process_slashings`], and +/// [`process_effective_balance_updates`] replace the shared versions in +/// place, and [`process_pending_deposits`] and [`process_pending_consolidations`] +/// are inserted right after `process_eth1_data_reset`, exactly where the +/// specification's own listing puts them (before the effective-balance +/// update, so a deposit credited this epoch is already reflected when +/// effective balances round toward it). +pub fn process_epoch(state: &mut BeaconState, config: &Config) -> Result<()> { + super::altair::process_justification_and_finalization(state)?; + super::altair::process_inactivity_updates(state, config)?; + super::altair::process_rewards_and_penalties(state, config)?; + // [Modified in Electra:EIP7251] + process_registry_updates(state, config)?; + // [Modified in Electra:EIP7251]: electra's own copy; see this module's + // own doc and `process_slashings`'s own doc for why `super::registry`'s + // copy is no longer correct from here on. + process_slashings(state, config)?; + super::process_eth1_data_reset(state)?; + // [New in Electra:EIP7251] + process_pending_deposits(state, config)?; + // [New in Electra:EIP7251] + process_pending_consolidations(state, config)?; + // [Modified in Electra:EIP7251] + process_effective_balance_updates(state)?; + super::process_slashings_reset(state)?; + super::process_randao_mixes_reset(state)?; + super::capella::process_historical_summaries_update(state)?; + super::altair::process_participation_flag_updates(state)?; + super::altair::process_sync_committee_updates(state)?; + Ok(()) +} + +// --------------------------------------------------------------------------- +// Registry updates +// --------------------------------------------------------------------------- + +/// A validator's outcome for one run of [`process_registry_updates`]: at most +/// one of the specification's `if`/`elif`/`elif` branches applies. +enum RegistryAction { + QueueForActivation, + Eject, + Activate, +} + +/// Moves validators between activation-queue eligibility, ejection, and +/// activation, replacing `super::registry::process_registry_updates` for this +/// fork. +/// +/// Rewritten as a single pass over the registry rather than phase0's two +/// passes (eligibility-and-ejection, then a sorted, churn-limited activation +/// queue): EIP-7251 moves the very thing that used to bound activation, a +/// per-epoch validator headcount, onto [`process_pending_deposits`]'s Gwei +/// budget instead, so nothing here needs to rate-limit how many validators +/// activate in one epoch. Every validator whose eligibility is already +/// finalized simply activates, in registry order, at the same +/// `compute_activation_exit_epoch(current_epoch)` the specification computes +/// once up front, which is the detail that most differs from phase0 and is +/// worth transcribing precisely rather than assuming. +/// +/// Decided in one immutable pass and applied in a second, the same shape +/// `crate::beacon::stf::epoch::process_effective_balance_updates` uses: `state` is an +/// enum over per-fork structs, so nothing can hold `validators` mutably while +/// also reading it to decide the next validator's action. None of the three +/// checks reads anything a *different* validator's mutation could have +/// changed, so the two passes are safe to split. The one exception is +/// [`initiate_validator_exit`]'s own churn cursor, which must still advance in +/// ascending validator-index order for the ejected balance total to match the +/// specification's single loop exactly; applying every decided action in +/// registry order (rather than, say, ejections first) is what preserves that. +pub fn process_registry_updates(state: &mut BeaconState, config: &Config) -> Result<()> { + let current_epoch = get_current_epoch(state); + let activation_epoch = compute_activation_exit_epoch(current_epoch); + let finalized_epoch = state.finalized_checkpoint().epoch; + + let actions: Vec> = state + .validators() + .iter() + .map(|validator| { + if is_eligible_for_activation_queue(validator) { + Some(RegistryAction::QueueForActivation) + } else if is_active_validator(validator, current_epoch) + && validator.effective_balance <= config.ejection_balance + { + Some(RegistryAction::Eject) + } else if is_eligible_for_activation(validator, finalized_epoch) { + Some(RegistryAction::Activate) + } else { + None + } + }) + .collect(); + + for (index, action) in actions.into_iter().enumerate() { + let index = index as ValidatorIndex; + match action { + Some(RegistryAction::QueueForActivation) => { + state.validator_mut(index)?.activation_eligibility_epoch = current_epoch + 1; + } + Some(RegistryAction::Eject) => initiate_validator_exit(state, index, config)?, + Some(RegistryAction::Activate) => { + state.validator_mut(index)?.activation_epoch = activation_epoch; + } + None => {} + } + } + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Slashings +// --------------------------------------------------------------------------- + +/// Applies the deferred part of every slashing whose penalty falls due this +/// epoch, replacing `super::registry::process_slashings` for this fork. +/// +/// The same three passes as that version: sum `state.slashings`, scale and cap +/// the sum against the total active balance, then apply a per-validator +/// penalty to whoever's withdrawable epoch arrives this epoch. What EIP-7251 +/// changes is which side of a division the rounding happens on. That version +/// computes, per validator, `effective_balance_increments * +/// adjusted_total_slashing_balance`, divides by the raw `total_balance`, and +/// only then multiplies back up by `increment`. This version instead divides +/// `adjusted_total_slashing_balance` by `total_balance / increment` once, up +/// front, and multiplies that one shared quotient by each validator's own +/// `effective_balance_increments`. +/// +/// The two orders are not algebraically equivalent under integer division. +/// Multiplying by a validator's own increment count before dividing, the way +/// the pre-electra version does, needs the *product* to reach `total_balance` +/// before any penalty shows up at all; dividing first only needs the slashed +/// amount itself to reach `total_balance / increment`, a number smaller by a +/// factor of `EFFECTIVE_BALANCE_INCREMENT`. A validator whose slashed balance +/// is not the dominant contributor to the epoch's total can therefore round +/// all the way down to no penalty under the old order while still receiving a +/// real one under this one; see this function's own tests for a worked +/// example. The specification also frames the restructuring as an overflow +/// guard: the pre-electra product, `effective_balance_increments * +/// adjusted_total_slashing_balance`, risks overflowing a `uint64` once a +/// compounding validator's ceiling +/// ([`preset::MAX_EFFECTIVE_BALANCE_ELECTRA`]) is dozens of times larger than +/// the old, fixed one, so dividing the shared quotient down to size before +/// that multiplication, rather than after, is not merely a rounding +/// preference. +/// +/// The proportional multiplier itself is unchanged from bellatrix: electra +/// never redefines it, so reading it by fork through +/// [`preset::retuned::proportional_slashing_multiplier`] reaches the same +/// constant that function already selects for this fork; only the arithmetic +/// downstream of it moves. +/// +/// Takes `config` only to match [`process_epoch`]'s pipeline, the same reason +/// `super::registry::process_slashings` does; the specification's own version +/// takes no configuration either. +pub fn process_slashings(state: &mut BeaconState, _config: &Config) -> Result<()> { + let epoch = get_current_epoch(state); + let total_balance = get_total_active_balance(state)?; + + let mut slashed_sum: Gwei = 0; + for &slashing in state.slashings().iter() { + slashed_sum = slashed_sum + .checked_add(slashing) + .ok_or(Error::ArithmeticOverflow("summing the slashings vector"))?; + } + let multiplier = preset::retuned::proportional_slashing_multiplier(state.fork_name()); + let scaled_slashings = slashed_sum + .checked_mul(multiplier) + .ok_or(Error::ArithmeticOverflow( + "scaling the summed slashings by the proportional multiplier", + ))?; + let adjusted_total_slashing_balance = scaled_slashings.min(total_balance); + + let increment = preset::EFFECTIVE_BALANCE_INCREMENT; + // `total_balance` (`get_total_active_balance`) sums every active + // validator's own increment-quantized effective balance and is floored at + // one whole increment, so it is always an exact multiple of `increment`: + // this can never divide by zero, and no remainder is lost to carry + // forward. + let total_increments = total_balance / increment; + let penalty_per_effective_balance_increment = + adjusted_total_slashing_balance / total_increments; + + let withdrawable_offset = (preset::EPOCHS_PER_SLASHINGS_VECTOR / 2) as Epoch; + + // Collecting the penalties before applying any of them keeps this pass + // reading a stable registry, the same reason + // `super::registry::process_slashings` does. + let mut penalties = Vec::new(); + for (index, validator) in state.validators().iter().enumerate() { + if validator.slashed && epoch + withdrawable_offset == validator.withdrawable_epoch { + let effective_balance_increments = validator.effective_balance / increment; + let penalty = penalty_per_effective_balance_increment + .checked_mul(effective_balance_increments) + .ok_or(Error::ArithmeticOverflow( + "penalty_per_effective_balance_increment * effective_balance_increments", + ))?; + penalties.push((index as ValidatorIndex, penalty)); + } + } + + for (index, penalty) in penalties { + decrease_balance(state, index, penalty)?; + } + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Pending deposits +// --------------------------------------------------------------------------- + +/// Drains a balance-churn-limited amount of [`electra::PendingDeposit`]s into +/// the validator registry. +/// +/// New in electra; see this module's own doc for why crediting a deposit +/// immediately, the way every earlier fork's `process_deposit` does, is no +/// longer safe once a validator's ceiling can be far above +/// [`preset::MIN_ACTIVATION_BALANCE`]. `crate::beacon::stf::operations::process_deposit` +/// and `apply_deposit` (block processing's own deposit path, EIP-6110, a file +/// this task does not own) queue a deposit's amount rather than crediting it +/// directly; this is what actually applies it, once there is room in this +/// epoch's [`get_activation_exit_churn_limit`] budget. +/// +/// The queue is drained strictly from the front. Every entry reached advances +/// `next_deposit_index`, meaning it leaves its place at the front of the +/// queue, except one case: a deposit that would push this epoch's processed +/// total over budget stops the whole pass rather than being skipped over, so +/// a small deposit further back in the queue can never jump ahead of a large +/// one still waiting for room. Three outcomes decide what happens to an entry +/// that clears the ordering gates (the eth1-bridge-ahead-of-requests check, +/// the finality check, and the per-epoch processing cap): +/// +/// - A deposit naming a validator that is already past its withdrawable +/// epoch can never usefully activate that balance, so it is credited +/// immediately without touching the churn budget at all. +/// - A deposit naming a validator that has started exiting, but is not yet +/// withdrawable, is **postponed**: moved out of its place in the queue and +/// appended to `deposits_to_postpone`, to be retried once the validator's +/// status resolves one way or the other. This is the branch worth reading +/// twice: dropping it here instead, the way an ordinary rejected operation +/// would be dropped, is silent stake loss, since nothing else in the state +/// transition ever revisits a discarded deposit. +/// - Anything else (an unknown pubkey, or a validator that is neither exited +/// nor withdrawn) consumes churn and is credited, unless doing so would +/// exceed the budget, in which case processing stops for this epoch as +/// described above. +pub fn process_pending_deposits(state: &mut BeaconState, config: &Config) -> Result<()> { + let next_epoch = get_current_epoch(state) + 1; + let churn_limit = get_activation_exit_churn_limit(state, config)?; + let finalized_slot = compute_start_slot_at_epoch(state.finalized_checkpoint().epoch); + let eth1_deposit_index = state.eth1_deposit_index(); + + // `pending_queue_fields` borrows the whole state, so everything read + // through it below has to finish before the loop's own, ordinary + // mutable borrows of `state` begin. Taking `pending_deposits` by value + // here, rather than iterating it in place, is what frees `state` for + // those: once the queue is a plain `Vec` of its own, reading + // `state.validators()` and crediting balances through `state` cannot + // conflict with walking the deposits that drive those reads and writes. + let (deposit_requests_start_index, available_for_processing, deposits) = { + let mut fields = pending_queue_fields(state, "process_pending_deposits")?; + let deposit_requests_start_index = fields.deposit_requests_start_index(); + let available_for_processing = fields + .deposit_balance_to_consume() + .checked_add(churn_limit) + .ok_or(Error::ArithmeticOverflow( + "deposit_balance_to_consume + get_activation_exit_churn_limit", + ))?; + let deposits: Vec = + core::mem::take(fields.pending_deposits_mut()).into_inner(); + ( + deposit_requests_start_index, + available_for_processing, + deposits, + ) + }; + + let mut processed_amount: Gwei = 0; + let mut next_deposit_index = 0usize; + let mut deposits_to_postpone: Vec = Vec::new(); + let mut is_churn_limit_reached = false; + + for deposit in &deposits { + // Eth1 bridge deposits (`slot == GENESIS_SLOT`) must all be applied + // before the first deposit *request* is: the two sources are ordered + // relative to each other only by this check, since a request's own + // slot says nothing about where it falls in the bridge's queue. + if deposit.slot > constants::GENESIS_SLOT + && eth1_deposit_index < deposit_requests_start_index + { + break; + } + + // A deposit whose queue position could still be reorged out must + // wait: crediting it now and reverting later is not an option, since + // nothing else in the state transition undoes a balance change. + if deposit.slot > finalized_slot { + break; + } + + if next_deposit_index >= preset::MAX_PENDING_DEPOSITS_PER_EPOCH as usize { + break; + } + + let (is_validator_exited, is_validator_withdrawn) = match state + .validators() + .iter() + .position(|validator| validator.pubkey == deposit.pubkey) + { + Some(index) => { + let validator = &state.validators()[index]; + ( + validator.exit_epoch < FAR_FUTURE_EPOCH, + validator.withdrawable_epoch < next_epoch, + ) + } + None => (false, false), + }; + + if is_validator_withdrawn { + apply_pending_deposit(state, deposit, config)?; + } else if is_validator_exited { + deposits_to_postpone.push(deposit.clone()); + } else { + match processed_amount.checked_add(deposit.amount) { + Some(sum) if sum <= available_for_processing => { + processed_amount = sum; + apply_pending_deposit(state, deposit, config)?; + } + // Either the sum overflowed (certainly too much) or it fit in + // a `u64` but still exceeded the budget: both mean this + // epoch's processing stops here. + _ => { + is_churn_limit_reached = true; + break; + } + } + } + + next_deposit_index += 1; + } + + let remaining: Vec = deposits + .into_iter() + .skip(next_deposit_index) + .chain(deposits_to_postpone) + .collect(); + + // Leftover churn is only worth remembering when it was actually the + // reason processing stopped: if the queue simply ran out, or one of the + // ordering gates stopped it first, next epoch's budget starts fresh + // rather than inheriting room this epoch never even tried to spend. + let deposit_balance_to_consume = if is_churn_limit_reached { + available_for_processing + .checked_sub(processed_amount) + .ok_or(Error::ArithmeticOverflow( + "available_for_processing - processed_amount", + ))? + } else { + 0 + }; + + let mut fields = pending_queue_fields(state, "process_pending_deposits")?; + *fields.pending_deposits_mut() = electra::PendingDeposits::try_from(remaining)?; + *fields.deposit_balance_to_consume_mut() = deposit_balance_to_consume; + + Ok(()) +} + +/// Credits one dequeued [`electra::PendingDeposit`]: as a balance top-up if +/// its pubkey already has a registry entry, or as a brand-new validator +/// (subject to [`is_valid_deposit_signature`]) if it does not. +/// +/// The specification's own `apply_pending_deposit`. Not a call into +/// `crate::beacon::stf::operations::apply_deposit`: that function answers the +/// equivalent question for block processing's own, differently-shaped +/// deposit path (a file this task does not own), and, as read while writing +/// this, still builds a new validator phase0's way; see +/// [`add_validator_from_pending_deposit`]'s doc for exactly how reusing it +/// would go wrong here. +fn apply_pending_deposit( + state: &mut BeaconState, + deposit: &electra::PendingDeposit, + config: &Config, +) -> Result<()> { + let existing_index = state + .validators() + .iter() + .position(|validator| validator.pubkey == deposit.pubkey); + + match existing_index { + Some(index) => increase_balance(state, index as ValidatorIndex, deposit.amount), + None if is_valid_deposit_signature( + deposit.pubkey, + deposit.withdrawal_credentials, + deposit.amount, + deposit.signature, + config, + ) => + { + add_validator_from_pending_deposit( + state, + deposit.pubkey, + deposit.withdrawal_credentials, + deposit.amount, + ) + } + // An invalid signature is not an error: the deposit is simply never + // credited to a new validator, the same tolerance + // `crate::beacon::stf::operations::apply_deposit` documents for its own, + // block-processing deposit path. + None => Ok(()), + } +} + +/// Whether `signature` is a valid proof of possession over (`pubkey`, +/// `withdrawal_credentials`, `amount`). +/// +/// The specification's own domain, `compute_domain(DOMAIN_DEPOSIT)` with no +/// fork version or validators root supplied, defaults to the genesis fork +/// version and an all-zero validators root: exactly what +/// [`compute_deposit_domain`] already computes for phase0's own deposit path, +/// so this reuses it rather than re-deriving the same default by hand. A +/// deposit is signed by a depositor with no way to know which fork, or even +/// which chain, will eventually accept it, which is why this is the one +/// signature check in the whole state transition that does not commit to a +/// specific fork version or genesis validators root the way every other one +/// does. +fn is_valid_deposit_signature( + pubkey: BlsPubkey, + withdrawal_credentials: Bytes32, + amount: Gwei, + signature: BlsSignature, + config: &Config, +) -> bool { + let deposit_message = DepositMessage { + pubkey, + withdrawal_credentials, + amount, + }; + let domain = compute_deposit_domain(config.genesis_fork_version); + let signing_root = compute_signing_root(deposit_message.hash_tree_root(), domain); + bls::verify(&pubkey, signing_root, &signature) +} + +/// Builds and appends a brand-new validator for a pending deposit whose +/// pubkey has no existing registry entry. +/// +/// A second copy of the specification's electra-modified +/// `add_validator_to_registry`, not a call into +/// `crate::beacon::stf::operations::add_validator_to_registry`: that copy belongs to +/// block processing's own deposit path (a file this task does not own) and, +/// as read while writing this, still caps a new validator's effective +/// balance at the phase0 `MAX_EFFECTIVE_BALANCE` rather than +/// [`get_max_effective_balance`]'s per-validator ceiling, and never extends +/// `previous_epoch_participation`, `current_epoch_participation`, or +/// `inactivity_scores` (fields phase0 does not have). Reusing it here would +/// activate a compounding validator at the wrong ceiling and desync those +/// three lists from the registry the moment a pending deposit creates a +/// validator, since nothing would ever grow them back into with the +/// registry's own length again. +fn add_validator_from_pending_deposit( + state: &mut BeaconState, + pubkey: BlsPubkey, + withdrawal_credentials: Bytes32, + amount: Gwei, +) -> Result<()> { + let mut validator = Validator { + pubkey, + withdrawal_credentials, + activation_eligibility_epoch: FAR_FUTURE_EPOCH, + activation_epoch: FAR_FUTURE_EPOCH, + exit_epoch: FAR_FUTURE_EPOCH, + withdrawable_epoch: FAR_FUTURE_EPOCH, + ..Default::default() + }; + // `get_max_effective_balance` only reads `withdrawal_credentials`, which + // is already set above, so the ceiling is correct even though + // `effective_balance` itself is still the zero `Default` placeholder. + // Subtracting the remainder can never underflow, since a modulus is + // always at most the value it divides. + let max_effective_balance = get_max_effective_balance(&validator); + validator.effective_balance = + (amount - amount % preset::EFFECTIVE_BALANCE_INCREMENT).min(max_effective_balance); + + state.validators_mut().push(validator)?; + state.balances_mut().push(amount)?; + pending_queue_fields(state, "add_validator_from_pending_deposit")? + .push_empty_participation_and_inactivity() +} + +// --------------------------------------------------------------------------- +// Pending consolidations +// --------------------------------------------------------------------------- + +/// Applies queued validator consolidations (EIP-7251), moving each eligible +/// source's balance to its target. +/// +/// New in electra. Unlike [`process_pending_deposits`], nothing here is +/// balance-churn-limited: a consolidation moves stake between two validators +/// already counted in the active balance rather than admitting new stake, so +/// it cannot grow the total the way a deposit can, and there is nothing left +/// for a churn budget to protect against. `config` is threaded through only +/// so this matches the signature every other step of [`process_epoch`]'s +/// pipeline is called with, the same reason +/// `super::registry::process_slashings` takes one it never reads. +/// +/// The queue is drained strictly from the front, but its two stopping +/// conditions behave differently. A slashed source is dropped from the queue +/// outright: its balance is already earmarked for the slashing penalty +/// instead of its intended target, and no later epoch changes that, so +/// nothing is gained by keeping the entry around. A source that is not yet +/// withdrawable simply stops the pass: that entry, and everything queued +/// behind it, is left in place (not postponed to the back, unlike +/// [`process_pending_deposits`]'s exited-validator case) to be retried once +/// it clears. +pub fn process_pending_consolidations(state: &mut BeaconState, _config: &Config) -> Result<()> { + let next_epoch = get_current_epoch(state) + 1; + + let consolidations: Vec = { + let mut fields = pending_queue_fields(state, "process_pending_consolidations")?; + core::mem::take(fields.pending_consolidations_mut()).into_inner() + }; + + let mut next_pending_consolidation = 0usize; + for consolidation in &consolidations { + let (slashed, withdrawable_epoch, effective_balance) = { + let source = state.validator(consolidation.source_index)?; + ( + source.slashed, + source.withdrawable_epoch, + source.effective_balance, + ) + }; + + if slashed { + next_pending_consolidation += 1; + continue; + } + if withdrawable_epoch > next_epoch { + break; + } + + let source_effective_balance = state + .balance(consolidation.source_index)? + .min(effective_balance); + decrease_balance(state, consolidation.source_index, source_effective_balance)?; + increase_balance(state, consolidation.target_index, source_effective_balance)?; + next_pending_consolidation += 1; + } + + let remaining: Vec = consolidations + .into_iter() + .skip(next_pending_consolidation) + .collect(); + let mut fields = pending_queue_fields(state, "process_pending_consolidations")?; + *fields.pending_consolidations_mut() = electra::PendingConsolidations::try_from(remaining)?; + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Effective balance updates +// --------------------------------------------------------------------------- + +/// Moves each validator's effective balance toward its actual balance, +/// replacing `super::process_effective_balance_updates` for this fork. +/// +/// The only change from that version: the ceiling each validator rounds +/// toward is [`get_max_effective_balance`], read per validator, rather than +/// the single `MAX_EFFECTIVE_BALANCE` every validator shared before +/// EIP-7251, since a compounding validator's ceiling can be far higher. The +/// hysteresis arithmetic itself is copied unchanged from that version, down +/// to computing `HYSTERESIS_INCREMENT` by dividing first and only then +/// multiplying it up to each threshold: multiplying before dividing is +/// algebraically equivalent but rounds differently, and only the +/// specification's own order reproduces its integer rounding. +pub fn process_effective_balance_updates(state: &mut BeaconState) -> Result<()> { + const HYSTERESIS_INCREMENT: Gwei = + preset::EFFECTIVE_BALANCE_INCREMENT / preset::HYSTERESIS_QUOTIENT; + const DOWNWARD_THRESHOLD: Gwei = HYSTERESIS_INCREMENT * preset::HYSTERESIS_DOWNWARD_MULTIPLIER; + const UPWARD_THRESHOLD: Gwei = HYSTERESIS_INCREMENT * preset::HYSTERESIS_UPWARD_MULTIPLIER; + + // Two passes for the same reason `super::process_effective_balance_updates` + // needs them: `state` is an enum over per-fork structs, so there is no + // way to hold `validators` mutably while also reading `balances`, or + // (here) while calling `get_max_effective_balance` on the validator + // being decided on. + let mut updates = Vec::new(); + for (index, validator) in state.validators().iter().enumerate() { + let balance = state.balances()[index]; + if balance + DOWNWARD_THRESHOLD < validator.effective_balance + || validator.effective_balance + UPWARD_THRESHOLD < balance + { + let max_effective_balance = get_max_effective_balance(validator); + let effective = (balance - balance % preset::EFFECTIVE_BALANCE_INCREMENT) + .min(max_effective_balance); + updates.push((index, effective)); + } + } + + let validators = state.validators_mut(); + for (index, effective) in updates { + validators[index].effective_balance = effective; + } + Ok(()) +} + +// --------------------------------------------------------------------------- +// Fork projection +// --------------------------------------------------------------------------- + +/// Fields [`process_pending_deposits`] and [`process_pending_consolidations`] +/// need that [`crate::beacon::helpers::electra::electra_state`] does not expose: that +/// projection only covers what its own module's functions need (the exit and +/// consolidation churn cursors, and `pending_deposits_mut` for +/// `queue_excess_active_balance` and its neighbors). This crate keeps one +/// file per fork's own state-transition concerns, so a second, file-local +/// projection lives here rather than as an addition to that module, even +/// though its shape, an electra-or-fulu match, is identical: fulu keeps every +/// field this covers unchanged (see `crate::beacon::helpers::electra`'s own module +/// doc for why that module's projection accepts fulu too). +enum PendingQueueFields<'a> { + Electra(&'a mut electra::BeaconState), + Fulu(&'a mut fulu::BeaconState), +} + +impl<'a> PendingQueueFields<'a> { + /// The execution-layer deposit request index at which the state switched + /// from crediting deposits off `Eth1Data` votes to crediting them off + /// `DepositRequest`s directly, read by [`process_pending_deposits`] to + /// know whether any eth1-bridge deposit is still outstanding. + fn deposit_requests_start_index(&self) -> u64 { + match self { + PendingQueueFields::Electra(state) => state.deposit_requests_start_index, + PendingQueueFields::Fulu(state) => state.deposit_requests_start_index, + } + } + + /// How much of this epoch's deposit balance churn limit remains unused. + fn deposit_balance_to_consume(&self) -> Gwei { + match self { + PendingQueueFields::Electra(state) => state.deposit_balance_to_consume, + PendingQueueFields::Fulu(state) => state.deposit_balance_to_consume, + } + } + + fn deposit_balance_to_consume_mut(&mut self) -> &mut Gwei { + match self { + PendingQueueFields::Electra(state) => &mut state.deposit_balance_to_consume, + PendingQueueFields::Fulu(state) => &mut state.deposit_balance_to_consume, + } + } + + /// Deposits known but not yet credited to the validator registry. + fn pending_deposits_mut(&mut self) -> &mut electra::PendingDeposits { + match self { + PendingQueueFields::Electra(state) => &mut state.pending_deposits, + PendingQueueFields::Fulu(state) => &mut state.pending_deposits, + } + } + + /// Consolidations known but not yet applied. + fn pending_consolidations_mut(&mut self) -> &mut electra::PendingConsolidations { + match self { + PendingQueueFields::Electra(state) => &mut state.pending_consolidations, + PendingQueueFields::Fulu(state) => &mut state.pending_consolidations, + } + } + + /// Extends `previous_epoch_participation`, `current_epoch_participation`, + /// and `inactivity_scores` by one all-zero entry each, keeping them + /// exactly as long as the registry after + /// [`add_validator_from_pending_deposit`] appends a validator. + fn push_empty_participation_and_inactivity(&mut self) -> Result<()> { + match self { + PendingQueueFields::Electra(state) => { + state.previous_epoch_participation.push(0)?; + state.current_epoch_participation.push(0)?; + state.inactivity_scores.push(0)?; + } + PendingQueueFields::Fulu(state) => { + state.previous_epoch_participation.push(0)?; + state.current_epoch_participation.push(0)?; + state.inactivity_scores.push(0)?; + } + } + Ok(()) + } +} + +/// The electra-or-fulu state, mutably, through [`PendingQueueFields`]. See +/// its own doc for why this is a second projection rather than a call into +/// [`crate::beacon::helpers::electra::electra_state`]. +fn pending_queue_fields<'a>( + state: &'a mut BeaconState, + function: &'static str, +) -> Result> { + match state { + BeaconState::Electra(state) => Ok(PendingQueueFields::Electra(state)), + BeaconState::Fulu(state) => Ok(PendingQueueFields::Fulu(state)), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use blst::min_pk::SecretKey; + + use crate::beacon::fork::ForkName; + + /// An electra state with `count` fully active, full-balance validators, + /// positioned one epoch in, the same way + /// `crate::beacon::helpers::test_state::with_validators` positions its phase0 + /// state. + /// + /// A thin wrapper around the shared fork-parameterised builder: see + /// [`crate::beacon::helpers::test_state::with_validators_at`] for the construction + /// this and every other fork's test module used to duplicate. + fn electra_state_with_validators(count: usize) -> BeaconState { + crate::beacon::helpers::test_state::with_validators_at(ForkName::Electra, count) + } + + // ----------------------------------------------------------------------- + // process_pending_deposits + // ----------------------------------------------------------------------- + + #[test] + fn a_pending_deposit_for_an_already_withdrawn_validator_bypasses_churn() { + let config = Config::mainnet(); + let mut state = electra_state_with_validators(2); + let next_epoch = get_current_epoch(&state) + 1; + + let (pubkey, withdrawal_credentials) = { + let validator = state.validator_mut(0).unwrap(); + validator.exit_epoch = 0; + validator.withdrawable_epoch = 0; + (validator.pubkey, validator.withdrawal_credentials) + }; + assert!(state.validator(0).unwrap().withdrawable_epoch < next_epoch); + + let churn_limit = get_activation_exit_churn_limit(&state, &config).unwrap(); + // Deliberately larger than the whole churn budget: a withdrawn + // validator's deposit must go through regardless of budget. + let deposit_amount = churn_limit + preset::EFFECTIVE_BALANCE_INCREMENT; + let deposit = electra::PendingDeposit { + pubkey, + withdrawal_credentials, + amount: deposit_amount, + signature: BlsSignature::default(), + slot: constants::GENESIS_SLOT, + }; + pending_queue_fields(&mut state, "test setup") + .unwrap() + .pending_deposits_mut() + .push(deposit) + .unwrap(); + + let balance_before = state.balance(0).unwrap(); + process_pending_deposits(&mut state, &config).unwrap(); + + assert_eq!(state.balance(0).unwrap(), balance_before + deposit_amount); + let mut fields = pending_queue_fields(&mut state, "test assertion").unwrap(); + assert_eq!(fields.deposit_balance_to_consume(), 0); + assert!(fields.pending_deposits_mut().is_empty()); + } + + #[test] + fn a_pending_deposit_for_an_exited_but_not_yet_withdrawn_validator_is_postponed_not_dropped() { + let config = Config::mainnet(); + let mut state = electra_state_with_validators(2); + let next_epoch = get_current_epoch(&state) + 1; + + let (pubkey, withdrawal_credentials) = { + let validator = state.validator_mut(0).unwrap(); + validator.exit_epoch = 0; + // Still far from withdrawable: `next_epoch` must not exceed this. + validator.withdrawable_epoch = FAR_FUTURE_EPOCH; + (validator.pubkey, validator.withdrawal_credentials) + }; + assert!(state.validator(0).unwrap().withdrawable_epoch >= next_epoch); + + let deposit = electra::PendingDeposit { + pubkey, + withdrawal_credentials, + amount: preset::EFFECTIVE_BALANCE_INCREMENT, + signature: BlsSignature::default(), + slot: constants::GENESIS_SLOT, + }; + pending_queue_fields(&mut state, "test setup") + .unwrap() + .pending_deposits_mut() + .push(deposit.clone()) + .unwrap(); + + let balance_before = state.balance(0).unwrap(); + process_pending_deposits(&mut state, &config).unwrap(); + + // Not applied... + assert_eq!(state.balance(0).unwrap(), balance_before); + // ...and not lost: it comes back out the other end of the queue. + let mut fields = pending_queue_fields(&mut state, "test assertion").unwrap(); + let remaining = fields.pending_deposits_mut(); + assert_eq!(remaining.len(), 1); + assert_eq!(remaining[0], deposit); + } + + #[test] + fn pending_deposits_stop_at_the_churn_limit_and_the_rest_stay_queued_in_place() { + let config = Config::mainnet(); + let mut state = electra_state_with_validators(2); + let churn_limit = get_activation_exit_churn_limit(&state, &config).unwrap(); + + let (pubkey_0, credentials_0) = { + let v = state.validator(0).unwrap(); + (v.pubkey, v.withdrawal_credentials) + }; + let (pubkey_1, credentials_1) = { + let v = state.validator(1).unwrap(); + (v.pubkey, v.withdrawal_credentials) + }; + + let first_amount = churn_limit / 2; + let second_amount = churn_limit; + let first = electra::PendingDeposit { + pubkey: pubkey_0, + withdrawal_credentials: credentials_0, + amount: first_amount, + signature: BlsSignature::default(), + slot: constants::GENESIS_SLOT, + }; + let second = electra::PendingDeposit { + pubkey: pubkey_1, + withdrawal_credentials: credentials_1, + amount: second_amount, + signature: BlsSignature::default(), + slot: constants::GENESIS_SLOT, + }; + { + let mut fields = pending_queue_fields(&mut state, "test setup").unwrap(); + fields.pending_deposits_mut().push(first).unwrap(); + fields.pending_deposits_mut().push(second.clone()).unwrap(); + } + + let balance_0_before = state.balance(0).unwrap(); + let balance_1_before = state.balance(1).unwrap(); + process_pending_deposits(&mut state, &config).unwrap(); + + assert_eq!(state.balance(0).unwrap(), balance_0_before + first_amount); + assert_eq!( + state.balance(1).unwrap(), + balance_1_before, + "over budget: must not apply" + ); + + let mut fields = pending_queue_fields(&mut state, "test assertion").unwrap(); + assert_eq!( + fields.deposit_balance_to_consume(), + churn_limit - first_amount + ); + let remaining = fields.pending_deposits_mut(); + assert_eq!(remaining.len(), 1); + assert_eq!(remaining[0], second); + } + + #[test] + fn a_pending_deposit_for_an_unseen_pubkey_activates_a_new_validator_at_its_own_ceiling() { + let config = Config::mainnet(); + let mut state = electra_state_with_validators(1); + + let secret_key = SecretKey::key_gen(&[9u8; 32], &[]).expect("32 bytes of key material"); + let pubkey = BlsPubkey(secret_key.sk_to_pk().to_bytes()); + let mut withdrawal_credentials = Bytes32::ZERO; + withdrawal_credentials.0[0] = constants::COMPOUNDING_WITHDRAWAL_PREFIX; + let amount = preset::MIN_ACTIVATION_BALANCE + preset::EFFECTIVE_BALANCE_INCREMENT; + + let deposit_message = DepositMessage { + pubkey, + withdrawal_credentials, + amount, + }; + let domain = compute_deposit_domain(config.genesis_fork_version); + let signing_root = compute_signing_root(deposit_message.hash_tree_root(), domain); + // The same domain separation tag `crate::beacon::bls` signs and verifies + // under, redefined here because that module keeps it private; see + // `crate::beacon::stf::operations::tests`'s own attester-slashing test for + // the same pattern applied to a different domain. + const DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; + let signature = BlsSignature( + secret_key + .sign(signing_root.as_slice(), DST, &[]) + .to_bytes(), + ); + + let deposit = electra::PendingDeposit { + pubkey, + withdrawal_credentials, + amount, + signature, + slot: constants::GENESIS_SLOT, + }; + pending_queue_fields(&mut state, "test setup") + .unwrap() + .pending_deposits_mut() + .push(deposit) + .unwrap(); + + let validators_before = state.validators().len(); + process_pending_deposits(&mut state, &config).unwrap(); + + assert_eq!(state.validators().len(), validators_before + 1); + let new_index = validators_before as ValidatorIndex; + let new_validator = state.validator(new_index).unwrap(); + assert_eq!(new_validator.pubkey, pubkey); + // A compounding credential from birth, so the deposit's whole amount + // (comfortably under `MAX_EFFECTIVE_BALANCE_ELECTRA`) becomes + // effective balance rather than being capped at the non-compounding + // `MIN_ACTIVATION_BALANCE` ceiling. + assert_eq!(new_validator.effective_balance, amount); + assert_eq!(state.balance(new_index).unwrap(), amount); + + // The participation and inactivity lists must stay exactly as long + // as the registry, or a later epoch's indexing into them for this + // validator panics or errors. + match &state { + BeaconState::Electra(inner) => { + assert_eq!( + inner.previous_epoch_participation.len(), + state.validators().len() + ); + assert_eq!( + inner.current_epoch_participation.len(), + state.validators().len() + ); + assert_eq!(inner.inactivity_scores.len(), state.validators().len()); + } + _ => unreachable!("electra_state_with_validators always builds an Electra state"), + } + } + + #[test] + fn a_pending_deposit_with_an_invalid_signature_is_dropped_not_added() { + let config = Config::mainnet(); + let mut state = electra_state_with_validators(1); + + let deposit = electra::PendingDeposit { + pubkey: BlsPubkey::default(), + withdrawal_credentials: Bytes32::ZERO, + amount: preset::MIN_ACTIVATION_BALANCE, + signature: BlsSignature::default(), + slot: constants::GENESIS_SLOT, + }; + pending_queue_fields(&mut state, "test setup") + .unwrap() + .pending_deposits_mut() + .push(deposit) + .unwrap(); + + let validators_before = state.validators().len(); + process_pending_deposits(&mut state, &config).unwrap(); + + assert_eq!( + state.validators().len(), + validators_before, + "an invalid signature must not create a validator" + ); + let mut fields = pending_queue_fields(&mut state, "test assertion").unwrap(); + assert!( + fields.pending_deposits_mut().is_empty(), + "the entry is still consumed from the queue, just never credited" + ); + } + + // ----------------------------------------------------------------------- + // process_pending_consolidations + // ----------------------------------------------------------------------- + + #[test] + fn a_pending_consolidation_from_a_slashed_source_is_dropped_from_the_queue() { + let config = Config::mainnet(); + let mut state = electra_state_with_validators(2); + state.validator_mut(0).unwrap().slashed = true; + + let consolidation = electra::PendingConsolidation { + source_index: 0, + target_index: 1, + }; + pending_queue_fields(&mut state, "test setup") + .unwrap() + .pending_consolidations_mut() + .push(consolidation) + .unwrap(); + + let source_balance_before = state.balance(0).unwrap(); + let target_balance_before = state.balance(1).unwrap(); + process_pending_consolidations(&mut state, &config).unwrap(); + + assert_eq!(state.balance(0).unwrap(), source_balance_before); + assert_eq!(state.balance(1).unwrap(), target_balance_before); + let mut fields = pending_queue_fields(&mut state, "test assertion").unwrap(); + assert!(fields.pending_consolidations_mut().is_empty()); + } + + #[test] + fn a_pending_consolidation_not_yet_withdrawable_stays_queued_in_place() { + let config = Config::mainnet(); + let mut state = electra_state_with_validators(2); + let next_epoch = get_current_epoch(&state) + 1; + state.validator_mut(0).unwrap().withdrawable_epoch = next_epoch + 1; + + let consolidation = electra::PendingConsolidation { + source_index: 0, + target_index: 1, + }; + pending_queue_fields(&mut state, "test setup") + .unwrap() + .pending_consolidations_mut() + .push(consolidation.clone()) + .unwrap(); + + process_pending_consolidations(&mut state, &config).unwrap(); + + let mut fields = pending_queue_fields(&mut state, "test assertion").unwrap(); + let remaining = fields.pending_consolidations_mut(); + assert_eq!(remaining.len(), 1); + assert_eq!(remaining[0], consolidation); + } + + #[test] + fn an_eligible_pending_consolidation_moves_the_source_balance_to_the_target() { + let config = Config::mainnet(); + let mut state = electra_state_with_validators(2); + state.validator_mut(0).unwrap().withdrawable_epoch = 0; + + let consolidation = electra::PendingConsolidation { + source_index: 0, + target_index: 1, + }; + pending_queue_fields(&mut state, "test setup") + .unwrap() + .pending_consolidations_mut() + .push(consolidation) + .unwrap(); + + let source_effective_balance = state.validator(0).unwrap().effective_balance; + let source_balance_before = state.balance(0).unwrap(); + let target_balance_before = state.balance(1).unwrap(); + + process_pending_consolidations(&mut state, &config).unwrap(); + + let moved = source_balance_before.min(source_effective_balance); + assert_eq!(state.balance(0).unwrap(), source_balance_before - moved); + assert_eq!(state.balance(1).unwrap(), target_balance_before + moved); + let mut fields = pending_queue_fields(&mut state, "test assertion").unwrap(); + assert!(fields.pending_consolidations_mut().is_empty()); + } + + // ----------------------------------------------------------------------- + // process_registry_updates + // ----------------------------------------------------------------------- + + #[test] + fn every_finalized_eligible_validator_activates_the_same_epoch_uncapped_by_headcount() { + let config = Config::mainnet(); + // More candidates than phase0's old count-based churn limit would + // ever admit in one epoch, to make the absence of that cap here + // unmistakable. + let count = config.min_per_epoch_churn_limit as usize + 4; + let mut state = electra_state_with_validators(count); + + for index in 0..count as ValidatorIndex { + let validator = state.validator_mut(index).unwrap(); + validator.activation_eligibility_epoch = 0; // already finalized + validator.activation_epoch = FAR_FUTURE_EPOCH; // not yet activated + } + + process_registry_updates(&mut state, &config).unwrap(); + + for index in 0..count as ValidatorIndex { + assert_ne!( + state.validator(index).unwrap().activation_epoch, + FAR_FUTURE_EPOCH, + "validator {index} should have activated: electra rate-limits admission by \ + balance, not by a per-epoch headcount", + ); + } + } + + // ----------------------------------------------------------------------- + // process_effective_balance_updates + // ----------------------------------------------------------------------- + + #[test] + fn effective_balance_updates_cap_a_compounding_validator_higher_than_a_regular_one() { + let mut state = electra_state_with_validators(2); + state.validator_mut(1).unwrap().withdrawal_credentials.0[0] = + constants::COMPOUNDING_WITHDRAWAL_PREFIX; + + // Push both balances far above either ceiling, so the update fires + // and both validators are actually capped, not merely nudged. + let huge = preset::MAX_EFFECTIVE_BALANCE_ELECTRA + preset::EFFECTIVE_BALANCE_INCREMENT; + state.balances_mut()[0] = huge; + state.balances_mut()[1] = huge; + + process_effective_balance_updates(&mut state).unwrap(); + + assert_eq!( + state.validator(0).unwrap().effective_balance, + preset::MIN_ACTIVATION_BALANCE, + "a non-compounding validator is still capped at MIN_ACTIVATION_BALANCE" + ); + assert_eq!( + state.validator(1).unwrap().effective_balance, + preset::MAX_EFFECTIVE_BALANCE_ELECTRA, + "a compounding validator's ceiling is MAX_EFFECTIVE_BALANCE_ELECTRA instead" + ); + } + + // ----------------------------------------------------------------------- + // process_slashings + // ----------------------------------------------------------------------- + + /// A slashing outside the withdrawable window must leave the balance + /// untouched, the same guard `super::registry::process_slashings` has. + #[test] + fn a_slashing_outside_the_withdrawable_window_is_untouched() { + let config = Config::mainnet(); + let mut state = electra_state_with_validators(4); + let balance_before = state.balance(1).unwrap(); + + state.validator_mut(1).unwrap().slashed = true; + state.slashings_mut()[0] = preset::MAX_EFFECTIVE_BALANCE_ELECTRA; + + process_slashings(&mut state, &config).unwrap(); + + assert_eq!(state.balance(1).unwrap(), balance_before); + } + + /// A worked example of the divergence [`process_slashings`]'s own doc + /// describes. A slashed sum equal to `total_increments` (the total active + /// balance's own increment count) is dwarfed by `total_balance` itself, + /// which is `total_increments` whole copies of `EFFECTIVE_BALANCE_INCREMENT`, + /// but it is exactly enough for electra's own division, + /// `adjusted_total_slashing_balance / total_increments`, to clear its + /// floor: the two cancel to precisely `multiplier`, with nothing left + /// over. `super::registry::process_slashings` divides by the raw + /// `total_balance` instead of `total_increments`, a divisor larger by a + /// factor of `EFFECTIVE_BALANCE_INCREMENT`, so the identical input never + /// clears *that* floor and rounds down to no penalty at all. + /// + /// This is not a contrived corner case: it is the ordinary shape of a + /// single validator's slashing measured against a whole active set's + /// balance, which is exactly why reusing the shared, pre-electra copy for + /// this fork would silently drop real penalties rather than merely + /// rounding them differently. + #[test] + fn electras_division_order_still_penalizes_where_the_shared_copy_rounds_to_zero() { + let config = Config::mainnet(); + let mut state = electra_state_with_validators(4); + let epoch = get_current_epoch(&state); + + let total_balance = get_total_active_balance(&state).unwrap(); + let total_increments = total_balance / preset::EFFECTIVE_BALANCE_INCREMENT; + let multiplier = preset::retuned::proportional_slashing_multiplier(state.fork_name()); + + let validator = state.validator_mut(1).unwrap(); + validator.slashed = true; + validator.withdrawable_epoch = epoch + (preset::EPOCHS_PER_SLASHINGS_VECTOR / 2) as Epoch; + let effective_balance_increments = + validator.effective_balance / preset::EFFECTIVE_BALANCE_INCREMENT; + + state.slashings_mut()[0] = total_increments; + + let mut shared_copy_state = state.clone(); + process_slashings(&mut state, &config).unwrap(); + super::super::registry::process_slashings(&mut shared_copy_state, &config).unwrap(); + + let expected_penalty = multiplier * effective_balance_increments; + assert_eq!( + preset::MIN_ACTIVATION_BALANCE - state.balance(1).unwrap(), + expected_penalty, + "electra's own division order lands exactly multiplier * effective_balance_increments" + ); + assert_eq!( + shared_copy_state.balance(1).unwrap(), + preset::MIN_ACTIVATION_BALANCE, + "the shared, pre-electra copy rounds the exact same inputs down to no penalty at all" + ); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/epoch/fulu.rs b/crates/blockchain/state_transition/src/beacon/stf/epoch/fulu.rs new file mode 100644 index 000000000..0975158e9 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/epoch/fulu.rs @@ -0,0 +1,180 @@ +//! Fulu-specific epoch processing. +//! +//! Electra's whole step list carries over unchanged: fulu's "Epoch processing" +//! section (`beacon-chain.md`) redefines `process_epoch` only to append one new +//! step, [`process_proposer_lookahead`] (EIP-7917), after electra's last one. +//! Nothing about how any existing step behaves changes; the state simply grows +//! one more piece of bookkeeping for [`process_proposer_lookahead`] to +//! maintain. +//! +//! [`process_proposer_lookahead`] keeps `BeaconState::proposer_lookahead` +//! (`crate::beacon::containers::fulu::BeaconState`) a fixed-length rolling window: it +//! drops the epoch that just ended (the window's oldest slice) and appends the +//! one epoch further out than the window already reached, so the window keeps +//! covering exactly the current epoch through `MIN_SEED_LOOKAHEAD` epochs +//! beyond it, the same span +//! [`crate::beacon::helpers::fulu::initialize_proposer_lookahead`] fills from scratch +//! at genesis and at the fulu upgrade. See that function's module docs for why +//! a seed, and therefore a proposer, is only ever knowable that far ahead and +//! no further. +//! +//! # Why this step runs last +//! +//! The newly-visible epoch's proposers come from +//! [`crate::beacon::helpers::fulu::get_beacon_proposer_indices`], which weighs +//! [`crate::beacon::helpers::accessors::get_active_validator_indices`] and each +//! validator's `effective_balance`, both of which earlier steps in this same +//! epoch's processing change: [`super::registry::process_registry_updates`] +//! moves validators into or out of the active set, and +//! [`super::process_effective_balance_updates`] moves balances toward their +//! post-epoch values. Running [`process_proposer_lookahead`] after every such +//! step, rather than before, is what lets the newly-appended epoch's proposers +//! reflect this epoch's final registry state rather than a stale one; the +//! specification gets that simply by placing the step last, and this driver +//! does the same. +//! +//! The randao mix the new epoch's seed reads is not why the step sits where it +//! does. [`crate::beacon::helpers::accessors::get_seed`]'s lookback means the +//! newly-visible epoch's seed is drawn from the *current*, outgoing epoch's +//! mix, and that mix was already fixed by the last block processed in this +//! epoch, well before epoch processing starts. [`super::process_randao_mixes_reset`] +//! only ever writes the *next* epoch's slot, so running this step before or +//! after that reset would not change which mix the new epoch's seed reads; +//! only the registry and balance state matters for the ordering here. + +use crate::beacon::config::Config; +use crate::beacon::containers::BeaconState; +use crate::beacon::error::Result; +use crate::beacon::helpers::accessors::get_current_epoch; +use crate::beacon::helpers::fulu::{fulu_state, get_beacon_proposer_indices}; +use crate::beacon::preset; + +use super::electra; + +/// Fulu's epoch-boundary driver: electra's, unchanged, with +/// [`process_proposer_lookahead`] appended at the end. +pub fn process_epoch(state: &mut BeaconState, config: &Config) -> Result<()> { + electra::process_epoch(state, config)?; + process_proposer_lookahead(state) +} + +/// Shifts `proposer_lookahead` forward by one epoch. +/// +/// Drops the window's first `SLOTS_PER_EPOCH` entries (the epoch that just +/// ended) and appends `SLOTS_PER_EPOCH` more for the epoch that becomes +/// computable now that this epoch's registry and balance updates have run: see +/// the module docs for why appending happens last rather than first. +/// +/// The specification writes this as two in-place slice assignments on +/// `state.proposer_lookahead`. This instead builds the whole new window as a +/// plain `Vec` and assigns it back in one piece, since `SszVector` has no +/// `Default` to grow into and its `IndexMut` only ever addresses a window that +/// already exists at its full length; building the replacement value +/// explicitly, at exactly [`preset::PROPOSER_LOOKAHEAD_LENGTH`], sidesteps +/// needing one. +pub fn process_proposer_lookahead(state: &mut BeaconState) -> Result<()> { + // The seed for this epoch is only just now fixed, per the module docs, so + // this is the earliest moment its proposers could have been computed. + let new_epoch = get_current_epoch(state) + preset::MIN_SEED_LOOKAHEAD + 1; + let new_epoch_proposers = get_beacon_proposer_indices(state, new_epoch)?; + + let fulu_state = fulu_state(state, "process_proposer_lookahead")?; + let slots_per_epoch = preset::SLOTS_PER_EPOCH as usize; + + let mut window = Vec::with_capacity(preset::PROPOSER_LOOKAHEAD_LENGTH); + window.extend_from_slice(&fulu_state.proposer_lookahead[slots_per_epoch..]); + window.extend(new_epoch_proposers); + + fulu_state.proposer_lookahead = window.try_into().expect( + "dropping SLOTS_PER_EPOCH entries and appending SLOTS_PER_EPOCH more preserves \ + PROPOSER_LOOKAHEAD_LENGTH", + ); + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::fork::ForkName; + use crate::beacon::helpers::fulu::initialize_proposer_lookahead; + + /// A fulu state with `count` fully active, full-balance validators and a + /// `proposer_lookahead` filled by + /// [`crate::beacon::helpers::fulu::initialize_proposer_lookahead`], one epoch past + /// genesis. + /// + /// The shared builder leaves `proposer_lookahead` zeroed, since that + /// field is fulu-specific and most of this module's per-fork test states + /// never touch it; this module's own tests are exactly the ones that do, + /// so this runs the real computation on top before handing the state + /// back, the same override + /// `crate::beacon::helpers::fulu::tests::fulu_state_with_validators` applies. + fn fulu_state_with_validators(count: usize) -> BeaconState { + let mut state = + crate::beacon::helpers::test_state::with_validators_at(ForkName::Fulu, count); + let lookahead = initialize_proposer_lookahead(&state).unwrap(); + if let BeaconState::Fulu(fulu_state) = &mut state { + fulu_state.proposer_lookahead = lookahead.try_into().expect( + "initialize_proposer_lookahead returns exactly PROPOSER_LOOKAHEAD_LENGTH indices", + ); + } + state + } + + /// Reads out `proposer_lookahead` for assertions, without exposing the + /// fork-specific projection to every test. + fn lookahead_of(state: &BeaconState) -> Vec { + match state { + BeaconState::Fulu(state) => state.proposer_lookahead.to_vec(), + _ => unreachable!("test states here are always fulu"), + } + } + + #[test] + fn process_proposer_lookahead_preserves_the_carried_over_slice() { + let mut state = fulu_state_with_validators(32); + let before = lookahead_of(&state); + + process_proposer_lookahead(&mut state).unwrap(); + + let after = lookahead_of(&state); + let slots_per_epoch = preset::SLOTS_PER_EPOCH as usize; + // Everything but the oldest and newest epoch's worth of entries must + // carry over unchanged, just shifted down by one epoch's length. + assert_eq!( + after[..after.len() - slots_per_epoch], + before[slots_per_epoch..] + ); + } + + #[test] + fn process_proposer_lookahead_appends_the_newly_computable_epoch() { + let state = fulu_state_with_validators(32); + let current_epoch = get_current_epoch(&state); + let new_epoch = current_epoch + preset::MIN_SEED_LOOKAHEAD + 1; + let expected = get_beacon_proposer_indices(&state, new_epoch).unwrap(); + + let mut state = state; + process_proposer_lookahead(&mut state).unwrap(); + + let after = lookahead_of(&state); + let slots_per_epoch = preset::SLOTS_PER_EPOCH as usize; + assert_eq!(after[after.len() - slots_per_epoch..], expected[..]); + } + + #[test] + fn process_proposer_lookahead_keeps_the_window_at_its_fixed_length() { + let mut state = fulu_state_with_validators(32); + process_proposer_lookahead(&mut state).unwrap(); + assert_eq!( + lookahead_of(&state).len(), + preset::PROPOSER_LOOKAHEAD_LENGTH + ); + } + + #[test] + fn process_proposer_lookahead_rejects_a_state_older_than_fulu() { + let mut phase0_state = crate::beacon::helpers::test_state::with_validators(4); + assert!(process_proposer_lookahead(&mut phase0_state).is_err()); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/epoch/justification.rs b/crates/blockchain/state_transition/src/beacon/stf/epoch/justification.rs new file mode 100644 index 000000000..ecbadf293 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/epoch/justification.rs @@ -0,0 +1,253 @@ +//! Justification and finalization. +//! +//! Every epoch, the state re-weighs how much of the active balance attested to +//! the previous and current epoch's checkpoint and folds the result into +//! `justification_bits`, a four-epoch sliding window recording which of the +//! last four epochs reached the two-thirds threshold. Finalization then checks +//! that window for one of two shapes: two consecutively-justified epochs, or +//! three, with the extra epoch of slack existing so a single epoch that narrowly +//! misses justification does not also cost the chain finality for the epoch +//! before it. Each shape is checked from both the previous and the current +//! epoch's justified checkpoint, which is why there are four rules rather than +//! two. + +use crate::beacon::config::Config; +use crate::beacon::constants; +use crate::beacon::containers::{BeaconState, Checkpoint}; +use crate::beacon::error::{Error, Result}; +use crate::beacon::helpers::accessors::{ + get_block_root, get_current_epoch, get_previous_epoch, get_total_active_balance, +}; +use crate::beacon::primitives::Gwei; + +use super::{JUSTIFICATION_BITS, get_attesting_balance, get_matching_target_attestations}; + +/// Updates justification and finality from the attestations the previous and +/// current epoch collected. +/// +/// `config` is unused: this step needs no configuration value, but takes one +/// anyway so every step in [`super::process_epoch`]'s pipeline shares a call +/// shape. +pub fn process_justification_and_finalization( + state: &mut BeaconState, + _config: &Config, +) -> Result<()> { + // Initial FFG checkpoint values have a `0x00` stub for `root`. + // Skip FFG updates in the first two epochs to avoid corner cases that might + // result in modifying this stub. + if get_current_epoch(state) <= constants::GENESIS_EPOCH + 1 { + return Ok(()); + } + + let previous_attestations = get_matching_target_attestations(state, get_previous_epoch(state))?; + let current_attestations = get_matching_target_attestations(state, get_current_epoch(state))?; + let total_active_balance = get_total_active_balance(state)?; + let previous_target_balance = get_attesting_balance(state, &previous_attestations)?; + let current_target_balance = get_attesting_balance(state, ¤t_attestations)?; + weigh_justification_and_finalization( + state, + total_active_balance, + previous_target_balance, + current_target_balance, + ) +} + +/// Advances the justification bitfield and applies the four finalization rules +/// against it. +/// +/// The target balances are passed in rather than recomputed here so this can be +/// exercised (and reasoned about) independently of attestation matching, which +/// is what [`process_justification_and_finalization`] uses it for. +pub fn weigh_justification_and_finalization( + state: &mut BeaconState, + total_active_balance: Gwei, + previous_epoch_target_balance: Gwei, + current_epoch_target_balance: Gwei, +) -> Result<()> { + let previous_epoch = get_previous_epoch(state); + let current_epoch = get_current_epoch(state); + let old_previous_justified_checkpoint = state.previous_justified_checkpoint(); + let old_current_justified_checkpoint = state.current_justified_checkpoint(); + + // Process justifications + *state.previous_justified_checkpoint_mut() = state.current_justified_checkpoint(); + + // Age the bitfield by one epoch before folding in this epoch's result. Index + // 0 always names the epoch just processed, so ageing moves every bit toward + // a HIGHER index (older epochs); the oldest bit falls off the top and is + // lost. Reading index `i - 1` before writing index `i`, from the top down, + // reproduces the spec's simultaneous slice assignment without a temporary + // copy. + for i in (1..JUSTIFICATION_BITS).rev() { + let older = state + .justification_bits() + .get(i - 1) + .expect("index is within JUSTIFICATION_BITS_LENGTH"); + state + .justification_bits_mut() + .set(i, older) + .expect("index is within JUSTIFICATION_BITS_LENGTH"); + } + state + .justification_bits_mut() + .set(0, false) + .expect("index is within JUSTIFICATION_BITS_LENGTH"); + + if meets_justification_threshold(previous_epoch_target_balance, total_active_balance)? { + *state.current_justified_checkpoint_mut() = Checkpoint { + epoch: previous_epoch, + root: get_block_root(state, previous_epoch)?, + }; + state + .justification_bits_mut() + .set(1, true) + .expect("index is within JUSTIFICATION_BITS_LENGTH"); + } + if meets_justification_threshold(current_epoch_target_balance, total_active_balance)? { + *state.current_justified_checkpoint_mut() = Checkpoint { + epoch: current_epoch, + root: get_block_root(state, current_epoch)?, + }; + state + .justification_bits_mut() + .set(0, true) + .expect("index is within JUSTIFICATION_BITS_LENGTH"); + } + + // Process finalizations + // + // Read every bit the four rules need before touching `finalized_checkpoint`, + // since holding a `&JustificationBits` borrow across those writes would + // conflict with the `&mut BeaconState` each rule needs. + let (justifies_1_2_3, justifies_1_2, justifies_0_1_2, justifies_0_1) = { + let bits = state.justification_bits(); + let bit = |i: usize| { + bits.get(i) + .expect("index is within JUSTIFICATION_BITS_LENGTH") + }; + ( + bit(1) && bit(2) && bit(3), + bit(1) && bit(2), + bit(0) && bit(1) && bit(2), + bit(0) && bit(1), + ) + }; + + // The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source + if justifies_1_2_3 && old_previous_justified_checkpoint.epoch + 3 == current_epoch { + *state.finalized_checkpoint_mut() = old_previous_justified_checkpoint; + } + // The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source + if justifies_1_2 && old_previous_justified_checkpoint.epoch + 2 == current_epoch { + *state.finalized_checkpoint_mut() = old_previous_justified_checkpoint; + } + // The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source + if justifies_0_1_2 && old_current_justified_checkpoint.epoch + 2 == current_epoch { + *state.finalized_checkpoint_mut() = old_current_justified_checkpoint; + } + // The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source + if justifies_0_1 && old_current_justified_checkpoint.epoch + 1 == current_epoch { + *state.finalized_checkpoint_mut() = old_current_justified_checkpoint; + } + + Ok(()) +} + +/// Whether `balance` covers at least two-thirds of `total_active_balance`. +/// +/// Written as `balance * 3 >= total_active_balance * 2` to avoid a division, +/// matching the specification exactly. `total_active_balance` sums the whole +/// validator registry, so its product is checked rather than left to wrap: a +/// wrapped comparison could manufacture or hide a justification that the real +/// balances never earned. +fn meets_justification_threshold(balance: Gwei, total_active_balance: Gwei) -> Result { + let weighed_balance = balance.checked_mul(3).ok_or(Error::ArithmeticOverflow( + "weigh_justification_and_finalization", + ))?; + let weighed_total = total_active_balance + .checked_mul(2) + .ok_or(Error::ArithmeticOverflow( + "weigh_justification_and_finalization", + ))?; + Ok(weighed_balance >= weighed_total) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::config::Config; + + #[test] + fn near_genesis_process_is_a_no_op() { + // `with_validators` positions the state at slot `SLOTS_PER_EPOCH`, i.e. + // current epoch 1, which is still within the `GENESIS_EPOCH + 1` guard. + let mut state = crate::beacon::helpers::test_state::with_validators(4); + let before = state.clone(); + let config = Config::mainnet(); + + process_justification_and_finalization(&mut state, &config).unwrap(); + + assert_eq!( + state.justification_bits(), + before.justification_bits(), + "the bitfield must be untouched this close to genesis" + ); + assert_eq!( + state.current_justified_checkpoint(), + before.current_justified_checkpoint() + ); + assert_eq!(state.finalized_checkpoint(), before.finalized_checkpoint()); + } + + #[test] + fn only_the_previous_epoch_bit_is_set_when_only_it_justifies() { + // `with_validators` positions the state at current epoch 1, previous + // epoch 0, which is enough to exercise `weigh_justification_and_finalization` + // directly without needing to build real attestations: it takes the + // target balances as arguments. + let mut state = crate::beacon::helpers::test_state::with_validators(4); + let total_active_balance: Gwei = 300; + let previous_epoch_target_balance: Gwei = 200; // exactly two-thirds: justifies + let current_epoch_target_balance: Gwei = 0; // nowhere near: does not justify + + weigh_justification_and_finalization( + &mut state, + total_active_balance, + previous_epoch_target_balance, + current_epoch_target_balance, + ) + .unwrap(); + + let bits = state.justification_bits(); + assert_eq!(bits.get(0), Some(false), "current epoch did not justify"); + assert_eq!(bits.get(1), Some(true), "previous epoch justified"); + assert_eq!(bits.get(2), Some(false)); + assert_eq!(bits.get(3), Some(false)); + + assert_eq!(state.current_justified_checkpoint().epoch, 0); + // Only one epoch justified this round, so none of the four finalization + // rules (each needing two or three consecutive justified epochs) fire. + assert_eq!(state.finalized_checkpoint().epoch, constants::GENESIS_EPOCH); + } + + #[test] + fn a_below_threshold_balance_justifies_neither_epoch() { + let mut state = crate::beacon::helpers::test_state::with_validators(4); + let total_active_balance: Gwei = 300; + + weigh_justification_and_finalization(&mut state, total_active_balance, 199, 199).unwrap(); + + let bits = state.justification_bits(); + assert_eq!(bits.get(0), Some(false)); + assert_eq!(bits.get(1), Some(false)); + } + + #[test] + fn an_overflowing_balance_is_reported_rather_than_wrapped() { + let mut state = crate::beacon::helpers::test_state::with_validators(4); + + let result = weigh_justification_and_finalization(&mut state, Gwei::MAX, Gwei::MAX, 0); + + assert!(matches!(result, Err(Error::ArithmeticOverflow(_)))); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/epoch/mod.rs b/crates/blockchain/state_transition/src/beacon/stf/epoch/mod.rs new file mode 100644 index 000000000..fa3bcba97 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/epoch/mod.rs @@ -0,0 +1,321 @@ +//! Epoch processing. +//! +//! Runs on the last slot of every epoch. Phase0 does the bulk of its accounting +//! here rather than as attestations arrive, because the reward an attestation +//! earns depends on facts that are not settled when it is included: whether its +//! target became the canonical block for the epoch, and whether the chain is +//! finalizing at all. So attestations accumulate in the state and are replayed +//! here. +//! +//! Order matters between these steps, and in two places it is load-bearing: +//! +//! - Justification and finalization runs before rewards, so rewards are computed +//! against the finality state the attestations themselves produced. +//! - Registry updates run before slashings, so a validator that exits this epoch +//! is already exiting when the slashing penalty is scaled. + +pub mod altair; +pub mod capella; +pub mod electra; +pub mod fulu; +pub mod justification; +pub mod registry; +pub mod rewards; + +use crate::beacon::containers::phase0::PendingAttestation; +use crate::beacon::containers::{BeaconState, HistoricalBatch}; +use crate::beacon::error::{Result, verify}; +use crate::beacon::fork::ForkName; +use crate::beacon::helpers::accessors::{ + get_block_root, get_block_root_at_slot, get_current_epoch, get_previous_epoch, get_randao_mix, + get_total_balance, +}; +use crate::beacon::lean_state_unreachable; +use crate::beacon::preset; +use crate::beacon::primitives::{Epoch, Gwei, HashTreeRoot as _, ValidatorIndex}; +use crate::beacon::{config::Config, constants}; + +use super::phase0_state; + +/// Phase0's epoch-boundary driver, in the specification's order. +/// +/// Named explicitly, unlike [`altair::process_epoch`] and every later fork's +/// own driver, only because this one predates [`process_epoch`] below: phase0 +/// has no module of its own elsewhere in [`crate::beacon::stf`] the way every later +/// fork does, so its driver stays here rather than moving to one. +pub fn process_epoch_phase0(state: &mut BeaconState, config: &Config) -> Result<()> { + justification::process_justification_and_finalization(state, config)?; + rewards::process_rewards_and_penalties(state, config)?; + registry::process_registry_updates(state, config)?; + registry::process_slashings(state, config)?; + process_eth1_data_reset(state)?; + process_effective_balance_updates(state)?; + process_slashings_reset(state)?; + process_randao_mixes_reset(state)?; + process_historical_roots_update(state)?; + process_participation_record_updates(state)?; + Ok(()) +} + +/// Runs every epoch-boundary step, dispatching on the state's own fork. +/// +/// Phase0 and altair each have a driver of their own already; every later +/// fork either reuses an earlier one unchanged or gets a stub of its own here, +/// to be filled in once that fork's own epoch-processing steps are written. +/// Which is which is settled by `beacon-chain.md`'s "Epoch processing" section +/// for each fork, not assumed: +/// +/// - Bellatrix's section only modifies `get_inactivity_penalty_deltas` and +/// `slash_validator`, two helpers the driver calls into, and never redefines +/// `process_epoch` itself, so this reuses altair's driver unchanged. +/// - Capella's section gives a full, modified `process_epoch` (it swaps +/// `process_historical_roots_update` for `process_historical_summaries_update`), +/// so it gets its own stub. +/// - Deneb's section only modifies `process_registry_updates` (EIP-7514's +/// activation churn limit), a helper the driver already calls uniformly +/// across forks, and never redefines `process_epoch` itself, so this reuses +/// capella's driver. +/// - Electra's and fulu's sections each give a full, modified `process_epoch` +/// (electra adds the pending-deposit and pending-consolidation steps; +/// fulu appends the proposer-lookahead step), so each gets its own stub. +pub fn process_epoch(state: &mut BeaconState, config: &Config) -> Result<()> { + match state.fork_name() { + ForkName::Phase0 => process_epoch_phase0(state, config), + ForkName::Altair => altair::process_epoch(state, config), + ForkName::Bellatrix => altair::process_epoch(state, config), + ForkName::Capella => capella::process_epoch(state, config), + ForkName::Deneb => capella::process_epoch(state, config), + ForkName::Electra => electra::process_epoch(state, config), + ForkName::Fulu => fulu::process_epoch(state, config), + ForkName::Lean => lean_state_unreachable("process_epoch"), + } +} + +/// Updates justification and finality, dispatching on the state's own fork. +/// +/// Every fork's driver already reaches its own version of this step directly, +/// so this dispatcher exists for the one caller that runs the step *outside* a +/// driver: [`crate::beacon::fork_choice::compute_pulled_up_tip`], which advances a +/// throwaway copy of a block's post-state just far enough to learn what +/// justification and finality that chain is heading towards. Fork choice has no +/// business knowing which fork's rules to reach for, so it asks here. +/// +/// Altair rewrote the step to read participation flags instead of replaying +/// stored attestations, and no later fork changes it again, so altair's version +/// serves everything from altair on. +pub fn process_justification_and_finalization( + state: &mut BeaconState, + config: &Config, +) -> Result<()> { + match state.fork_name() { + ForkName::Phase0 => justification::process_justification_and_finalization(state, config), + _ => altair::process_justification_and_finalization(state), + } +} + +// --------------------------------------------------------------------------- +// Attestation matching +// --------------------------------------------------------------------------- + +/// The attestations the state retained for `epoch`. +/// +/// Only the current and previous epoch are available, since those are the only +/// two the state keeps. +pub fn get_matching_source_attestations( + state: &BeaconState, + epoch: Epoch, +) -> Result> { + let current = get_current_epoch(state); + verify( + epoch == current || epoch == get_previous_epoch(state), + "attestations are only retained for the current and previous epoch", + )?; + + let state = super::phase0_state_ref(state, "get_matching_source_attestations")?; + let attestations = if epoch == current { + &state.current_epoch_attestations + } else { + &state.previous_epoch_attestations + }; + Ok(attestations.to_vec()) +} + +/// Those whose target is the epoch's canonical block, meaning the attester agreed +/// with this chain about what the epoch's checkpoint is. +pub fn get_matching_target_attestations( + state: &BeaconState, + epoch: Epoch, +) -> Result> { + let source = get_matching_source_attestations(state, epoch)?; + + // The early return is load-bearing, not an optimization. The specification + // writes this as a list comprehension, so `get_block_root` is evaluated per + // element and never at all when there are no attestations. It has its own + // range assertion, which fails for the epoch a state sits at the very start + // of, so hoisting the call out of the loop would reject states the + // specification accepts. + if source.is_empty() { + return Ok(Vec::new()); + } + + let block_root = get_block_root(state, epoch)?; + Ok(source + .into_iter() + .filter(|attestation| attestation.data.target.root == block_root) + .collect()) +} + +/// Those that also agreed about the head block at their own slot, which is the +/// strictest of the three and the only one that depends on the attester having +/// been up to date at the time. +pub fn get_matching_head_attestations( + state: &BeaconState, + epoch: Epoch, +) -> Result> { + let mut matching = Vec::new(); + for attestation in get_matching_target_attestations(state, epoch)? { + let root = get_block_root_at_slot(state, attestation.data.slot)?; + if attestation.data.beacon_block_root == root { + matching.push(attestation); + } + } + Ok(matching) +} + +/// The union of the attesters in `attestations`, minus those since slashed. +/// +/// Sorted and deduplicated, since callers use it both as a set and to index the +/// registry in order. +pub fn get_unslashed_attesting_indices( + state: &BeaconState, + attestations: &[PendingAttestation], +) -> Result> { + let mut indices = Vec::new(); + for attestation in attestations { + let committee = crate::beacon::helpers::accessors::get_beacon_committee( + state, + attestation.data.slot, + attestation.data.index, + )?; + for (position, index) in committee.into_iter().enumerate() { + if attestation.aggregation_bits.get(position).unwrap_or(false) { + indices.push(index); + } + } + } + + indices.sort_unstable(); + indices.dedup(); + indices.retain(|index| { + state + .validator(*index) + .is_ok_and(|validator| !validator.slashed) + }); + Ok(indices) +} + +/// The combined effective balance of the unslashed attesters in `attestations`. +pub fn get_attesting_balance( + state: &BeaconState, + attestations: &[PendingAttestation], +) -> Result { + let indices = get_unslashed_attesting_indices(state, attestations)?; + get_total_balance(state, &indices) +} + +// --------------------------------------------------------------------------- +// Resets and rotations +// --------------------------------------------------------------------------- + +/// Clears the eth1 vote tally at the end of each voting period. +pub fn process_eth1_data_reset(state: &mut BeaconState) -> Result<()> { + let next_epoch = get_current_epoch(state) + 1; + if next_epoch.is_multiple_of(preset::EPOCHS_PER_ETH1_VOTING_PERIOD) { + *state.eth1_data_votes_mut() = Default::default(); + } + Ok(()) +} + +/// Moves each validator's effective balance toward its actual balance. +/// +/// The two thresholds are hysteresis: a balance has to move meaningfully past the +/// boundary before the effective balance follows it. Without that, a validator +/// hovering at an increment boundary would change effective balance every epoch, +/// and since effective balance feeds the shuffling seed's weighting and every +/// reward, that would churn far more than it measures. +pub fn process_effective_balance_updates(state: &mut BeaconState) -> Result<()> { + const HYSTERESIS_INCREMENT: Gwei = + preset::EFFECTIVE_BALANCE_INCREMENT / preset::HYSTERESIS_QUOTIENT; + const DOWNWARD_THRESHOLD: Gwei = HYSTERESIS_INCREMENT * preset::HYSTERESIS_DOWNWARD_MULTIPLIER; + const UPWARD_THRESHOLD: Gwei = HYSTERESIS_INCREMENT * preset::HYSTERESIS_UPWARD_MULTIPLIER; + + // Decided in one pass and applied in another. The state is an enum over + // per-fork structs, so the accessors hand out a borrow of the whole state + // rather than of one field, and there is no way to hold `validators` mutably + // while reading `balances`. Collecting the decisions first keeps this + // fork-independent, which matters because every fork runs this step + // unchanged. + let mut updates = Vec::new(); + for (index, validator) in state.validators().iter().enumerate() { + let balance = state.balances()[index]; + if balance + DOWNWARD_THRESHOLD < validator.effective_balance + || validator.effective_balance + UPWARD_THRESHOLD < balance + { + let effective = (balance - balance % preset::EFFECTIVE_BALANCE_INCREMENT) + .min(preset::MAX_EFFECTIVE_BALANCE); + updates.push((index, effective)); + } + } + + let validators = state.validators_mut(); + for (index, effective) in updates { + validators[index].effective_balance = effective; + } + Ok(()) +} + +/// Zeroes the slot the slashings ring buffer is about to reuse. +pub fn process_slashings_reset(state: &mut BeaconState) -> Result<()> { + let next_epoch = get_current_epoch(state) + 1; + let position = next_epoch as usize % preset::EPOCHS_PER_SLASHINGS_VECTOR; + state.slashings_mut()[position] = 0; + Ok(()) +} + +/// Seeds the next epoch's randao slot with the current epoch's mix. +pub fn process_randao_mixes_reset(state: &mut BeaconState) -> Result<()> { + let current_epoch = get_current_epoch(state); + let mix = get_randao_mix(state, current_epoch); + let position = (current_epoch + 1) as usize % preset::EPOCHS_PER_HISTORICAL_VECTOR; + state.randao_mixes_mut()[position] = mix; + Ok(()) +} + +/// Folds the block and state root vectors into one historical root when they are +/// about to wrap. +/// +/// This is what keeps history provable after the ring buffers overwrite it: the +/// roots themselves are dropped, but a commitment to them is kept forever. +pub fn process_historical_roots_update(state: &mut BeaconState) -> Result<()> { + let next_epoch = get_current_epoch(state) + 1; + let epochs_per_historical_root = + (preset::SLOTS_PER_HISTORICAL_ROOT / preset::SLOTS_PER_EPOCH as usize) as Epoch; + if next_epoch.is_multiple_of(epochs_per_historical_root) { + let batch = HistoricalBatch { + block_roots: state.block_roots().clone(), + state_roots: state.state_roots().clone(), + }; + state.historical_roots_mut().push(batch.hash_tree_root())?; + } + Ok(()) +} + +/// Rotates the retained attestations, discarding those two epochs old. +pub fn process_participation_record_updates(state: &mut BeaconState) -> Result<()> { + let state = phase0_state(state, "process_participation_record_updates")?; + state.previous_epoch_attestations = core::mem::take(&mut state.current_epoch_attestations); + Ok(()) +} + +/// The number of epochs of attestation history the justification bitfield holds. +pub(crate) const JUSTIFICATION_BITS: usize = constants::JUSTIFICATION_BITS_LENGTH; diff --git a/crates/blockchain/state_transition/src/beacon/stf/epoch/registry.rs b/crates/blockchain/state_transition/src/beacon/stf/epoch/registry.rs new file mode 100644 index 000000000..5c8f30dc2 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/epoch/registry.rs @@ -0,0 +1,386 @@ +//! Registry updates and slashings. +//! +//! Both functions walk the whole validator registry once per epoch: the first +//! moves validators between activation and exit states, the second applies the +//! deferred part of a slashing penalty. + +use crate::beacon::config::Config; +use crate::beacon::containers::BeaconState; +use crate::beacon::error::{Error, Result}; +use crate::beacon::fork::ForkName; +use crate::beacon::helpers::accessors::{ + get_current_epoch, get_total_active_balance, get_validator_churn_limit, +}; +use crate::beacon::helpers::misc::compute_activation_exit_epoch; +use crate::beacon::helpers::mutators::{decrease_balance, initiate_validator_exit}; +use crate::beacon::helpers::predicates::{ + is_active_validator, is_eligible_for_activation, is_eligible_for_activation_queue, +}; +use crate::beacon::lean_state_unreachable; +use crate::beacon::preset; +use crate::beacon::primitives::{Epoch, Gwei, ValidatorIndex}; + +/// The cap on how many validators may newly activate this epoch. +/// +/// Phase0 through capella cap activations only indirectly, as part of the +/// combined activation/exit churn limit ([`get_validator_churn_limit`]). +/// Deneb adds a second, independent ceiling on activations specifically +/// (EIP-7514, `MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT` in [`Config`]), so that a +/// single epoch's whole churn budget cannot be spent activating new +/// validators and leave none of it for the exits already in flight. +/// +/// Electra replaces [`process_registry_updates`] wholesale with a +/// balance-denominated version (`get_balance_churn_limit`), which belongs to +/// whichever module implements electra rather than here, and the +/// specification never revives a validator-count churn limit for fulu after +/// that. Calling this for electra or fulu would silently apply deneb's rule +/// where the specification no longer has one at all, so both are refused +/// outright rather than guessed at; see [`process_registry_updates`]'s own +/// documentation for exactly which forks that leaves this serving. +fn activation_churn_limit(state: &BeaconState, config: &Config) -> Result { + let churn_limit = get_validator_churn_limit(state, config); + match state.fork_name() { + ForkName::Phase0 | ForkName::Altair | ForkName::Bellatrix | ForkName::Capella => { + Ok(churn_limit) + } + ForkName::Deneb => Ok(config.max_per_epoch_activation_churn_limit.min(churn_limit)), + fork @ (ForkName::Electra | ForkName::Fulu) => Err(Error::UnsupportedForFork { + function: "process_registry_updates", + fork, + }), + ForkName::Lean => lean_state_unreachable("activation_churn_limit"), + } +} + +/// Moves validators between activation and exit states. +/// +/// Three passes, and the order between them matters. The first marks +/// validators newly eligible for the activation queue and starts exiting +/// anyone whose balance has fallen to the ejection floor; both checks read the +/// registry as it stood at the start of the epoch, before either pass changes +/// anything. The second builds the activation queue from eligibility as it +/// stands after that pass, so a validator ejected and a validator freshly +/// eligible in the same epoch are both accounted for before anyone activates. +/// +/// One copy of this function serves phase0 through deneb. Deneb's own change +/// (EIP-7514) is confined to which cap the third pass dequeues against, so it +/// is selected by fork through [`activation_churn_limit`] rather than +/// duplicating the three passes around it, the same reuse-by-value pattern +/// [`super::process_slashings`] already uses for its own per-fork multiplier. +/// Electra redefines every pass, not just the cap, so it is a wholly separate +/// function the crate's electra module owns, and fulu never revives a +/// validator-count rule after that; [`activation_churn_limit`] refuses to run +/// for either, so this function does too, rather than letting an electra or +/// fulu state silently activate validators under deneb's superseded rule. +pub fn process_registry_updates(state: &mut BeaconState, config: &Config) -> Result<()> { + let current_epoch = get_current_epoch(state); + let validator_count = state.validators().len() as ValidatorIndex; + + // `initiate_validator_exit` itself scans every validator's exit epoch to + // find the queue's current tail, which needs `state` uncommitted to any + // other borrow. Collecting the indices first, rather than calling it from + // inside a loop that also holds a reference into the registry, is what + // keeps that scan free to run. + let mut to_eject = Vec::new(); + for index in 0..validator_count { + if is_eligible_for_activation_queue(state.validator(index)?) { + state.validator_mut(index)?.activation_eligibility_epoch = current_epoch + 1; + } + + let validator = state.validator(index)?; + if is_active_validator(validator, current_epoch) + && validator.effective_balance <= config.ejection_balance + { + to_eject.push(index); + } + } + for index in to_eject { + initiate_validator_exit(state, index, config)?; + } + + // Queue validators eligible for activation and not yet dequeued. The sort + // key pairs the eligibility epoch with the validator index so that two + // validators becoming eligible in the same epoch still activate in the + // same order on every client, rather than in whatever order the registry + // happens to store them. + let finalized_epoch = state.finalized_checkpoint().epoch; + let mut activation_queue: Vec = (0..validator_count) + .filter(|&index| { + is_eligible_for_activation( + state + .validator(index) + .expect("index is within the registry"), + finalized_epoch, + ) + }) + .collect(); + activation_queue.sort_by_key(|&index| { + let validator = state + .validator(index) + .expect("index is within the registry"); + (validator.activation_eligibility_epoch, index) + }); + + // Dequeue validators for activation up to the churn limit. + let churn_limit = activation_churn_limit(state, config)? as usize; + let activation_epoch = compute_activation_exit_epoch(current_epoch); + for &index in activation_queue.iter().take(churn_limit) { + state.validator_mut(index)?.activation_epoch = activation_epoch; + } + + Ok(()) +} + +/// Applies the deferred part of every slashing whose penalty falls due this +/// epoch. +/// +/// `slash_validator` only takes an immediate cut of the slashed validator's +/// balance; the rest is scaled by how much of the whole active balance was +/// slashed in the surrounding window and applied here, `EPOCHS_PER_SLASHINGS_VECTOR` +/// divided by two after the offence. Scaling by the fraction of the registry +/// slashed together is what makes a coordinated attack cost far more per +/// validator than an isolated slashable mistake. +/// +/// Takes `config` only to match the signature every other step of +/// [`super::process_epoch`]'s pipeline is called with; the specification's +/// version of this function takes no configuration, since the multiplier and +/// the slashings window are both presets, not chain configuration. +/// +/// One copy of this function serves phase0 through deneb. Altair and +/// bellatrix each raise the proportional multiplier and nothing else, which +/// the specification expresses by redefining the whole function around a new +/// constant; here the value is selected by fork through [`preset::retuned`] +/// instead, the same reuse-by-value pattern [`process_registry_updates`] uses +/// for its own deneb-only change. +/// +/// Electra (EIP-7251) is not another multiplier swap: it restructures the +/// division itself, so this copy stops being correct there. Where this +/// function divides `effective_balance_increments * adjusted_total_slashing_balance` +/// by the raw `total_balance` and multiplies the result back up by +/// `increment` at the end, electra's version divides +/// `adjusted_total_slashing_balance` by `total_balance / increment` once, up +/// front, and multiplies that shared quotient by each validator's own +/// `effective_balance_increments` instead. The two orders are not equivalent +/// under integer division, and electra's own copy in +/// [`super::electra::process_slashings`] is where that difference is worked +/// through with a concrete example; fulu never mentions this function again, +/// so it reuses electra's copy the same way it reuses everything else electra +/// last redefined. +pub fn process_slashings(state: &mut BeaconState, _config: &Config) -> Result<()> { + let epoch = get_current_epoch(state); + let total_balance = get_total_active_balance(state)?; + + let mut slashed_sum: Gwei = 0; + for &slashing in state.slashings().iter() { + slashed_sum = slashed_sum + .checked_add(slashing) + .ok_or(Error::ArithmeticOverflow("summing the slashings vector"))?; + } + let multiplier = preset::retuned::proportional_slashing_multiplier(state.fork_name()); + let scaled_slashings = slashed_sum + .checked_mul(multiplier) + .ok_or(Error::ArithmeticOverflow( + "scaling the summed slashings by the proportional multiplier", + ))?; + let adjusted_total_slashing_balance = scaled_slashings.min(total_balance); + + let withdrawable_offset = (preset::EPOCHS_PER_SLASHINGS_VECTOR / 2) as Epoch; + + // Collecting the penalties before applying any of them keeps this pass + // reading a stable registry: `decrease_balance` only touches the balances + // vector, not the validator being read here, but every other mutator in + // this module needs the same shape, so this one follows suit. + let mut penalties = Vec::new(); + for (index, validator) in state.validators().iter().enumerate() { + if validator.slashed && epoch + withdrawable_offset == validator.withdrawable_epoch { + // Factored out from the penalty numerator to avoid a `uint64` + // overflow, exactly as the specification does; multiplying before + // dividing (rather than the algebraically equivalent other order) + // is what reproduces the specification's integer rounding. + let increment = preset::EFFECTIVE_BALANCE_INCREMENT; + let penalty_numerator = (validator.effective_balance / increment) + .checked_mul(adjusted_total_slashing_balance) + .ok_or(Error::ArithmeticOverflow( + "computing a validator's slashing penalty numerator", + ))?; + let penalty = penalty_numerator / total_balance * increment; + penalties.push((index as ValidatorIndex, penalty)); + } + } + + for (index, penalty) in penalties { + decrease_balance(state, index, penalty)?; + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::constants::FAR_FUTURE_EPOCH; + + /// A deneb state with `count` fully active, full-balance validators, + /// positioned one epoch in, the same shape + /// [`crate::beacon::helpers::test_state::with_validators`] builds for phase0. + /// + /// A thin wrapper around the shared fork-parameterised builder: see + /// [`crate::beacon::helpers::test_state::with_validators_at`] for the construction + /// this and every other fork's test module used to duplicate. + fn deneb_state_with_validators(count: usize) -> BeaconState { + crate::beacon::helpers::test_state::with_validators_at(ForkName::Deneb, count) + } + + /// Deneb's EIP-7514 cap must bind even when the plain validator-count + /// churn limit alone would let more validators through: enough of these + /// validators are already active that [`get_validator_churn_limit`] + /// exceeds [`Config::max_per_epoch_activation_churn_limit`], so a state + /// still running phase0's rule would activate more of the queued + /// validators below than deneb's is allowed to. + #[test] + fn deneb_caps_activation_churn_below_the_validator_count_limit() { + let config = Config::minimal(); + let active_count = 200; + let queued_count = 10; + let mut state = deneb_state_with_validators(active_count + queued_count); + + // Everyone from `active_count` on is eligible for activation but not + // yet active; everyone before them already is, active from genesis + // by `deneb_state_with_validators`'s own construction. + for index in active_count..(active_count + queued_count) { + let validator = state.validator_mut(index as ValidatorIndex).unwrap(); + validator.activation_epoch = FAR_FUTURE_EPOCH; + validator.activation_eligibility_epoch = 0; + } + + let churn_limit = get_validator_churn_limit(&state, &config); + assert!( + churn_limit > config.max_per_epoch_activation_churn_limit, + "the active set must be large enough that the plain churn limit \ + alone exceeds deneb's cap, or this test is not exercising it" + ); + assert_eq!( + activation_churn_limit(&state, &config).unwrap(), + config.max_per_epoch_activation_churn_limit, + "the smaller of the two limits must win" + ); + + process_registry_updates(&mut state, &config).unwrap(); + + let activated = (active_count..(active_count + queued_count)) + .filter(|&index| { + state + .validator(index as ValidatorIndex) + .unwrap() + .activation_epoch + != FAR_FUTURE_EPOCH + }) + .count(); + assert_eq!( + activated, config.max_per_epoch_activation_churn_limit as usize, + "only the deneb cap's worth of queued validators should have activated this epoch" + ); + } + + /// Validators becoming eligible for activation in the same epoch must + /// dequeue in index order, since every client has to agree on which ones + /// take the churn limit's few slots. + #[test] + fn activation_ordering_breaks_ties_by_validator_index() { + let config = Config::mainnet(); + // None of these validators are active yet, so the churn limit is the + // configured floor rather than a share of the active set. A few more + // candidates than that floor leaves some outside the queue. + let count = config.min_per_epoch_churn_limit as usize + 2; + let mut state = crate::beacon::helpers::test_state::with_validators(count); + + // Every validator becomes eligible for activation in the same epoch, + // but the churn limit does not admit all of them. + for index in 0..count as ValidatorIndex { + let validator = state.validator_mut(index).unwrap(); + validator.activation_eligibility_epoch = 0; + validator.activation_epoch = FAR_FUTURE_EPOCH; + } + let churn_limit = get_validator_churn_limit(&state, &config); + assert_eq!(churn_limit, config.min_per_epoch_churn_limit); + assert!((churn_limit as usize) < count); + + process_registry_updates(&mut state, &config).unwrap(); + + for index in 0..churn_limit { + assert_ne!( + state.validator(index).unwrap().activation_epoch, + FAR_FUTURE_EPOCH, + "validator {index} is within the churn limit and should have activated", + ); + } + for index in churn_limit..count as ValidatorIndex { + assert_eq!( + state.validator(index).unwrap().activation_epoch, + FAR_FUTURE_EPOCH, + "validator {index} is past the churn limit and should still be queued", + ); + } + } + + /// A validator whose effective balance has fallen to the ejection floor + /// must be moved into the exit queue, even though nothing else about it + /// changed. + #[test] + fn a_validator_at_the_ejection_balance_is_queued_to_exit() { + let config = Config::mainnet(); + let mut state = crate::beacon::helpers::test_state::with_validators(4); + state.validator_mut(2).unwrap().effective_balance = config.ejection_balance; + + process_registry_updates(&mut state, &config).unwrap(); + + assert_ne!(state.validator(2).unwrap().exit_epoch, FAR_FUTURE_EPOCH); + } + + /// A validator just above the ejection floor is untouched. + #[test] + fn a_validator_above_the_ejection_balance_stays_active() { + let config = Config::mainnet(); + let mut state = crate::beacon::helpers::test_state::with_validators(4); + state.validator_mut(2).unwrap().effective_balance = config.ejection_balance + 1; + + process_registry_updates(&mut state, &config).unwrap(); + + assert_eq!(state.validator(2).unwrap().exit_epoch, FAR_FUTURE_EPOCH); + } + + /// A freshly slashed validator is not due a deferred penalty yet: the + /// window has not elapsed, so this epoch must leave its balance alone. + #[test] + fn slashings_outside_the_withdrawable_window_are_untouched() { + let config = Config::mainnet(); + let mut state = crate::beacon::helpers::test_state::with_validators(4); + let balance_before = state.balance(1).unwrap(); + + state.validator_mut(1).unwrap().slashed = true; + state.slashings_mut()[0] = preset::MAX_EFFECTIVE_BALANCE; + + process_slashings(&mut state, &config).unwrap(); + + assert_eq!(state.balance(1).unwrap(), balance_before); + } + + /// Once the withdrawable epoch arrives, the deferred penalty is applied, + /// scaled up by the whole slashed balance recorded in the window. + #[test] + fn a_slashing_due_this_epoch_reduces_the_balance() { + let config = Config::mainnet(); + let mut state = crate::beacon::helpers::test_state::with_validators(4); + let epoch = get_current_epoch(&state); + let balance_before = state.balance(1).unwrap(); + + let validator = state.validator_mut(1).unwrap(); + validator.slashed = true; + validator.withdrawable_epoch = epoch + (preset::EPOCHS_PER_SLASHINGS_VECTOR / 2) as Epoch; + state.slashings_mut()[0] = preset::MAX_EFFECTIVE_BALANCE; + + process_slashings(&mut state, &config).unwrap(); + + assert!(state.balance(1).unwrap() < balance_before); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/epoch/rewards.rs b/crates/blockchain/state_transition/src/beacon/stf/epoch/rewards.rs new file mode 100644 index 000000000..0c12655e7 --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/epoch/rewards.rs @@ -0,0 +1,372 @@ +//! Rewards and penalties. +//! +//! Every accounting pass here reads the attestations the previous epoch's +//! validators cast (buffered as `PendingAttestation`s and matched by slot, +//! target, and head in `super`) and turns them into one delta per validator: a +//! reward for a vote component that matched the canonical chain, a penalty for +//! one that did not, and, while the chain is failing to finalize, an +//! inactivity penalty that grows the longer finality stays stuck. Every reward +//! and penalty is proportional to [`get_base_reward`], itself inversely +//! proportional to the square root of the total active balance, so the +//! aggregate reward rate shrinks as the validator set grows rather than paying +//! a fixed amount per validator regardless of how many there are. +//! +//! [`process_rewards_and_penalties`] applies the results as two separate +//! passes, rewards then penalties, each through [`increase_balance`] and +//! [`decrease_balance`] rather than a single netted delta. That distinction is +//! load-bearing: [`decrease_balance`] floors at zero, and netting the two +//! before applying them would let a reward mask a penalty that should have +//! driven a low balance all the way down. +//! +//! # Why every component-delta function takes `config` +//! +//! None of phase0's own formulas below read a configuration value: every +//! divisor and threshold they use (`BASE_REWARD_FACTOR`, +//! `PROPOSER_REWARD_QUOTIENT`, `INACTIVITY_PENALTY_QUOTIENT`, +//! `MIN_EPOCHS_TO_INACTIVITY_PENALTY`) is a preset, resolved through +//! `crate::beacon::preset` at compile time with no argument needed. [`get_source_deltas`], +//! [`get_target_deltas`], [`get_head_deltas`], [`get_inclusion_delay_deltas`], +//! and [`get_inactivity_penalty_deltas`] still take `config: &Config` (unused +//! here, each parameter named `_config`), for two reasons: the `rewards` +//! fixture runner calls all five through one array and so needs them to share +//! exactly one signature, and altair's rewrite of this module (participation +//! flags instead of matched attestations, and configuration-scoped inactivity +//! score parameters) does need `Config` for the equivalent functions there. +//! Accepting the parameter now, unused, is what keeps this module's call shape +//! stable across that later rewrite. + +use crate::beacon::config::Config; +use crate::beacon::constants; +use crate::beacon::containers::BeaconState; +use crate::beacon::containers::phase0::PendingAttestation; +use crate::beacon::error::{Error, Result}; +use crate::beacon::helpers::accessors::{ + get_current_epoch, get_previous_epoch, get_total_active_balance, get_total_balance, +}; +use crate::beacon::helpers::finality::{ + get_eligible_validator_indices, get_finality_delay, is_in_inactivity_leak, +}; +use crate::beacon::helpers::math::integer_squareroot; +use crate::beacon::helpers::mutators::{decrease_balance, increase_balance}; +use crate::beacon::preset; +use crate::beacon::primitives::{Gwei, ValidatorIndex}; + +use super::{ + get_matching_head_attestations, get_matching_source_attestations, + get_matching_target_attestations, get_unslashed_attesting_indices, +}; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/// The base unit every attestation-component reward and inactivity penalty +/// scales from. +/// +/// Scales with the validator's own effective balance, but divides by the +/// square root of the total active balance rather than the total itself: the +/// aggregate reward budget is meant to grow with the square root of stake, not +/// linearly with it, so adding validators dilutes each one's reward rate. +pub fn get_base_reward(state: &BeaconState, index: ValidatorIndex) -> Result { + let total_balance = get_total_active_balance(state)?; + let effective_balance = state.validator(index)?.effective_balance; + Ok(effective_balance * preset::BASE_REWARD_FACTOR + / integer_squareroot(total_balance) + / constants::BASE_REWARDS_PER_EPOCH) +} + +/// The proposer's cut of an attester's base reward for including its +/// attestation. +pub fn get_proposer_reward(state: &BeaconState, attesting_index: ValidatorIndex) -> Result { + Ok(get_base_reward(state, attesting_index)? / preset::PROPOSER_REWARD_QUOTIENT) +} + +/// Shared accounting for the source, target, and head components of the +/// attestation reward: every eligible validator that cast whichever vote +/// `attestations` names is rewarded, and every eligible validator that did not +/// is penalized one base reward. +/// +/// Takes no `config`, unlike its five callers below, because nothing in the +/// shared formula reads one; see the module documentation for why the callers +/// carry it anyway. +/// +/// During an inactivity leak, a matching validator is paid its full base +/// reward here rather than the balance-weighted share the non-leaking branch +/// computes, because [`get_inactivity_penalty_deltas`] is about to cancel +/// exactly that much back out; paying it in full first is what makes an +/// optimally participating validator's net reward during a leak come out +/// neutral rather than negative. +pub fn get_attestation_component_deltas( + state: &BeaconState, + attestations: &[PendingAttestation], +) -> Result<(Vec, Vec)> { + let mut rewards = vec![0; state.validators().len()]; + let mut penalties = vec![0; state.validators().len()]; + + let total_balance = get_total_active_balance(state)?; + let unslashed_attesting_indices = get_unslashed_attesting_indices(state, attestations)?; + let attesting_balance = get_total_balance(state, &unslashed_attesting_indices)?; + + for index in get_eligible_validator_indices(state) { + if unslashed_attesting_indices.binary_search(&index).is_ok() { + // Factored out of both totals below before the division, to keep + // the numerator and denominator well clear of `u64::MAX` on a + // large validator set. + let increment = preset::EFFECTIVE_BALANCE_INCREMENT; + if is_in_inactivity_leak(state) { + rewards[index as usize] += get_base_reward(state, index)?; + } else { + let reward_numerator = + get_base_reward(state, index)? * (attesting_balance / increment); + rewards[index as usize] += reward_numerator / (total_balance / increment); + } + } else { + penalties[index as usize] += get_base_reward(state, index)?; + } + } + Ok((rewards, penalties)) +} + +// --------------------------------------------------------------------------- +// Components of attestation deltas +// --------------------------------------------------------------------------- + +/// Attester micro-rewards/penalties for the source-vote component. +pub fn get_source_deltas(state: &BeaconState, _config: &Config) -> Result<(Vec, Vec)> { + let matching_source_attestations = + get_matching_source_attestations(state, get_previous_epoch(state))?; + get_attestation_component_deltas(state, &matching_source_attestations) +} + +/// Attester micro-rewards/penalties for the target-vote component. +pub fn get_target_deltas(state: &BeaconState, _config: &Config) -> Result<(Vec, Vec)> { + let matching_target_attestations = + get_matching_target_attestations(state, get_previous_epoch(state))?; + get_attestation_component_deltas(state, &matching_target_attestations) +} + +/// Attester micro-rewards/penalties for the head-vote component. +pub fn get_head_deltas(state: &BeaconState, _config: &Config) -> Result<(Vec, Vec)> { + let matching_head_attestations = + get_matching_head_attestations(state, get_previous_epoch(state))?; + get_attestation_component_deltas(state, &matching_head_attestations) +} + +/// Proposer and inclusion-delay micro-rewards for each validator. +/// +/// Unlike the three components above, there is no penalty side: attesting +/// late only shrinks the reward the attester and its including proposer +/// split, it never costs either of them a balance they would otherwise have +/// kept. +/// +/// An attester that matches more than one retained source attestation (by +/// appearing in more than one of them) is paid only once, through whichever +/// reached the chain with the smallest `inclusion_delay`: the proposer who +/// included that one earns the proposer reward, and the attester's own reward +/// divides by that same delay, so being included again later cannot be used to +/// collect a second reward. +pub fn get_inclusion_delay_deltas( + state: &BeaconState, + _config: &Config, +) -> Result<(Vec, Vec)> { + let mut rewards = vec![0; state.validators().len()]; + + let matching_source_attestations = + get_matching_source_attestations(state, get_previous_epoch(state))?; + + for index in get_unslashed_attesting_indices(state, &matching_source_attestations)? { + // `PendingAttestation` shares `Attestation`'s `data`/`aggregation_bits` + // shape but is a distinct container type, so membership is checked by + // asking for the unslashed attesters of a single-attestation slice + // rather than by re-deriving the committee lookup directly. `index` is + // already known unslashed (it came from the call above), so this + // agrees with the specification's plain "index in + // get_attesting_indices(state, a)" check. + let mut candidates = Vec::new(); + for attestation in &matching_source_attestations { + let attesters = + get_unslashed_attesting_indices(state, std::slice::from_ref(attestation))?; + if attesters.binary_search(&index).is_ok() { + candidates.push(attestation); + } + } + let attestation = candidates + .into_iter() + .min_by_key(|attestation| attestation.inclusion_delay) + .ok_or(Error::SpecAssert( + "an unslashed source attester attests in at least one matching source attestation", + ))?; + + let proposer_reward = get_proposer_reward(state, index)?; + rewards[attestation.proposer_index as usize] += proposer_reward; + let max_attester_reward = get_base_reward(state, index)? - proposer_reward; + rewards[index as usize] += max_attester_reward / attestation.inclusion_delay; + } + + // No penalties are associated with inclusion delay. + let penalties = vec![0; state.validators().len()]; + Ok((rewards, penalties)) +} + +/// Inactivity penalties for each validator; phase0 pays no separate inactivity +/// reward, only a penalty, so the reward side of the pair is always zero. +/// +/// Outside a leak this is a no-op: the whole penalty exists to drain balance +/// from validators that are not helping the chain finalize while it is stuck, +/// and there is nothing to drain if it is not stuck. Inside a leak, every +/// eligible validator pays back the base reward +/// [`get_attestation_component_deltas`] already credited it, for a canceling +/// effect on an optimally participating validator, and a validator that also +/// missed the target vote pays an additional penalty that grows with +/// [`get_finality_delay`]: the longer finality stalls, the faster an inactive +/// validator's share of the stake shrinks. +pub fn get_inactivity_penalty_deltas( + state: &BeaconState, + _config: &Config, +) -> Result<(Vec, Vec)> { + let mut penalties = vec![0; state.validators().len()]; + + if is_in_inactivity_leak(state) { + let matching_target_attestations = + get_matching_target_attestations(state, get_previous_epoch(state))?; + let matching_target_attesting_indices = + get_unslashed_attesting_indices(state, &matching_target_attestations)?; + + for index in get_eligible_validator_indices(state) { + let base_reward = get_base_reward(state, index)?; + let proposer_reward = get_proposer_reward(state, index)?; + penalties[index as usize] += + constants::BASE_REWARDS_PER_EPOCH * base_reward - proposer_reward; + + if matching_target_attesting_indices + .binary_search(&index) + .is_err() + { + let effective_balance = state.validator(index)?.effective_balance; + // `get_finality_delay` grows without bound the longer a leak + // lasts, so this product is checked rather than left to wrap: + // the specification treats a `uint64` overflow here as an + // invalid state, not as a penalty that silently wraps small. + let penalty_numerator = effective_balance + .checked_mul(get_finality_delay(state)) + .ok_or(Error::ArithmeticOverflow( + "scaling effective balance by the finality delay for the inactivity penalty", + ))?; + penalties[index as usize] += + penalty_numerator / preset::INACTIVITY_PENALTY_QUOTIENT; + } + } + } + + // No rewards are associated with inactivity penalties. + let rewards = vec![0; state.validators().len()]; + Ok((rewards, penalties)) +} + +// --------------------------------------------------------------------------- +// `get_attestation_deltas` +// --------------------------------------------------------------------------- + +/// The combined attestation reward and penalty for each validator: the sum of +/// the source, target, head, and inclusion-delay rewards, and the sum of the +/// source, target, head, and inactivity penalties. +pub fn get_attestation_deltas( + state: &BeaconState, + config: &Config, +) -> Result<(Vec, Vec)> { + let (source_rewards, source_penalties) = get_source_deltas(state, config)?; + let (target_rewards, target_penalties) = get_target_deltas(state, config)?; + let (head_rewards, head_penalties) = get_head_deltas(state, config)?; + let (inclusion_delay_rewards, _) = get_inclusion_delay_deltas(state, config)?; + let (_, inactivity_penalties) = get_inactivity_penalty_deltas(state, config)?; + + let validator_count = state.validators().len(); + let mut rewards = vec![0; validator_count]; + let mut penalties = vec![0; validator_count]; + for i in 0..validator_count { + rewards[i] = + source_rewards[i] + target_rewards[i] + head_rewards[i] + inclusion_delay_rewards[i]; + penalties[i] = + source_penalties[i] + target_penalties[i] + head_penalties[i] + inactivity_penalties[i]; + } + + Ok((rewards, penalties)) +} + +/// Applies the epoch's attestation rewards and penalties to every validator's +/// balance. +/// +/// Skipped entirely at the genesis epoch: rewards pay for attestations cast in +/// the previous epoch, and genesis has none. Rewards and penalties are two +/// separate passes over [`increase_balance`] and [`decrease_balance`], not one +/// netted delta, because [`decrease_balance`] floors at zero: netting first +/// would let a reward mask a penalty that should have driven a low balance all +/// the way down. +pub fn process_rewards_and_penalties(state: &mut BeaconState, config: &Config) -> Result<()> { + if get_current_epoch(state) == constants::GENESIS_EPOCH { + return Ok(()); + } + + let (rewards, penalties) = get_attestation_deltas(state, config)?; + for index in 0..state.validators().len() as ValidatorIndex { + increase_balance(state, index, rewards[index as usize])?; + decrease_balance(state, index, penalties[index as usize])?; + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn finality_delay_is_zero_on_a_fresh_state() { + // `with_validators` positions the state at current epoch 1, previous + // epoch 0, with the finalized checkpoint left at its default (epoch + // 0): finality has not fallen behind at all. + let state = crate::beacon::helpers::test_state::with_validators(4); + assert_eq!(get_finality_delay(&state), 0); + } + + #[test] + fn current_finality_is_not_a_leak() { + let state = crate::beacon::helpers::test_state::with_validators(4); + assert!(!is_in_inactivity_leak(&state)); + } + + #[test] + fn finality_stalled_past_the_threshold_is_a_leak() { + let mut state = crate::beacon::helpers::test_state::with_validators(4); + // The finalized checkpoint stays at its default (epoch 0); pushing the + // slot far enough ahead pulls the previous epoch more than + // `MIN_EPOCHS_TO_INACTIVITY_PENALTY` epochs ahead of it. + *state.slot_mut() = + preset::SLOTS_PER_EPOCH * (preset::MIN_EPOCHS_TO_INACTIVITY_PENALTY + 10); + assert!(is_in_inactivity_leak(&state)); + } + + #[test] + fn every_active_validator_is_eligible() { + let state = crate::beacon::helpers::test_state::with_validators(6); + assert_eq!( + get_eligible_validator_indices(&state), + (0..6).collect::>() + ); + } + + #[test] + fn process_rewards_and_penalties_is_a_no_op_at_genesis() { + let config = Config::mainnet(); + let mut state = crate::beacon::helpers::test_state::with_validators(4); + *state.slot_mut() = 0; + let balances_before = state.balances().clone(); + + process_rewards_and_penalties(&mut state, &config).unwrap(); + + assert_eq!( + state.balances(), + &balances_before, + "the genesis epoch has no previous epoch to reward" + ); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/fulu.rs b/crates/blockchain/state_transition/src/beacon/stf/fulu.rs new file mode 100644 index 000000000..01e296d4e --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/fulu.rs @@ -0,0 +1,393 @@ +//! Fulu-specific block processing. +//! +//! Fulu changes no field of a block and redefines no step of `process_block` +//! itself: `beacon-chain.md`'s "Block processing" section for this fork +//! contains exactly one item, a modified `process_execution_payload`. So +//! [`process_block`] dispatches on [`electra::BeaconBlock`], the same type +//! fulu's own [`crate::beacon::containers::SignedBeaconBlock::Fulu`] variant wraps, +//! rather than a `fulu::BeaconBlock` that does not exist, and every step +//! but one is [`super::electra`]'s own function, called directly rather than +//! transcribed. +//! +//! The one change is why a block's blob commitment count stops being checked +//! against a single network-wide constant. Through electra, a block could +//! carry at most [`Config::max_blobs_per_block_electra`] blobs, each +//! downloaded and verified whole by every node that wants to check it. Fulu +//! moves to a sampling model instead (`das-core.md`): a blob is +//! erasure-coded into a wide row of columns, and a node gains the same +//! confidence that the data behind a commitment is available by sampling a +//! handful of those columns rather than downloading the blob itself. That +//! changes what the per-block limit is even bounding: no longer "how much +//! data must every node download," but "how many columns exist for the +//! network to sample from," a quantity the network can raise again and +//! again without a further hard fork, since nothing about an individual +//! node's own workload scales with it the way whole-blob downloads used to. +//! EIP-7892's blob schedule ([`Config::blob_schedule`]) is what carries a +//! raised limit into effect at a chosen epoch, and [`process_execution_payload`] +//! is the one place in block processing that reads it, through +//! [`Config::max_blobs_per_block`], in place of electra's fixed field. +//! +//! [`super::block::process_block_header`], [`super::block::process_randao`], +//! and [`super::block::process_eth1_data`] are reused because they always +//! were fork-shared; [`super::electra::process_withdrawals`], +//! [`super::electra::process_operations`], and +//! [`super::altair::process_sync_aggregate`] are reused because fulu's +//! specification never mentions any of the three. [`process_execution_payload`] +//! itself cannot be [`super::electra::process_execution_payload`] called +//! unchanged, for the same reason electra's own version could not be +//! deneb's: it reads a different [`Config`] field for the one check that +//! changed. + +use crate::beacon::config::Config; +use crate::beacon::containers::{BeaconState, deneb, electra}; +use crate::beacon::error::{Result, verify}; +use crate::beacon::helpers::accessors::{get_current_epoch, get_randao_mix}; +use crate::beacon::helpers::fulu::{fulu_state, fulu_state_ref}; +use crate::beacon::primitives::{Bytes32, HashTreeRoot as _}; + +use super::ExecutionEngine; + +// --------------------------------------------------------------------------- +// Block processing +// --------------------------------------------------------------------------- + +/// Fulu's block processing: electra's own steps, in electra's own order, +/// with [`process_execution_payload`] standing in for +/// [`super::electra::process_execution_payload`]. See the module docs for +/// why that is the only step this fork's specification asks to change. +pub fn process_block( + state: &mut BeaconState, + block: &electra::BeaconBlock, + config: &Config, + engine: &ExecutionEngine, +) -> Result<()> { + super::block::process_block_header( + state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + )?; + super::electra::process_withdrawals(state, &block.body.execution_payload)?; + process_execution_payload(state, &block.body, config, engine)?; + super::block::process_randao(state, &block.body.randao_reveal)?; + super::block::process_eth1_data(state, &block.body.eth1_data)?; + super::electra::process_operations(state, &block.body, config)?; + super::altair::process_sync_aggregate(state, &block.body.sync_aggregate)?; + Ok(()) +} + +// --------------------------------------------------------------------------- +// Execution payload +// --------------------------------------------------------------------------- + +/// Validates this slot's execution payload and its blob commitments, then +/// caches the payload's header. +/// +/// Structurally [`super::electra::process_execution_payload`] (parent-hash +/// continuity, `prev_randao`, timestamp, a blob-commitment count check, the +/// collapsed engine check, then caching a [`deneb::ExecutionPayloadHeader`], +/// the same header type fulu keeps unchanged from deneb through electra), +/// but not literally callable as that function: its commitment-count check +/// reads [`Config::max_blobs_per_block_electra`], a single fixed +/// configuration value, while fulu's own limit comes from +/// [`Config::max_blobs_per_block`], which consults +/// [`Config::blob_schedule`] (EIP-7892) for the epoch the block belongs to +/// and only falls back to that same fixed value once the schedule has +/// nothing to say about it (see that method's own documentation, which +/// mirrors the specification's `get_blob_parameters`). [`super::electra`]'s +/// own state projection reads and writes `latest_execution_payload_header` +/// through functions private to that module, so this instead goes through +/// [`fulu_state_ref`] and [`fulu_state`], the same projection +/// [`crate::beacon::helpers::fulu::get_beacon_proposer_index`] already uses to reach +/// fulu's own state. +/// +/// Every other step is transcribed unchanged, including not computing +/// anything from `body.execution_requests`: see +/// [`super::deneb::process_execution_payload`]'s own documentation for why +/// the versioned-hashes list, and the execution-requests list a real +/// execution client would also need, are dead weight in this module +/// specifically. [`ExecutionEngine`] collapses the whole +/// `verify_and_notify_new_payload` interface to one boolean and never +/// inspects either, but the versioned hashes are still computed +/// unconditionally so that a future engine model with something real to +/// check against has the value ready to hand it. +pub fn process_execution_payload( + state: &mut BeaconState, + body: &electra::BeaconBlockBody, + config: &Config, + engine: &ExecutionEngine, +) -> Result<()> { + let payload = &body.execution_payload; + + let expected_parent_hash = fulu_state_ref(state, "process_execution_payload")? + .latest_execution_payload_header + .block_hash; + verify( + payload.parent_hash == expected_parent_hash, + "payload.parent_hash == state.latest_execution_payload_header.block_hash", + )?; + verify( + payload.prev_randao == get_randao_mix(state, get_current_epoch(state)), + "payload.prev_randao == get_randao_mix(state, get_current_epoch(state))", + )?; + verify( + payload.timestamp + == super::bellatrix::compute_timestamp_at_slot(state, state.slot(), config), + "payload.timestamp == compute_time_at_slot(state, state.slot)", + )?; + // [Modified in Fulu:EIP7892]: the schedule-aware limit rather than + // electra's fixed `max_blobs_per_block_electra`; see this function's own + // documentation for why the two cannot share one check. + verify( + body.blob_kzg_commitments.len() as u64 + <= config.max_blobs_per_block(get_current_epoch(state)), + "len(body.blob_kzg_commitments) <= get_blob_parameters(get_current_epoch(state)).max_blobs_per_block", + )?; + + // See this function's own documentation for why this is computed but + // not itself checked against anything. + let _versioned_hashes: Vec = body + .blob_kzg_commitments + .iter() + .map(super::deneb::kzg_commitment_to_versioned_hash) + .collect(); + + verify( + engine.execution_valid, + "verify_and_notify_new_payload(NewPayloadRequest(execution_payload=payload, \ + versioned_hashes=versioned_hashes, \ + parent_beacon_block_root=state.latest_block_header.parent_root, \ + execution_requests=body.execution_requests))", + )?; + + let header = deneb::ExecutionPayloadHeader { + parent_hash: payload.parent_hash, + fee_recipient: payload.fee_recipient, + state_root: payload.state_root, + receipts_root: payload.receipts_root, + logs_bloom: payload.logs_bloom.clone(), + prev_randao: payload.prev_randao, + block_number: payload.block_number, + gas_limit: payload.gas_limit, + gas_used: payload.gas_used, + timestamp: payload.timestamp, + extra_data: payload.extra_data.clone(), + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash, + transactions_root: payload.transactions.hash_tree_root(), + withdrawals_root: payload.withdrawals.hash_tree_root(), + blob_gas_used: payload.blob_gas_used, + excess_blob_gas: payload.excess_blob_gas, + }; + fulu_state(state, "process_execution_payload")?.latest_execution_payload_header = header; + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::beacon::config::BlobScheduleEntry; + use crate::beacon::containers::bellatrix::LogsBloom; + use crate::beacon::fork::ForkName; + use crate::beacon::helpers::accessors::{get_current_epoch, get_randao_mix}; + use crate::beacon::preset; + use crate::beacon::primitives::{ + ExecutionAddress, ExecutionBlockHash, KzgCommitment, Root, Uint256, + }; + + /// An all-zero execution payload header, standing in for the genesis + /// payload. + fn empty_execution_payload_header() -> deneb::ExecutionPayloadHeader { + deneb::ExecutionPayloadHeader { + parent_hash: ExecutionBlockHash::ZERO, + fee_recipient: ExecutionAddress::ZERO, + state_root: Bytes32::ZERO, + receipts_root: Bytes32::ZERO, + logs_bloom: LogsBloom::try_from(vec![0u8; preset::BYTES_PER_LOGS_BLOOM]) + .expect("built at exactly BYTES_PER_LOGS_BLOOM"), + prev_randao: Bytes32::ZERO, + block_number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: 0, + extra_data: Default::default(), + base_fee_per_gas: Uint256::ZERO, + block_hash: ExecutionBlockHash::ZERO, + transactions_root: Root::ZERO, + withdrawals_root: Root::ZERO, + blob_gas_used: 0, + excess_blob_gas: 0, + } + } + + /// A fulu state with `count` fully active, full-balance validators, one + /// epoch in (so the block-root history window already has entries), and + /// `header` as its `latest_execution_payload_header`. + /// + /// A thin wrapper around the shared fork-parameterised builder, which has + /// no header to take as a parameter, so this overrides the placeholder it + /// builds with the one every real caller here actually wants under test. + /// See [`crate::beacon::helpers::test_state::with_validators_at`] for the + /// construction this and every other fork's test module used to + /// duplicate. + fn fulu_state_with_validators( + count: usize, + header: deneb::ExecutionPayloadHeader, + ) -> BeaconState { + let mut state = + crate::beacon::helpers::test_state::with_validators_at(ForkName::Fulu, count); + if let BeaconState::Fulu(inner) = &mut state { + inner.latest_execution_payload_header = header; + } + state + } + + /// A block body carrying `commitment_count` blob commitments and an + /// otherwise-empty operation list, with a payload that matches `state` + /// and `header` closely enough to pass every check in + /// [`process_execution_payload`] except the one under test. + fn body_with_commitments( + state: &BeaconState, + config: &Config, + header: &deneb::ExecutionPayloadHeader, + commitment_count: usize, + ) -> electra::BeaconBlockBody { + let payload = deneb::ExecutionPayload { + parent_hash: header.block_hash, + fee_recipient: ExecutionAddress::ZERO, + state_root: Bytes32::ZERO, + receipts_root: Bytes32::ZERO, + logs_bloom: LogsBloom::try_from(vec![0u8; preset::BYTES_PER_LOGS_BLOOM]) + .expect("built at exactly BYTES_PER_LOGS_BLOOM"), + prev_randao: get_randao_mix(state, get_current_epoch(state)), + block_number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: crate::beacon::stf::bellatrix::compute_timestamp_at_slot( + state, + state.slot(), + config, + ), + extra_data: Default::default(), + base_fee_per_gas: Uint256::ZERO, + block_hash: ExecutionBlockHash::repeat_byte(0xcd), + transactions: Default::default(), + withdrawals: Default::default(), + blob_gas_used: 0, + excess_blob_gas: 0, + }; + + electra::BeaconBlockBody { + randao_reveal: Default::default(), + eth1_data: Default::default(), + graffiti: Bytes32::ZERO, + proposer_slashings: Default::default(), + attester_slashings: Default::default(), + attestations: Default::default(), + deposits: Default::default(), + voluntary_exits: Default::default(), + sync_aggregate: Default::default(), + execution_payload: payload, + bls_to_execution_changes: Default::default(), + blob_kzg_commitments: vec![KzgCommitment::default(); commitment_count] + .try_into() + .expect("commitment_count stays well within MAX_BLOB_COMMITMENTS_PER_BLOCK here"), + execution_requests: electra::ExecutionRequests { + deposits: Default::default(), + withdrawals: Default::default(), + consolidations: Default::default(), + }, + } + } + + /// The one behavior fulu actually changes: a commitment count above + /// electra's fixed ceiling but within a raised schedule entry is + /// rejected by electra's own function and accepted by fulu's. + /// + /// Calls `crate::beacon::stf::electra::process_execution_payload` directly on + /// the same fulu state, rather than building a separate electra one: + /// that function's internal state projection already accepts a fulu + /// state (see this file's own module docs), so this exercises the real + /// function fulu diverges from instead of a stand-in for it. + #[test] + fn process_execution_payload_uses_the_schedule_aware_limit_electra_does_not() { + let header = empty_execution_payload_header(); + let mut config = Config::minimal(); + let raised_limit = config.max_blobs_per_block_electra + 3; + config.blob_schedule = vec![BlobScheduleEntry { + epoch: 0, + max_blobs_per_block: raised_limit, + }]; + + let state = fulu_state_with_validators(4, header.clone()); + let commitment_count = (config.max_blobs_per_block_electra + 1) as usize; + let body = body_with_commitments(&state, &config, &header, commitment_count); + let engine = ExecutionEngine::valid(); + + assert!( + crate::beacon::stf::electra::process_execution_payload( + &mut state.clone(), + &body, + &config, + &engine + ) + .is_err(), + "electra's own fixed ceiling must still reject a count above it" + ); + process_execution_payload(&mut state.clone(), &body, &config, &engine) + .expect("the schedule raised the limit above this count"); + } + + /// The schedule is a ceiling, not a suggestion: a count above even the + /// raised limit is still rejected. + #[test] + fn process_execution_payload_still_rejects_more_than_the_schedule_allows() { + let header = empty_execution_payload_header(); + let mut config = Config::minimal(); + let raised_limit = config.max_blobs_per_block_electra + 3; + config.blob_schedule = vec![BlobScheduleEntry { + epoch: 0, + max_blobs_per_block: raised_limit, + }]; + + let state = fulu_state_with_validators(4, header.clone()); + let body = body_with_commitments(&state, &config, &header, (raised_limit + 1) as usize); + let engine = ExecutionEngine::valid(); + + assert!(process_execution_payload(&mut state.clone(), &body, &config, &engine).is_err()); + } + + /// With no schedule entries at all, [`Config::max_blobs_per_block`] + /// falls back to electra's own fixed limit, so fulu's check and + /// electra's must agree at that same boundary. + #[test] + fn process_execution_payload_matches_electra_when_the_schedule_is_empty() { + let header = empty_execution_payload_header(); + let config = Config::minimal(); + assert!(config.blob_schedule.is_empty()); + + let state = fulu_state_with_validators(4, header.clone()); + let engine = ExecutionEngine::valid(); + + let at_limit = body_with_commitments( + &state, + &config, + &header, + config.max_blobs_per_block_electra as usize, + ); + process_execution_payload(&mut state.clone(), &at_limit, &config, &engine) + .expect("exactly electra's own limit must still pass with no schedule"); + + let over_limit = body_with_commitments( + &state, + &config, + &header, + (config.max_blobs_per_block_electra + 1) as usize, + ); + assert!( + process_execution_payload(&mut state.clone(), &over_limit, &config, &engine).is_err() + ); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/mod.rs b/crates/blockchain/state_transition/src/beacon/stf/mod.rs new file mode 100644 index 000000000..d69bb686e --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/mod.rs @@ -0,0 +1,293 @@ +//! The beacon state transition function. +//! +//! Applying a block is two stages. First the state is advanced to the block's +//! slot, one slot at a time, running epoch processing at each epoch boundary +//! crossed. Then the block's own contents are applied. Both stages can fail, and +//! a failure at any point means the block is invalid. +//! +//! # Failure is the normal case +//! +//! The specification expresses invalidity by letting an `assert` fail or an index +//! go out of range, and says that a `uint64` overflow or underflow is invalid +//! too. Here every one of those is a [`crate::beacon::Error`] returned through `?`, so +//! nothing panics on a hostile block. That is why balance arithmetic goes through +//! checked operations rather than `+` and `-`: in release builds Rust wraps +//! silently, which would turn an invalid block into a corrupted state. +//! +//! # Mutation in place, and what that costs the caller +//! +//! The spec mutates the state in place and so does this, which means a state +//! passed to [`state_transition`] is left partly modified when a block turns out +//! to be invalid. Callers that need to keep the pre-state must clone it first, +//! which is what the fixture runners do. The alternative, threading a fresh state +//! through every function, would depart from the spec's structure everywhere +//! without making anything safer. +//! +//! # Dispatching on the block's fork, not a shared body type +//! +//! [`containers::BeaconState`] and [`containers::SignedBeaconBlock`] are enums +//! over per-fork structs, so every entry point here has to decide, at some +//! point, which fork's rules apply. [`block::process_block`] makes that +//! decision once, by matching [`containers::SignedBeaconBlock`]'s variant, and +//! hands each fork's own concrete `BeaconBlock` to a function written just for +//! it: [`block::process_block_phase0`], [`block::process_block_altair`], and a +//! stub per later fork in this module's [`bellatrix`], [`capella`], [`deneb`], +//! [`electra`], and [`fulu`] siblings. +//! +//! Deliberately absent from that list is any shared `BeaconBlockBody` enum, a +//! `BeaconBlockBodyRef`, or a trait over bodies. Such a type would have to grow +//! a method (or a match arm) per fork-specific field or operation list, which +//! defeats the point of dispatching once: a caller of `body.attester_slashings()` +//! would still have to know which fork it is dealing with to make sense of what +//! comes back, since electra's attester slashings are not phase0's. What +//! actually lets one function serve every fork is narrower and cheaper than any +//! of that: [`block::process_block_header`], [`block::process_randao`], and +//! [`block::process_eth1_data`] take the handful of fields they each read +//! directly, rather than a whole body, so nothing about validating a header +//! cares whether the body it came from also carries a sync aggregate or an +//! execution payload. A shared step earns its genericity by needing less, not +//! by being handed a bigger abstraction to see through. +//! +//! [`state_transition`] adds one check the specification itself has no +//! occasion to make: that the block's fork actually matches the state's. See +//! its own documentation for why that check belongs there and not inside +//! [`block::process_block`]. + +pub mod altair; +pub mod bellatrix; +pub mod block; +pub mod capella; +pub mod deneb; +pub mod electra; +pub mod epoch; +pub mod fulu; +pub mod operations; + +use crate::beacon::containers; +use crate::beacon::containers::{BeaconState, phase0}; +use crate::beacon::error::{Error, Result, verify}; +use crate::beacon::helpers::accessors::get_domain; +use crate::beacon::helpers::misc::compute_signing_root; +use crate::beacon::preset; +use crate::beacon::primitives::{HashTreeRoot as _, Slot}; +use crate::beacon::{bls, config::Config, constants}; + +/// What the execution layer would answer for a block's payload. +/// +/// The specification models this as a call out to an execution client: +/// `notify_new_payload` and the rest of `verify_and_notify_new_payload`, present +/// from bellatrix on. Nothing in this module speaks to a real execution client, +/// and the fixture suites that exercise this path supply the answer directly as +/// a boolean in `execution.yaml` rather than a payload to actually validate, so +/// the whole interface collapses to that one value. +#[derive(Debug, Clone, Copy)] +pub struct ExecutionEngine { + pub execution_valid: bool, +} + +impl ExecutionEngine { + /// An engine that accepts every payload it is asked about. + pub fn valid() -> Self { + ExecutionEngine { + execution_valid: true, + } + } + + /// An engine that rejects every payload it is asked about. + pub fn invalid() -> Self { + ExecutionEngine { + execution_valid: false, + } + } +} + +/// Applies a signed block to the state. +/// +/// With `validate_result` set, the proposer's signature and the block's committed +/// `state_root` are both checked. The fixture suites that feed in blocks the +/// proposer never really signed clear it, which is also what a block producer +/// building on a state it already trusts would do. +/// +/// Checks the block's fork against the state's own before doing anything else, +/// which is a check the specification never has occasion to write: its +/// `BeaconState` and `BeaconBlock` are already one fork's own types, so a +/// mismatch between them cannot even be expressed there. Here it can be, since +/// both are enums, so this module has to enforce by hand an invariant the +/// specification gets for free. The check belongs in this function rather than +/// in [`block::process_block`] because a mismatch would not reliably fail +/// inside that dispatcher for the reason a reader would expect: most of what an +/// earlier fork's block shares with a later one (the header, the RANDAO reveal, +/// the eth1 vote, and every operation through deneb's shape) reads and writes +/// only the state's fork-invariant fields, so it runs to completion regardless +/// of which variant `state` actually is. A phase0-shaped block applied to an +/// altair state, for instance, would simply never reach `process_sync_aggregate`, +/// since a phase0 body has no such field to read, silently skipping a step the +/// specification requires instead of failing on it. Rejecting the mismatch +/// before any of that runs is what keeps the failure legible: "wrong fork," not +/// some unrelated-looking assertion three steps later. +pub fn state_transition( + state: &mut BeaconState, + signed_block: &containers::SignedBeaconBlock, + validate_result: bool, + config: &Config, + engine: &ExecutionEngine, +) -> Result<()> { + process_slots(state, signed_block.slot(), config)?; + + // After `process_slots`, never before it. A block proposed at the first slot + // of a fork's activation epoch is the *post*-fork shape while the state + // arriving here is still the pre-fork one, which is exactly the case a fork + // transition consists of. `process_slots` is what upgrades the state, so + // checking first would reject every legitimate fork-boundary block and make + // crossing a fork impossible. + verify( + signed_block.fork_name() == state.fork_name(), + "the block's fork matches the state's", + )?; + + if validate_result { + verify( + verify_block_signature(state, signed_block), + "block signature", + )?; + } + + block::process_block(state, signed_block, config, engine)?; + + if validate_result { + verify( + signed_block.state_root() == state.hash_tree_root(), + "block state root matches the post-state", + )?; + } + + Ok(()) +} + +/// Whether the block carries its proposer's signature. +pub fn verify_block_signature( + state: &BeaconState, + signed_block: &containers::SignedBeaconBlock, +) -> bool { + let Ok(proposer) = state.validator(signed_block.proposer_index()) else { + return false; + }; + let domain = get_domain(state, constants::DOMAIN_BEACON_PROPOSER, None); + let signing_root = compute_signing_root(signed_block.message_hash_tree_root(), domain); + bls::verify(&proposer.pubkey, signing_root, &signed_block.signature()) +} + +/// Advances the state to `slot`, running epoch processing at each boundary and +/// upgrading the state's shape at each fork boundary crossed. +/// +/// Rejects a slot at or before the current one, so this can only ever move +/// forward. +pub fn process_slots(state: &mut BeaconState, slot: Slot, config: &Config) -> Result<()> { + verify(state.slot() < slot, "target slot is after the current slot")?; + + while state.slot() < slot { + process_slot(state)?; + // Epoch processing runs on the last slot of an epoch, before the counter + // moves into the next one. + if (state.slot() + 1).is_multiple_of(preset::SLOTS_PER_EPOCH) { + epoch::process_epoch(state, config)?; + } + *state.slot_mut() += 1; + upgrade_at_fork_boundary(state, config)?; + } + + Ok(()) +} + +/// Replaces the state with the next fork's shape if the slot just reached is the +/// first slot of that fork's activation epoch. +/// +/// The specification does not list this as a step of `process_slots`. Each fork's +/// `fork.md` instead describes it as an "irregular state change" made when +/// `state.slot % SLOTS_PER_EPOCH == 0` and the resulting epoch equals that fork's +/// activation epoch, leaving where to put it to the implementation. Here is the +/// only place that works: it has to happen after the slot counter advances and +/// before anything reads the state again, and `process_slots` is the one function +/// every path into a new slot goes through. +/// +/// Without this, nothing can cross a fork. Every per-fork state transition in the +/// crate could be perfectly correct and the chain would still stop dead at the +/// first activation epoch, because the state would keep the old fork's shape while +/// blocks arrived in the new one. +/// +/// The loop, rather than a single check, is for a configuration that activates +/// two forks at the same epoch. The fixture suites do exactly that: a `transition` +/// case moves one fork's activation epoch, and nothing stops it landing on +/// another's. Upgrading one fork per slot would silently leave the state a fork +/// behind. +fn upgrade_at_fork_boundary(state: &mut BeaconState, config: &Config) -> Result<()> { + if !state.slot().is_multiple_of(preset::SLOTS_PER_EPOCH) { + return Ok(()); + } + let epoch = state.slot() / preset::SLOTS_PER_EPOCH; + + while let Some(next) = state.fork_name().next() { + if config.fork_epoch(next) != epoch { + break; + } + // Bound the borrow of `state` to this statement, since the assignment + // needs it back mutably. + let upgraded = crate::beacon::upgrade::upgrade_state(state, next, config)?; + *state = upgraded; + } + + Ok(()) +} + +/// Records the outgoing slot's state and block roots. +/// +/// The `latest_block_header.state_root` fixup is the resolution of a +/// circularity: a block commits to the root of the state that results from +/// applying it, so the header stored while processing that block cannot yet know +/// it. It is left zero and filled in here, one slot later, which is the first +/// moment the value exists. +pub fn process_slot(state: &mut BeaconState) -> Result<()> { + let previous_state_root = state.hash_tree_root(); + let position = state.slot() as usize % preset::SLOTS_PER_HISTORICAL_ROOT; + state.state_roots_mut()[position] = previous_state_root; + + if state.latest_block_header().state_root.is_zero() { + state.latest_block_header_mut().state_root = previous_state_root; + } + + let previous_block_root = state.latest_block_header().hash_tree_root(); + state.block_roots_mut()[position] = previous_block_root; + + Ok(()) +} + +/// The phase0 state, or an error naming the function that needs one. +/// +/// Functions whose body is specific to phase0's state shape start here rather +/// than matching inline, so the fork check reads the same in each of them. +pub(crate) fn phase0_state<'a>( + state: &'a mut BeaconState, + function: &'static str, +) -> Result<&'a mut phase0::BeaconState> { + match state { + BeaconState::Phase0(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +/// The phase0 state, immutably. +pub(crate) fn phase0_state_ref<'a>( + state: &'a BeaconState, + function: &'static str, +) -> Result<&'a phase0::BeaconState> { + match state { + BeaconState::Phase0(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} diff --git a/crates/blockchain/state_transition/src/beacon/stf/operations.rs b/crates/blockchain/state_transition/src/beacon/stf/operations.rs new file mode 100644 index 000000000..9802751ee --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/stf/operations.rs @@ -0,0 +1,678 @@ +//! Block operations: the five lists a proposer packs into a block body. +//! +//! Each list is processed independently and in a fixed order (proposer +//! slashings, then attester slashings, then attestations, then deposits, then +//! voluntary exits), which is why [`process_operations`] is nothing more than +//! five loops. What makes this section worth its own module is that three of +//! the five operations end in a slashing, one has a two-phase signature domain +//! rule unlike anything else in the state transition, and the deposit path +//! silently tolerates the one kind of invalidity (a bad signature) that every +//! other operation treats as fatal to the whole block. Getting each of those +//! exactly right is the point; the loops around them are incidental. + +use std::collections::HashSet; + +use crate::beacon::bls; +use crate::beacon::config::Config; +use crate::beacon::constants::{self, FAR_FUTURE_EPOCH}; +use crate::beacon::containers::BeaconState; +use crate::beacon::containers::phase0; +use crate::beacon::containers::shared::{ + Deposit, DepositMessage, ProposerSlashing, SignedVoluntaryExit, Validator, +}; +use crate::beacon::error::{Error, Result, verify}; +use crate::beacon::fork::ForkName; +use crate::beacon::helpers::accessors::{ + get_beacon_committee, get_beacon_proposer_index, get_committee_count_per_slot, + get_current_epoch, get_domain, get_previous_epoch, +}; +use crate::beacon::helpers::attestation::{get_indexed_attestation, is_valid_indexed_attestation}; +use crate::beacon::helpers::misc::{ + compute_deposit_domain, compute_epoch_at_slot, compute_signing_root, is_valid_merkle_branch, +}; +use crate::beacon::helpers::mutators::{ + increase_balance, initiate_validator_exit, slash_validator, +}; +use crate::beacon::helpers::predicates::{ + is_active_validator, is_slashable_attestation_data, is_slashable_validator, +}; +use crate::beacon::preset; +use crate::beacon::primitives::{Gwei, HashTreeRoot as _, ValidatorIndex}; + +/// Runs every operation in a block, in the specification's order. +/// +/// Takes each operation list as a slice rather than a whole body, which is +/// what lets this one function serve every fork through deneb even though +/// their body types are all distinct: nothing here needs to know what else a +/// fork's body carries alongside these five lists. Capella's body adds a sixth +/// list (BLS-to-execution changes), and electra reshapes the attestation types +/// this signature assumes, so both get their own `process_operations` once that +/// work lands, rather than this one growing parameters to cover them. +/// +/// The deposit count check comes first and covers every deposit at once rather +/// than any one operation: a block must include exactly as many deposits as are +/// outstanding, up to the per-block cap, so a proposer cannot fall behind the +/// deposit contract by including too few, nor claim more than exist. +pub fn process_operations( + state: &mut BeaconState, + proposer_slashings: &[ProposerSlashing], + attester_slashings: &[phase0::AttesterSlashing], + attestations: &[phase0::Attestation], + deposits: &[Deposit], + voluntary_exits: &[SignedVoluntaryExit], + config: &Config, +) -> Result<()> { + // `eth1_deposit_index` only ever advances by one per processed deposit, + // and `deposit_count` only ever grows, so in a correctly-derived state the + // index never exceeds the count. Nothing here re-derives that invariant, + // so a malformed pre-state (or a future bug) must not be allowed to wrap + // this into a huge outstanding count that no block could ever satisfy. + let outstanding = state + .eth1_data() + .deposit_count + .checked_sub(state.eth1_deposit_index()) + .ok_or(Error::ArithmeticOverflow( + "eth1_data.deposit_count - eth1_deposit_index", + ))?; + verify( + deposits.len() as u64 == outstanding.min(preset::MAX_DEPOSITS as u64), + "len(body.deposits) == min(MAX_DEPOSITS, eth1_data.deposit_count - eth1_deposit_index)", + )?; + + for proposer_slashing in proposer_slashings { + process_proposer_slashing(state, proposer_slashing, config)?; + } + for attester_slashing in attester_slashings { + process_attester_slashing(state, attester_slashing, config)?; + } + for attestation in attestations { + // Phase0 defers an attestation's reward to the epoch boundary, so it + // needs its own version of this step (below); altair scores one the + // moment it is processed instead, and nothing about that changed + // through deneb, so every later fork this signature serves shares + // altair's version rather than getting one of its own. This is the + // same coexisting-by-fork pattern `crate::beacon::helpers::altair` and + // `crate::beacon::stf::epoch::rewards` already use for the two + // `get_base_reward` implementations: neither is renamed, and the call + // site picks between them by fully-qualified path. + if state.fork_name() == ForkName::Phase0 { + process_attestation(state, attestation, config)?; + } else { + crate::beacon::stf::altair::process_attestation(state, attestation)?; + } + } + for deposit in deposits { + process_deposit(state, deposit, config)?; + } + for voluntary_exit in voluntary_exits { + process_voluntary_exit(state, voluntary_exit, config)?; + } + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Proposer slashings +// --------------------------------------------------------------------------- + +/// Slashes a proposer caught signing two different headers for the same slot. +/// +/// The two headers must actually differ: a proposer can be asked to co-sign +/// the same header twice (by different requesters, or the same one twice), +/// and that is not evidence of anything. Only a genuine equivocation, two +/// distinct headers for the one slot, is slashable. +pub fn process_proposer_slashing( + state: &mut BeaconState, + proposer_slashing: &ProposerSlashing, + config: &Config, +) -> Result<()> { + let header_1 = &proposer_slashing.signed_header_1.message; + let header_2 = &proposer_slashing.signed_header_2.message; + + verify( + header_1.slot == header_2.slot, + "header_1.slot == header_2.slot", + )?; + verify( + header_1.proposer_index == header_2.proposer_index, + "header_1.proposer_index == header_2.proposer_index", + )?; + verify(header_1 != header_2, "header_1 != header_2")?; + + let proposer_index = header_1.proposer_index; + let current_epoch = get_current_epoch(state); + let proposer = state.validator(proposer_index)?; + verify( + is_slashable_validator(proposer, current_epoch), + "is_slashable_validator(proposer, get_current_epoch(state))", + )?; + // Copied out rather than re-borrowed per iteration below: both signatures + // are checked against the same proposer, and holding the borrow across + // the loop would conflict with `get_domain`'s borrow of `state`. + let pubkey = proposer.pubkey; + + for signed_header in [ + &proposer_slashing.signed_header_1, + &proposer_slashing.signed_header_2, + ] { + let epoch = compute_epoch_at_slot(signed_header.message.slot); + let domain = get_domain(state, constants::DOMAIN_BEACON_PROPOSER, Some(epoch)); + let signing_root = compute_signing_root(signed_header.message.hash_tree_root(), domain); + verify( + bls::verify(&pubkey, signing_root, &signed_header.signature), + "bls.Verify(proposer.pubkey, signing_root, signed_header.signature)", + )?; + } + + slash_validator(state, proposer_index, None, config)?; + Ok(()) +} + +// --------------------------------------------------------------------------- +// Attester slashings +// --------------------------------------------------------------------------- + +/// Slashes every slashable validator in the overlap of two conflicting +/// attestations' attesting sets. +/// +/// The two indexed attestations must each be independently valid (sorted, +/// unique, unslashed-signature-correct) before their overlap means anything: +/// evidence built from a forged or malformed attestation proves nothing. +/// It is not enough for the overlap to be non-empty either. If every +/// validator in it has already been slashed (and so is past +/// [`is_slashable_validator`]'s reach) or has already withdrawn, the +/// operation has no effect and including it would let a block waste space +/// (or, worse, let a proposer replay old evidence) for free. +pub fn process_attester_slashing( + state: &mut BeaconState, + attester_slashing: &phase0::AttesterSlashing, + config: &Config, +) -> Result<()> { + let attestation_1 = &attester_slashing.attestation_1; + let attestation_2 = &attester_slashing.attestation_2; + + verify( + is_slashable_attestation_data(&attestation_1.data, &attestation_2.data), + "is_slashable_attestation_data(attestation_1.data, attestation_2.data)", + )?; + verify( + is_valid_indexed_attestation(state, attestation_1), + "is_valid_indexed_attestation(state, attestation_1)", + )?; + verify( + is_valid_indexed_attestation(state, attestation_2), + "is_valid_indexed_attestation(state, attestation_2)", + )?; + + let current_epoch = get_current_epoch(state); + // `is_valid_indexed_attestation` already required both index lists to be + // sorted and unique, so walking `attestation_1`'s list in order while + // filtering by membership in `attestation_2`'s set yields the + // intersection already sorted, matching the specification's + // `sorted(indices)` without a separate sort. + let indices_2: HashSet = + attestation_2.attesting_indices.iter().copied().collect(); + + let mut slashed_any = false; + for &index in attestation_1.attesting_indices.iter() { + if !indices_2.contains(&index) { + continue; + } + if is_slashable_validator(state.validator(index)?, current_epoch) { + slash_validator(state, index, None, config)?; + slashed_any = true; + } + } + verify( + slashed_any, + "at least one validator in the intersection of the two attesting index sets was slashed", + )?; + Ok(()) +} + +// --------------------------------------------------------------------------- +// Attestations +// --------------------------------------------------------------------------- + +/// Records an attestation for later reward accounting, and checks its +/// signature. +/// +/// Phase0 cannot score an attestation on arrival, so this only validates its +/// shape (target epoch, inclusion window, committee) and its claimed source +/// checkpoint, then defers the actual reward to the epoch boundary by +/// appending a [`phase0::PendingAttestation`] to whichever of the state's two +/// attestation lists matches the target epoch. The specification checks the +/// signature last, after that append, so a block with a well-formed but +/// unsigned attestation still leaves the append in place before the whole +/// block is rejected; callers that need the pre-state intact must clone it +/// first (see [`crate::beacon::stf`]'s module documentation). +/// +/// Takes `config` only for symmetry with the other operation processors +/// [`process_operations`] dispatches to uniformly; nothing this function +/// calls needs a runtime configuration value. +pub fn process_attestation( + state: &mut BeaconState, + attestation: &phase0::Attestation, + _config: &Config, +) -> Result<()> { + let data = attestation.data; + let current_epoch = get_current_epoch(state); + let previous_epoch = get_previous_epoch(state); + + verify( + data.target.epoch == previous_epoch || data.target.epoch == current_epoch, + "data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))", + )?; + verify( + data.target.epoch == compute_epoch_at_slot(data.slot), + "data.target.epoch == compute_epoch_at_slot(data.slot)", + )?; + + // Both bounds are driven directly by `data.slot`, which comes straight off + // the wire, so a hostile value close to `u64::MAX` must not be allowed to + // wrap either bound into something that vacuously accepts the attestation. + let min_slot = data + .slot + .checked_add(preset::MIN_ATTESTATION_INCLUSION_DELAY) + .ok_or(Error::ArithmeticOverflow( + "data.slot + MIN_ATTESTATION_INCLUSION_DELAY", + ))?; + let max_slot = data + .slot + .checked_add(preset::SLOTS_PER_EPOCH) + .ok_or(Error::ArithmeticOverflow("data.slot + SLOTS_PER_EPOCH"))?; + verify( + min_slot <= state.slot() && state.slot() <= max_slot, + "data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH", + )?; + verify( + data.index < get_committee_count_per_slot(state, data.target.epoch), + "data.index < get_committee_count_per_slot(state, data.target.epoch)", + )?; + + let committee = get_beacon_committee(state, data.slot, data.index)?; + verify( + attestation.aggregation_bits.len() == committee.len(), + "len(attestation.aggregation_bits) == len(committee)", + )?; + + // Safe: `min_slot <= state.slot()` above and `min_slot >= data.slot` + // (the inclusion delay is non-negative), so `data.slot <= state.slot()`. + let pending_attestation = phase0::PendingAttestation { + data, + aggregation_bits: attestation.aggregation_bits.clone(), + inclusion_delay: state.slot() - data.slot, + proposer_index: get_beacon_proposer_index(state)?, + }; + + if data.target.epoch == current_epoch { + verify( + data.source == state.current_justified_checkpoint(), + "data.source == state.current_justified_checkpoint", + )?; + super::phase0_state(state, "process_attestation")? + .current_epoch_attestations + .push(pending_attestation)?; + } else { + verify( + data.source == state.previous_justified_checkpoint(), + "data.source == state.previous_justified_checkpoint", + )?; + super::phase0_state(state, "process_attestation")? + .previous_epoch_attestations + .push(pending_attestation)?; + } + + let indexed_attestation = get_indexed_attestation(state, attestation)?; + verify( + is_valid_indexed_attestation(state, &indexed_attestation), + "is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))", + )?; + + Ok(()) +} + +// --------------------------------------------------------------------------- +// Deposits +// --------------------------------------------------------------------------- + +/// Builds the registry entry a new deposit creates. +/// +/// The effective balance rounds the deposit amount down to a multiple of +/// `EFFECTIVE_BALANCE_INCREMENT` before capping it. Subtracting the remainder +/// can never underflow: a modulus is always at most the value it divides. +pub fn get_validator_from_deposit( + pubkey: crate::beacon::primitives::BlsPubkey, + withdrawal_credentials: crate::beacon::primitives::Bytes32, + amount: Gwei, +) -> Validator { + let effective_balance = + (amount - amount % preset::EFFECTIVE_BALANCE_INCREMENT).min(preset::MAX_EFFECTIVE_BALANCE); + + Validator { + pubkey, + withdrawal_credentials, + effective_balance, + slashed: false, + activation_eligibility_epoch: FAR_FUTURE_EPOCH, + activation_epoch: FAR_FUTURE_EPOCH, + exit_epoch: FAR_FUTURE_EPOCH, + withdrawable_epoch: FAR_FUTURE_EPOCH, + } +} + +/// Appends a brand-new validator and its starting balance. +/// +/// Every per-validator list is positionally parallel and must be grown +/// together; nothing about this operation should ever be run for a `pubkey` +/// already in the registry (see [`apply_deposit`], the only caller). +/// +/// From altair on there are five such lists, not two. Altair adds +/// `previous_epoch_participation`, `current_epoch_participation`, and +/// `inactivity_scores`, each indexed by validator, and its specification grows +/// all three here alongside `validators` and `balances`. Missing them does not +/// fail loudly: every later read is bounds-checked, so the state simply carries +/// lists one entry short of the registry and produces a `hash_tree_root` that +/// disagrees with every other client. That is exactly how it showed up here, +/// as seven altair `deposit` cases failing on a post-state root with no other +/// symptom. +/// +/// Electra replaces this function outright, since a deposit there is queued +/// rather than credited, so `crate::beacon::stf::electra` has its own; this one serves +/// phase0 through deneb. The altair branch still covers every later fork +/// anyway, because being conservative here costs nothing and a silent +/// length mismatch costs a great deal. +pub fn add_validator_to_registry( + state: &mut BeaconState, + pubkey: crate::beacon::primitives::BlsPubkey, + withdrawal_credentials: crate::beacon::primitives::Bytes32, + amount: Gwei, +) -> Result<()> { + state.validators_mut().push(get_validator_from_deposit( + pubkey, + withdrawal_credentials, + amount, + ))?; + state.balances_mut().push(amount)?; + + if state.fork_name() >= ForkName::Altair { + let (previous, current, scores) = state.altair_validator_lists_mut()?; + previous.push(0)?; + current.push(0)?; + scores.push(0)?; + } + Ok(()) +} + +/// Credits a deposit: to a new validator if the public key is unseen, or as a +/// balance top-up if it already has an entry. +/// +/// The signature check here is the one place in the whole state transition +/// that does not use [`get_domain`]: a deposit is signed by a depositor who +/// has no way to know which fork, or even which chain, will eventually accept +/// it, so it cannot commit to a genesis validators root or a fork version the +/// way every other signed message does. [`compute_deposit_domain`] instead +/// mixes in only the network's genesis fork version with an all-zero +/// validators root, giving every deposit across every fork of one network the +/// same signing domain. +/// +/// A signature that fails this check is not an error: the deposit is simply +/// not credited to a new validator; see [`process_deposit`], the only caller, +/// for why that is safe. +pub fn apply_deposit( + state: &mut BeaconState, + pubkey: crate::beacon::primitives::BlsPubkey, + withdrawal_credentials: crate::beacon::primitives::Bytes32, + amount: Gwei, + signature: crate::beacon::primitives::BlsSignature, + config: &Config, +) -> Result<()> { + let existing_index = state + .validators() + .iter() + .position(|validator| validator.pubkey == pubkey); + + match existing_index { + None => { + let deposit_message = DepositMessage { + pubkey, + withdrawal_credentials, + amount, + }; + let domain = compute_deposit_domain(config.genesis_fork_version); + let signing_root = compute_signing_root(deposit_message.hash_tree_root(), domain); + if bls::verify(&pubkey, signing_root, &signature) { + add_validator_to_registry(state, pubkey, withdrawal_credentials, amount)?; + } + } + Some(index) => { + increase_balance(state, index as ValidatorIndex, amount)?; + } + } + + Ok(()) +} + +/// Verifies a deposit's merkle proof, then applies it. +/// +/// The index advances before the deposit is applied, and advances +/// unconditionally, whether or not the signature inside turns out to be +/// valid. Deposits are processed strictly in the order the deposit contract +/// received them, so the index is really "how many deposits have been +/// consumed", not "how many produced a validator"; conflating the two would +/// let one depositor's bad signature desynchronize every subsequent deposit's +/// expected merkle position from the contract's own tree. +pub fn process_deposit(state: &mut BeaconState, deposit: &Deposit, config: &Config) -> Result<()> { + verify( + is_valid_merkle_branch( + deposit.data.hash_tree_root(), + &deposit.proof, + (constants::DEPOSIT_CONTRACT_TREE_DEPTH + 1) as u64, + state.eth1_deposit_index(), + state.eth1_data().deposit_root, + ), + "is_valid_merkle_branch(hash_tree_root(deposit.data), deposit.proof, DEPOSIT_CONTRACT_TREE_DEPTH + 1, state.eth1_deposit_index, state.eth1_data.deposit_root)", + )?; + + *state.eth1_deposit_index_mut() += 1; + + apply_deposit( + state, + deposit.data.pubkey, + deposit.data.withdrawal_credentials, + deposit.data.amount, + deposit.data.signature, + config, + ) +} + +// --------------------------------------------------------------------------- +// Voluntary exits +// --------------------------------------------------------------------------- + +/// Starts a validator's voluntary exit. +/// +/// Four conditions gate it, each guarding against a different way an exit +/// could be abused: the validator must still be active (an exited or +/// unactivated validator has nothing left to exit from), not already +/// exiting (so this cannot be replayed to push the exit queue further out), +/// past its own requested epoch (an exit cannot be redeemed early), and past +/// `SHARD_COMMITTEE_PERIOD` since activation (so a validator cannot buy a +/// committee assignment and immediately leave before it can be held to +/// account for anything done in it). +pub fn process_voluntary_exit( + state: &mut BeaconState, + signed_voluntary_exit: &SignedVoluntaryExit, + config: &Config, +) -> Result<()> { + let voluntary_exit = signed_voluntary_exit.message; + let current_epoch = get_current_epoch(state); + let validator = state.validator(voluntary_exit.validator_index)?; + + verify( + is_active_validator(validator, current_epoch), + "is_active_validator(validator, get_current_epoch(state))", + )?; + verify( + validator.exit_epoch == FAR_FUTURE_EPOCH, + "validator.exit_epoch == FAR_FUTURE_EPOCH", + )?; + verify( + current_epoch >= voluntary_exit.epoch, + "get_current_epoch(state) >= voluntary_exit.epoch", + )?; + // `validator.activation_epoch` is settled, previously-validated state + // (assigned by registry updates from the chain's own current epoch), not + // a value an attacker supplies directly the way `data.slot` is above, but + // checked anyway since the cost of doing so is free. + let eligible_epoch = validator + .activation_epoch + .checked_add(config.shard_committee_period) + .ok_or(Error::ArithmeticOverflow( + "validator.activation_epoch + SHARD_COMMITTEE_PERIOD", + ))?; + verify( + current_epoch >= eligible_epoch, + "get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD", + )?; + + let domain = get_domain( + state, + constants::DOMAIN_VOLUNTARY_EXIT, + Some(voluntary_exit.epoch), + ); + let signing_root = compute_signing_root(voluntary_exit.hash_tree_root(), domain); + verify( + bls::verify( + &validator.pubkey, + signing_root, + &signed_voluntary_exit.signature, + ), + "bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)", + )?; + + initiate_validator_exit(state, voluntary_exit.validator_index, config)?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use blst::min_pk::SecretKey; + + use super::*; + use crate::beacon::containers::phase0::{AttesterSlashing, IndexedAttestation}; + use crate::beacon::containers::shared::{ + AttestationData, BeaconBlockHeader, Checkpoint, SignedBeaconBlockHeader, + }; + use crate::beacon::primitives::{BlsPubkey, BlsSignature, Root}; + + #[test] + fn identical_proposer_slashing_headers_are_rejected() { + let mut state = crate::beacon::helpers::test_state::with_validators(4); + let config = Config::mainnet(); + + let header = BeaconBlockHeader { + slot: state.slot(), + proposer_index: 0, + ..Default::default() + }; + let signed_header = SignedBeaconBlockHeader { + message: header, + signature: BlsSignature::default(), + }; + // Two identical headers carry no evidence of equivocation: the spec + // requires them to differ before anything else about the slashing + // (proposer identity, signatures) is even inspected. + let slashing = ProposerSlashing { + signed_header_1: signed_header.clone(), + signed_header_2: signed_header, + }; + + assert!(process_proposer_slashing(&mut state, &slashing, &config).is_err()); + } + + #[test] + fn an_attester_slashing_that_slashes_nobody_is_rejected() { + let mut state = crate::beacon::helpers::test_state::with_validators(4); + let config = Config::mainnet(); + + // A real key pair rather than a placeholder: `is_valid_indexed_attestation` + // genuinely checks the aggregate signature, and only a valid one lets this + // test reach (and so actually exercise) the "at least one validator + // slashed" check rather than failing earlier for an unrelated reason. + let secret_key = SecretKey::key_gen(&[7u8; 32], &[]).expect("32 bytes of key material"); + let public_key = secret_key.sk_to_pk(); + { + let validator = state.validator_mut(0).expect("validator 0 exists"); + validator.pubkey = BlsPubkey(public_key.to_bytes()); + // Already slashed, so the one validator in the overlap of the two + // attestations' attesting sets is not slashable, and the + // operation must still be rejected even though the overlap + // itself is non-empty. + validator.slashed = true; + } + + let target_epoch = 1; + let data_1 = AttestationData { + slot: preset::SLOTS_PER_EPOCH, + index: 0, + beacon_block_root: Root::repeat_byte(1), + source: Checkpoint::default(), + target: Checkpoint { + epoch: target_epoch, + root: Root::repeat_byte(1), + }, + }; + // A double vote: same target epoch, different content, both from + // validator 0. That is enough for `is_slashable_attestation_data` + // without needing a surround vote's separate source/target spread. + let data_2 = AttestationData { + beacon_block_root: Root::repeat_byte(2), + target: Checkpoint { + epoch: target_epoch, + root: Root::repeat_byte(2), + }, + ..data_1 + }; + + // Both attestations share a target epoch, so they share a domain; + // signing under exactly what `is_valid_indexed_attestation` will + // recompute is what makes these signatures genuinely valid rather + // than merely well-formed. + let domain = get_domain( + &state, + constants::DOMAIN_BEACON_ATTESTER, + Some(target_epoch), + ); + const DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; + let sign = |data: &AttestationData| { + let signing_root = compute_signing_root(data.hash_tree_root(), domain); + BlsSignature( + secret_key + .sign(signing_root.as_slice(), DST, &[]) + .to_bytes(), + ) + }; + + let attestation_1 = IndexedAttestation { + attesting_indices: vec![0] + .try_into() + .expect("one index, far below the committee limit"), + data: data_1, + signature: sign(&data_1), + }; + let attestation_2 = IndexedAttestation { + attesting_indices: vec![0] + .try_into() + .expect("one index, far below the committee limit"), + data: data_2, + signature: sign(&data_2), + }; + let slashing = AttesterSlashing { + attestation_1, + attestation_2, + }; + + assert!(process_attester_slashing(&mut state, &slashing, &config).is_err()); + } +} diff --git a/crates/blockchain/state_transition/src/beacon/upgrade.rs b/crates/blockchain/state_transition/src/beacon/upgrade.rs new file mode 100644 index 000000000..1b0a0bcbb --- /dev/null +++ b/crates/blockchain/state_transition/src/beacon/upgrade.rs @@ -0,0 +1,1173 @@ +//! Fork-boundary state upgrades. +//! +//! `process_slots` runs an irregular state change whenever it advances the +//! state across a fork's activation epoch: the state's shape itself changes, +//! which an ordinary block-driven mutation can never do. Each fork that +//! changes the state's shape gets one function here, named and structured +//! after the specification's own `upgrade_to_`, plus one arm in +//! [`upgrade_state`] so a caller that only knows the target [`ForkName`] does +//! not have to match on it itself. +//! +//! Every upgrade function takes the pre-state by reference and returns a new +//! post-state rather than mutating in place. The two states are different +//! Rust types (`phase0::BeaconState` and `altair::BeaconState` are not the +//! same struct), so an in-place upgrade is not expressible in the type system +//! to begin with, and returning a value keeps the field-by-field mapping laid +//! out once, in one place, checkable against the specification's own +//! constructor line by line. + +use crate::beacon::config::Config; +use crate::beacon::constants; +use crate::beacon::containers::{ + BeaconState, EpochParticipation, Fork, InactivityScores, altair, bellatrix, capella, deneb, + electra, fulu, phase0, +}; +use crate::beacon::error::{Error, Result}; +use crate::beacon::fork::ForkName; +use crate::beacon::helpers::attestation::get_attesting_indices; +use crate::beacon::helpers::misc::{compute_activation_exit_epoch, compute_epoch_at_slot}; +use crate::beacon::lean_fork_unreachable; +use crate::beacon::preset; +use crate::beacon::primitives::{ + BlsPubkey, BlsSignature, Bytes32, ExecutionAddress, ExecutionBlockHash, Root, Uint256, + ValidatorIndex, +}; + +/// Replays `pending_attestations` into `post`'s `previous_epoch_participation`. +/// +/// Phase0 scores an attestation only at the epoch boundary, by replaying +/// whatever accumulated in `previous_epoch_attestations`. Altair scores one +/// the moment it is processed and keeps no backlog, so without this step the +/// upgrade would silently discard the attestations phase0 was still holding +/// for the epoch that was in progress when the fork activated: those flags +/// are exactly what the next epoch boundary's rewards pass reads. +/// +/// Takes `post` as the enum rather than the concrete altair struct because +/// [`get_attestation_participation_flag_indices`](crate::beacon::helpers::altair::get_attestation_participation_flag_indices) +/// and [`get_attesting_indices`] both read only fields every fork shares +/// (justified checkpoints, block roots, committees), so they are written +/// against `&BeaconState` like every other state accessor in this module. The +/// match is repeated once per attestation rather than hoisted above the loop +/// so that each iteration's immutable borrow (for those two calls) ends +/// before the mutable borrow (for writing the flags) begins; a single match +/// held across the whole loop would keep the mutable borrow alive throughout +/// and rule out the immutable calls entirely. +fn translate_participation( + post: &mut BeaconState, + pending_attestations: &[phase0::PendingAttestation], +) -> Result<()> { + for attestation in pending_attestations { + let participation_flag_indices = + crate::beacon::helpers::altair::get_attestation_participation_flag_indices( + post, + &attestation.data, + attestation.inclusion_delay, + )?; + + // `get_attesting_indices` is typed for a phase0 `Attestation`, not a + // `PendingAttestation`. The two carry exactly the fields it reads + // (`data` and `aggregation_bits`); a signature-less `Attestation` + // assembled from them stands in rather than adding a second, + // decomposed entry point for one caller. + let attestation_for_indices = phase0::Attestation { + aggregation_bits: attestation.aggregation_bits.clone(), + data: attestation.data, + signature: BlsSignature::default(), + }; + let attesting_indices = get_attesting_indices(post, &attestation_for_indices)?; + + let altair_state = match post { + BeaconState::Altair(state) => state, + other => { + return Err(Error::UnsupportedForFork { + function: "translate_participation", + fork: other.fork_name(), + }); + } + }; + for index in attesting_indices { + let entry = altair_state + .previous_epoch_participation + .get_mut(index as usize) + .ok_or(Error::UnknownValidator(index))?; + for &flag_index in &participation_flag_indices { + *entry = crate::beacon::helpers::altair::add_flag(*entry, flag_index); + } + } + } + + Ok(()) +} + +/// Upgrades a phase0 state to altair's shape. +/// +/// Transcribed from `specs/altair/fork.md`'s `upgrade_to_altair`. Fields +/// through `slashings` carry over unchanged; `previous_epoch_attestations` +/// and `current_epoch_attestations` have no altair counterpart and are +/// dropped, replaced by freshly zeroed participation flags one entry per +/// validator (never left empty, since every validator needs a flag byte from +/// the moment the fork activates); `inactivity_scores` is likewise zeroed at +/// one entry per validator, since inactivity leak accounting starts fresh +/// here. `fork` is rebuilt rather than carried over: its `previous_version` +/// becomes the pre-state's `current_version`, and `current_version` becomes +/// `config.altair_fork_version`, which is what makes this the fork boundary +/// rather than a same-fork slot advance. +pub fn upgrade_to_altair( + pre: &phase0::BeaconState, + config: &Config, +) -> Result { + // Equivalent to the spec's `phase0.get_current_epoch(pre)`: computed + // straight from `pre.slot` rather than through the `get_current_epoch` + // accessor, which needs `&BeaconState` and so would otherwise force a + // whole-state clone just to read one field of it. + let epoch = compute_epoch_at_slot(pre.slot); + let validator_count = pre.validators.len(); + + let fork = Fork { + previous_version: pre.fork.current_version, + current_version: config.altair_fork_version, + epoch, + }; + + // `SyncCommittee` has no `Default` impl (its `SszVector` field does not, + // unlike `SszList`, since a vector can never be validly empty). This + // placeholder exists only so the struct literal below type-checks before + // the real committees, derived a few lines down from `post` itself, are + // known. It is never observed: `get_next_sync_committee` reads + // `validators`, `slot`, and `randao_mixes`, none of which are the sync + // committee fields it is about to overwrite. + let placeholder_sync_committee = altair::SyncCommittee { + pubkeys: altair::SyncCommitteePubkeys::try_from(vec![ + BlsPubkey::default(); + preset::SYNC_COMMITTEE_SIZE + ])?, + aggregate_pubkey: BlsPubkey::default(), + }; + + let post = altair::BeaconState { + genesis_time: pre.genesis_time, + genesis_validators_root: pre.genesis_validators_root, + slot: pre.slot, + fork, + latest_block_header: pre.latest_block_header.clone(), + block_roots: pre.block_roots.clone(), + state_roots: pre.state_roots.clone(), + historical_roots: pre.historical_roots.clone(), + eth1_data: pre.eth1_data.clone(), + eth1_data_votes: pre.eth1_data_votes.clone(), + eth1_deposit_index: pre.eth1_deposit_index, + validators: pre.validators.clone(), + balances: pre.balances.clone(), + randao_mixes: pre.randao_mixes.clone(), + slashings: pre.slashings.clone(), + previous_epoch_participation: EpochParticipation::try_from(vec![0u8; validator_count])?, + current_epoch_participation: EpochParticipation::try_from(vec![0u8; validator_count])?, + justification_bits: pre.justification_bits.clone(), + previous_justified_checkpoint: pre.previous_justified_checkpoint, + current_justified_checkpoint: pre.current_justified_checkpoint, + finalized_checkpoint: pre.finalized_checkpoint, + inactivity_scores: InactivityScores::try_from(vec![0u64; validator_count])?, + current_sync_committee: placeholder_sync_committee.clone(), + next_sync_committee: placeholder_sync_committee, + }; + let mut post = BeaconState::Altair(post); + + // Fill in previous epoch participation from the pre-state's pending + // attestations, before the sync committees below: matches the spec's own + // ordering, and neither step depends on the other's result. + translate_participation(&mut post, &pre.previous_epoch_attestations)?; + + // Fill in sync committees. The specification calls `get_next_sync_committee` + // twice rather than computing it once and cloning the result, and its own + // comment says why: at the fork boundary there has been no sync-committee + // period boundary yet, so the current and next committees are the *same* + // committee by construction, not merely equal by coincidence. Calling + // the function twice keeps that guarantee explicit rather than relying on + // a clone to preserve it. + let current_sync_committee = crate::beacon::helpers::altair::get_next_sync_committee(&post)?; + let next_sync_committee = crate::beacon::helpers::altair::get_next_sync_committee(&post)?; + + let BeaconState::Altair(mut post) = post else { + unreachable!("post was constructed as BeaconState::Altair immediately above") + }; + post.current_sync_committee = current_sync_committee; + post.next_sync_committee = next_sync_committee; + + Ok(post) +} + +// --------------------------------------------------------------------------- +// Fork-state projections +// --------------------------------------------------------------------------- +// +// `upgrade_to_altair` takes its pre-state as the concrete `phase0::BeaconState` +// because phase0 already has a crate-wide projection to reuse +// (`crate::beacon::stf::phase0_state_ref`). Every upgrade below instead takes +// `pre: &BeaconState`, the enum, and projects down to the concrete struct +// itself: `upgrade_state` calls every one of these through the same +// signature, and threading the enum through uniformly is what lets it +// dispatch on `to: ForkName` alone rather than also matching on `pre`'s own +// shape at each call site. Altair and fulu already have a crate-wide +// projection of their own to reuse (`crate::beacon::helpers::altair::altair_state_ref`, +// `crate::beacon::helpers::fulu::fulu_state_ref`); bellatrix, capella, deneb, and +// electra do not, so those four are projected locally here, on the same +// pattern `crate::beacon::stf::phase0_state`/`phase0_state_ref` set. None of the four +// needs a mutable counterpart: [`upgrade_to_electra`] is the one function +// here that mutates a post-state field-by-field rather than only building +// one, and the fields it reaches for that [`BeaconState`]'s own accessors do +// not cover (`exit_balance_to_consume`, `consolidation_balance_to_consume`, +// `pending_deposits`) already have a projection to reuse in +// `crate::beacon::helpers::electra` (`electra_state`, returning `ElectraOrFuluMut`), +// so this file does not need a second one of its own. + +/// The bellatrix state, or an error naming the function that needs one. +fn bellatrix_state_ref<'a>( + state: &'a BeaconState, + function: &'static str, +) -> Result<&'a bellatrix::BeaconState> { + match state { + BeaconState::Bellatrix(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +/// The capella state, or an error naming the function that needs one. +fn capella_state_ref<'a>( + state: &'a BeaconState, + function: &'static str, +) -> Result<&'a capella::BeaconState> { + match state { + BeaconState::Capella(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +/// The deneb state, or an error naming the function that needs one. +fn deneb_state_ref<'a>( + state: &'a BeaconState, + function: &'static str, +) -> Result<&'a deneb::BeaconState> { + match state { + BeaconState::Deneb(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +/// The electra state, or an error naming the function that needs one. +/// +/// [`upgrade_to_fulu`]'s only use: fulu's pre-state is electra's shape. +/// [`upgrade_to_electra`] never needs this projection for its own `pre` +/// (that is [`deneb_state_ref`]'s job) or for reading back its freshly built +/// `post` (every read there goes through [`BeaconState`]'s fork-invariant +/// accessors or `crate::beacon::helpers::electra::electra_state`). +fn electra_state_ref<'a>( + state: &'a BeaconState, + function: &'static str, +) -> Result<&'a electra::BeaconState> { + match state { + BeaconState::Electra(state) => Ok(state), + other => Err(Error::UnsupportedForFork { + function, + fork: other.fork_name(), + }), + } +} + +// --------------------------------------------------------------------------- +// Execution payload header helpers +// --------------------------------------------------------------------------- + +/// An all-zero bellatrix execution payload header. +/// +/// `specs/bellatrix/fork.md`'s `upgrade_to_bellatrix` writes this as the bare +/// constructor call `ExecutionPayloadHeader()`, meaning every field at its +/// type's default. That is not `#[derive(Default)]` here: `logs_bloom` is an +/// [`libssz_types::SszVector`], which libssz gives no `Default` impl (a vector, +/// unlike a list, can never be validly empty, so there is no such thing as *the* +/// default one), so its all-zero value is built explicitly at its exact length +/// instead. +fn empty_bellatrix_execution_payload_header() -> Result { + Ok(bellatrix::ExecutionPayloadHeader { + parent_hash: ExecutionBlockHash::ZERO, + fee_recipient: ExecutionAddress::ZERO, + state_root: Bytes32::ZERO, + receipts_root: Bytes32::ZERO, + logs_bloom: bellatrix::LogsBloom::try_from(vec![0u8; preset::BYTES_PER_LOGS_BLOOM])?, + prev_randao: Bytes32::ZERO, + block_number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: 0, + extra_data: bellatrix::ExtraData::default(), + base_fee_per_gas: Uint256::ZERO, + block_hash: ExecutionBlockHash::ZERO, + transactions_root: Root::ZERO, + }) +} + +/// Upgrades an altair state to bellatrix's shape. +/// +/// Transcribed from `specs/bellatrix/fork.md`'s `upgrade_to_bellatrix`. Every +/// field through `next_sync_committee` carries over unchanged: bellatrix (the +/// Merge) changes no field altair already had. It adds exactly one, +/// `latest_execution_payload_header`, and that one starts as the all-zero +/// [`empty_bellatrix_execution_payload_header`] rather than anything copied +/// from `pre`: proof-of-work blocks were never beacon-chain execution +/// payloads, so there is no earlier payload for this field to summarize until +/// the first post-Merge block supplies one. +pub fn upgrade_to_bellatrix(pre: &BeaconState, config: &Config) -> Result { + let pre = crate::beacon::helpers::altair::altair_state_ref(pre, "upgrade_to_bellatrix")?; + let epoch = compute_epoch_at_slot(pre.slot); + + let fork = Fork { + previous_version: pre.fork.current_version, + current_version: config.bellatrix_fork_version, + epoch, + }; + + let post = bellatrix::BeaconState { + genesis_time: pre.genesis_time, + genesis_validators_root: pre.genesis_validators_root, + slot: pre.slot, + fork, + latest_block_header: pre.latest_block_header.clone(), + block_roots: pre.block_roots.clone(), + state_roots: pre.state_roots.clone(), + historical_roots: pre.historical_roots.clone(), + eth1_data: pre.eth1_data.clone(), + eth1_data_votes: pre.eth1_data_votes.clone(), + eth1_deposit_index: pre.eth1_deposit_index, + validators: pre.validators.clone(), + balances: pre.balances.clone(), + randao_mixes: pre.randao_mixes.clone(), + slashings: pre.slashings.clone(), + previous_epoch_participation: pre.previous_epoch_participation.clone(), + current_epoch_participation: pre.current_epoch_participation.clone(), + justification_bits: pre.justification_bits.clone(), + previous_justified_checkpoint: pre.previous_justified_checkpoint, + current_justified_checkpoint: pre.current_justified_checkpoint, + finalized_checkpoint: pre.finalized_checkpoint, + inactivity_scores: pre.inactivity_scores.clone(), + current_sync_committee: pre.current_sync_committee.clone(), + next_sync_committee: pre.next_sync_committee.clone(), + // [New in Bellatrix] + latest_execution_payload_header: empty_bellatrix_execution_payload_header()?, + }; + + Ok(BeaconState::Bellatrix(post)) +} + +/// Upgrades a bellatrix state to capella's shape. +/// +/// Transcribed from `specs/capella/fork.md`'s `upgrade_to_capella`. Every +/// field through `next_sync_committee` carries over unchanged, including +/// `historical_roots`: the specification copies it as-is rather than +/// truncating it. Freezing it in place (never appended to again, from this +/// fork on) is capella's actual change to it; `historical_summaries` (added +/// below) is where new history accumulates instead, which is why the two +/// coexist rather than one replacing the other outright. +/// +/// `latest_execution_payload_header` keeps its name and position but is +/// rebuilt as capella's own container, carrying every one of bellatrix's +/// header fields across individually and appending an empty +/// `withdrawals_root`: withdrawals are capella's new operation, so there is +/// no earlier payload's withdrawal root for this field to summarize yet, the +/// same reasoning [`upgrade_to_bellatrix`] applies to its own brand new +/// field. `next_withdrawal_index`, `next_withdrawal_validator_index`, and +/// `historical_summaries` are capella's other three additions, all starting +/// at their type's zero: the withdrawal sweep and the history it accumulates +/// both begin only once this fork is active. +pub fn upgrade_to_capella(pre: &BeaconState, config: &Config) -> Result { + let pre = bellatrix_state_ref(pre, "upgrade_to_capella")?; + let epoch = compute_epoch_at_slot(pre.slot); + + let fork = Fork { + previous_version: pre.fork.current_version, + current_version: config.capella_fork_version, + epoch, + }; + + let execution_header = &pre.latest_execution_payload_header; + let latest_execution_payload_header = capella::ExecutionPayloadHeader { + parent_hash: execution_header.parent_hash, + fee_recipient: execution_header.fee_recipient, + state_root: execution_header.state_root, + receipts_root: execution_header.receipts_root, + logs_bloom: execution_header.logs_bloom.clone(), + prev_randao: execution_header.prev_randao, + block_number: execution_header.block_number, + gas_limit: execution_header.gas_limit, + gas_used: execution_header.gas_used, + timestamp: execution_header.timestamp, + extra_data: execution_header.extra_data.clone(), + base_fee_per_gas: execution_header.base_fee_per_gas, + block_hash: execution_header.block_hash, + transactions_root: execution_header.transactions_root, + // [New in Capella] + withdrawals_root: Root::ZERO, + }; + + let post = capella::BeaconState { + genesis_time: pre.genesis_time, + genesis_validators_root: pre.genesis_validators_root, + slot: pre.slot, + fork, + latest_block_header: pre.latest_block_header.clone(), + block_roots: pre.block_roots.clone(), + state_roots: pre.state_roots.clone(), + historical_roots: pre.historical_roots.clone(), + eth1_data: pre.eth1_data.clone(), + eth1_data_votes: pre.eth1_data_votes.clone(), + eth1_deposit_index: pre.eth1_deposit_index, + validators: pre.validators.clone(), + balances: pre.balances.clone(), + randao_mixes: pre.randao_mixes.clone(), + slashings: pre.slashings.clone(), + previous_epoch_participation: pre.previous_epoch_participation.clone(), + current_epoch_participation: pre.current_epoch_participation.clone(), + justification_bits: pre.justification_bits.clone(), + previous_justified_checkpoint: pre.previous_justified_checkpoint, + current_justified_checkpoint: pre.current_justified_checkpoint, + finalized_checkpoint: pre.finalized_checkpoint, + inactivity_scores: pre.inactivity_scores.clone(), + current_sync_committee: pre.current_sync_committee.clone(), + next_sync_committee: pre.next_sync_committee.clone(), + latest_execution_payload_header, + // [New in Capella] + next_withdrawal_index: 0, + // [New in Capella] + next_withdrawal_validator_index: 0, + // [New in Capella] + historical_summaries: Default::default(), + }; + + Ok(BeaconState::Capella(post)) +} + +/// Upgrades a capella state to deneb's shape. +/// +/// Transcribed from `specs/deneb/fork.md`'s `upgrade_to_deneb`. The state's +/// field count does not change: every field through `historical_summaries` +/// carries over unchanged, and the only reshaping is +/// `latest_execution_payload_header`, rebuilt as deneb's own container with +/// every one of capella's header fields (now including `withdrawals_root`) +/// carried across individually, plus `blob_gas_used` and `excess_blob_gas` +/// starting at zero: deneb's blob fee market has no history to inherit +/// either, the same reasoning [`upgrade_to_bellatrix`] and +/// [`upgrade_to_capella`] apply to their own brand new fields. +pub fn upgrade_to_deneb(pre: &BeaconState, config: &Config) -> Result { + let pre = capella_state_ref(pre, "upgrade_to_deneb")?; + let epoch = compute_epoch_at_slot(pre.slot); + + let fork = Fork { + previous_version: pre.fork.current_version, + current_version: config.deneb_fork_version, + epoch, + }; + + let execution_header = &pre.latest_execution_payload_header; + let latest_execution_payload_header = deneb::ExecutionPayloadHeader { + parent_hash: execution_header.parent_hash, + fee_recipient: execution_header.fee_recipient, + state_root: execution_header.state_root, + receipts_root: execution_header.receipts_root, + logs_bloom: execution_header.logs_bloom.clone(), + prev_randao: execution_header.prev_randao, + block_number: execution_header.block_number, + gas_limit: execution_header.gas_limit, + gas_used: execution_header.gas_used, + timestamp: execution_header.timestamp, + extra_data: execution_header.extra_data.clone(), + base_fee_per_gas: execution_header.base_fee_per_gas, + block_hash: execution_header.block_hash, + transactions_root: execution_header.transactions_root, + withdrawals_root: execution_header.withdrawals_root, + // [New in Deneb:EIP4844] + blob_gas_used: 0, + // [New in Deneb:EIP4844] + excess_blob_gas: 0, + }; + + let post = deneb::BeaconState { + genesis_time: pre.genesis_time, + genesis_validators_root: pre.genesis_validators_root, + slot: pre.slot, + fork, + latest_block_header: pre.latest_block_header.clone(), + block_roots: pre.block_roots.clone(), + state_roots: pre.state_roots.clone(), + historical_roots: pre.historical_roots.clone(), + eth1_data: pre.eth1_data.clone(), + eth1_data_votes: pre.eth1_data_votes.clone(), + eth1_deposit_index: pre.eth1_deposit_index, + validators: pre.validators.clone(), + balances: pre.balances.clone(), + randao_mixes: pre.randao_mixes.clone(), + slashings: pre.slashings.clone(), + previous_epoch_participation: pre.previous_epoch_participation.clone(), + current_epoch_participation: pre.current_epoch_participation.clone(), + justification_bits: pre.justification_bits.clone(), + previous_justified_checkpoint: pre.previous_justified_checkpoint, + current_justified_checkpoint: pre.current_justified_checkpoint, + finalized_checkpoint: pre.finalized_checkpoint, + inactivity_scores: pre.inactivity_scores.clone(), + current_sync_committee: pre.current_sync_committee.clone(), + next_sync_committee: pre.next_sync_committee.clone(), + latest_execution_payload_header, + next_withdrawal_index: pre.next_withdrawal_index, + next_withdrawal_validator_index: pre.next_withdrawal_validator_index, + historical_summaries: pre.historical_summaries.clone(), + }; + + Ok(BeaconState::Deneb(post)) +} + +/// Upgrades a deneb state to electra's shape. +/// +/// Transcribed from `specs/electra/fork.md`'s `upgrade_to_electra`. Fields +/// through `historical_summaries` carry over unchanged; the nine electra +/// appends need more than a copy, because EIP-7251 changes what "how much +/// stake may enter or leave the validator set this epoch" even means. +/// +/// Before electra, activation and exit churn is a *count* of validators: +/// every validator activates at the same effective balance, so bounding how +/// many validators move per epoch bounds how much stake moves too. EIP-7251 +/// lets a validator's effective balance grow past that floor (given a +/// compounding withdrawal credential), which breaks the equivalence: one +/// large validator activating could move as much stake as thousands of +/// ordinary ones, so the churn limit has to be denominated in balance +/// instead. Electra cannot apply that retroactively: a validator already +/// active before this fork was admitted under the old count-based +/// accounting, which kept no record of how much of its stake that admitted. +/// Two migrations below are what electra does instead of pretending +/// otherwise: +/// +/// - A validator not yet active (`activation_epoch` still +/// [`constants::FAR_FUTURE_EPOCH`]) has its whole balance zeroed and +/// reinstated as a synthetic [`electra::PendingDeposit`], via +/// [`crate::beacon::helpers::electra::queue_entire_balance_and_reset_validator`], +/// so it re-enters through the queue the balance-based churn limit +/// actually governs, instead of activating under rules that no longer +/// exist. +/// - A validator that already upgraded to a compounding withdrawal +/// credential, and so is already sitting above +/// [`preset::MIN_ACTIVATION_BALANCE`], has that excess queued the same way +/// by [`crate::beacon::helpers::electra::queue_excess_active_balance`]: the +/// balance is real and already credited, but the count-based accounting +/// that admitted it never subjected it to any churn limit at all, so it +/// has to pass through the new one now, after the fact, rather than being +/// grandfathered in as if it already had. +/// +/// The two churn fields this upgrade sets, `exit_balance_to_consume` and +/// `consolidation_balance_to_consume`, are computed by calling +/// [`crate::beacon::helpers::electra::get_activation_exit_churn_limit`] and +/// [`crate::beacon::helpers::electra::get_consolidation_churn_limit`] on `post` +/// itself, after every fork-invariant field (crucially, `validators` and +/// `balances`) has already been copied across from `pre`, not on `pre` +/// directly. The specification's own pseudocode does this too, for a reason +/// invisible from the field values alone: those two helpers read through +/// `&BeaconState`, matching against the electra variant internally, so they +/// cannot run at all until the state they are reading exists as +/// `BeaconState::Electra` rather than still being `pre`'s +/// `deneb::BeaconState`. Numerically the two states agree at this exact +/// point (the validator-and-balance migrations below have not run yet), but +/// the ordering the specification chose is load-bearing for a different +/// reason than the numbers: it is the earliest point at which a value of the +/// right *type* exists to call them with. +/// +/// [`crate::beacon::helpers::electra::switch_to_compounding_validator`] is not +/// called here: the specification calls it from a validator's own +/// credential-switch request, not from this fork boundary. +pub fn upgrade_to_electra(pre: &BeaconState, config: &Config) -> Result { + let pre = deneb_state_ref(pre, "upgrade_to_electra")?; + // Reused for every one of the specification's own repeated + // `get_current_epoch(pre)` calls below: `pre` is never mutated between + // them, so recomputing it each time would just recompute this same + // value. + let epoch = compute_epoch_at_slot(pre.slot); + + let fork = Fork { + previous_version: pre.fork.current_version, + current_version: config.electra_fork_version, + epoch, + }; + + let mut earliest_exit_epoch = compute_activation_exit_epoch(epoch); + for validator in pre.validators.iter() { + if validator.exit_epoch != constants::FAR_FUTURE_EPOCH + && validator.exit_epoch > earliest_exit_epoch + { + earliest_exit_epoch = validator.exit_epoch; + } + } + earliest_exit_epoch = earliest_exit_epoch + .checked_add(1) + .ok_or(Error::ArithmeticOverflow("earliest_exit_epoch + 1"))?; + + let post = electra::BeaconState { + genesis_time: pre.genesis_time, + genesis_validators_root: pre.genesis_validators_root, + slot: pre.slot, + fork, + latest_block_header: pre.latest_block_header.clone(), + block_roots: pre.block_roots.clone(), + state_roots: pre.state_roots.clone(), + historical_roots: pre.historical_roots.clone(), + eth1_data: pre.eth1_data.clone(), + eth1_data_votes: pre.eth1_data_votes.clone(), + eth1_deposit_index: pre.eth1_deposit_index, + validators: pre.validators.clone(), + balances: pre.balances.clone(), + randao_mixes: pre.randao_mixes.clone(), + slashings: pre.slashings.clone(), + previous_epoch_participation: pre.previous_epoch_participation.clone(), + current_epoch_participation: pre.current_epoch_participation.clone(), + justification_bits: pre.justification_bits.clone(), + previous_justified_checkpoint: pre.previous_justified_checkpoint, + current_justified_checkpoint: pre.current_justified_checkpoint, + finalized_checkpoint: pre.finalized_checkpoint, + inactivity_scores: pre.inactivity_scores.clone(), + current_sync_committee: pre.current_sync_committee.clone(), + next_sync_committee: pre.next_sync_committee.clone(), + latest_execution_payload_header: pre.latest_execution_payload_header.clone(), + next_withdrawal_index: pre.next_withdrawal_index, + next_withdrawal_validator_index: pre.next_withdrawal_validator_index, + historical_summaries: pre.historical_summaries.clone(), + // [New in Electra:EIP6110] + deposit_requests_start_index: constants::UNSET_DEPOSIT_REQUESTS_START_INDEX, + // [New in Electra:EIP7251] Never overwritten: unlike the two fields + // below, the specification has no post-construction assignment for + // this one. + deposit_balance_to_consume: 0, + // [New in Electra:EIP7251] Overwritten below, once `post` exists as + // an electra state; see this function's own doc for why that + // ordering is load-bearing. + exit_balance_to_consume: 0, + // [New in Electra:EIP7251] + earliest_exit_epoch, + // [New in Electra:EIP7251] Overwritten below; see + // `exit_balance_to_consume` above. + consolidation_balance_to_consume: 0, + // [New in Electra:EIP7251] + earliest_consolidation_epoch: compute_activation_exit_epoch(epoch), + // [New in Electra:EIP7251] + pending_deposits: Default::default(), + // [New in Electra:EIP7251] + pending_partial_withdrawals: Default::default(), + // [New in Electra:EIP7251] + pending_consolidations: Default::default(), + }; + let mut post = BeaconState::Electra(post); + + // Churn is computed from `post`, not `pre`: see this function's own doc + // for why the ordering is load-bearing even though the two states still + // agree numerically at this point. + let exit_balance_to_consume = + crate::beacon::helpers::electra::get_activation_exit_churn_limit(&post, config)?; + let consolidation_balance_to_consume = + crate::beacon::helpers::electra::get_consolidation_churn_limit(&post, config)?; + { + let mut fields = + crate::beacon::helpers::electra::electra_state(&mut post, "upgrade_to_electra")?; + *fields.exit_balance_to_consume_mut() = exit_balance_to_consume; + *fields.consolidation_balance_to_consume_mut() = consolidation_balance_to_consume; + } + + // Add validators that are not yet active to the pending deposit queue: + // see this function's own doc for why a not-yet-active validator cannot + // simply keep activating under rules the state no longer tracks. Sorted + // by `(activation_eligibility_epoch, index)`, matching the + // specification's own tie-break exactly. + let mut pre_activation: Vec = post + .validators() + .iter() + .enumerate() + .filter(|(_, validator)| validator.activation_epoch == constants::FAR_FUTURE_EPOCH) + .map(|(index, _)| index as ValidatorIndex) + .collect(); + pre_activation.sort_by_key(|&index| { + let eligibility_epoch = post + .validator(index) + .expect("index was read from post.validators() above") + .activation_eligibility_epoch; + (eligibility_epoch, index) + }); + for index in pre_activation { + crate::beacon::helpers::electra::queue_entire_balance_and_reset_validator( + &mut post, index, + )?; + } + + // Ensure early adopters of a compounding withdrawal credential go + // through the same activation churn: a fresh pass over every validator + // (including the ones the loop above already zeroed, matching the + // specification's own unconditional second loop) rather than folded into + // it, since compounding eligibility and pre-activation are independent + // conditions on the same registry. + let compounding_indices: Vec = post + .validators() + .iter() + .enumerate() + .filter(|(_, validator)| { + crate::beacon::helpers::electra::has_compounding_withdrawal_credential(validator) + }) + .map(|(index, _)| index as ValidatorIndex) + .collect(); + for index in compounding_indices { + crate::beacon::helpers::electra::queue_excess_active_balance(&mut post, index)?; + } + + Ok(post) +} + +/// Upgrades an electra state to fulu's shape. +/// +/// Transcribed from `specs/fulu/fork.md`'s `upgrade_to_fulu`. Every field +/// through `pending_consolidations` carries over unchanged; the one addition +/// is `proposer_lookahead`, filled by +/// [`crate::beacon::helpers::fulu::initialize_proposer_lookahead`] rather than left +/// empty, since [`crate::beacon::helpers::fulu::get_beacon_proposer_index`] reads it +/// as a lookup from the moment this fork activates and has no on-demand +/// fallback to compute it from if it were left blank (see that module's own +/// docs for why the two coexist rather than one calling the other). +/// +/// [`initialize_proposer_lookahead`](crate::beacon::helpers::fulu::initialize_proposer_lookahead) +/// is called on `pre` while it is still electra's shape, one statement before +/// a `proposer_lookahead` field exists anywhere in `post` to write into: it +/// reads through fork-invariant accessors only, never a fulu-only field, so +/// there is nothing circular about calling it on a pre-fulu state. +pub fn upgrade_to_fulu(pre: &BeaconState, config: &Config) -> Result { + let pre_state = electra_state_ref(pre, "upgrade_to_fulu")?; + let epoch = compute_epoch_at_slot(pre_state.slot); + + let fork = Fork { + previous_version: pre_state.fork.current_version, + current_version: config.fulu_fork_version, + epoch, + }; + + // Called on the original enum-typed `pre`, not `pre_state`: see this + // function's own doc for why that is safe one statement before `post`'s + // `proposer_lookahead` field exists. + let proposer_lookahead = crate::beacon::helpers::fulu::initialize_proposer_lookahead(pre)?; + + let post = fulu::BeaconState { + genesis_time: pre_state.genesis_time, + genesis_validators_root: pre_state.genesis_validators_root, + slot: pre_state.slot, + fork, + latest_block_header: pre_state.latest_block_header.clone(), + block_roots: pre_state.block_roots.clone(), + state_roots: pre_state.state_roots.clone(), + historical_roots: pre_state.historical_roots.clone(), + eth1_data: pre_state.eth1_data.clone(), + eth1_data_votes: pre_state.eth1_data_votes.clone(), + eth1_deposit_index: pre_state.eth1_deposit_index, + validators: pre_state.validators.clone(), + balances: pre_state.balances.clone(), + randao_mixes: pre_state.randao_mixes.clone(), + slashings: pre_state.slashings.clone(), + previous_epoch_participation: pre_state.previous_epoch_participation.clone(), + current_epoch_participation: pre_state.current_epoch_participation.clone(), + justification_bits: pre_state.justification_bits.clone(), + previous_justified_checkpoint: pre_state.previous_justified_checkpoint, + current_justified_checkpoint: pre_state.current_justified_checkpoint, + finalized_checkpoint: pre_state.finalized_checkpoint, + inactivity_scores: pre_state.inactivity_scores.clone(), + current_sync_committee: pre_state.current_sync_committee.clone(), + next_sync_committee: pre_state.next_sync_committee.clone(), + latest_execution_payload_header: pre_state.latest_execution_payload_header.clone(), + next_withdrawal_index: pre_state.next_withdrawal_index, + next_withdrawal_validator_index: pre_state.next_withdrawal_validator_index, + historical_summaries: pre_state.historical_summaries.clone(), + deposit_requests_start_index: pre_state.deposit_requests_start_index, + deposit_balance_to_consume: pre_state.deposit_balance_to_consume, + exit_balance_to_consume: pre_state.exit_balance_to_consume, + earliest_exit_epoch: pre_state.earliest_exit_epoch, + consolidation_balance_to_consume: pre_state.consolidation_balance_to_consume, + earliest_consolidation_epoch: pre_state.earliest_consolidation_epoch, + pending_deposits: pre_state.pending_deposits.clone(), + pending_partial_withdrawals: pre_state.pending_partial_withdrawals.clone(), + pending_consolidations: pre_state.pending_consolidations.clone(), + // [New in Fulu:EIP7917] + proposer_lookahead: proposer_lookahead.try_into()?, + }; + + Ok(BeaconState::Fulu(post)) +} + +/// Applies the fork upgrade that produces `to`'s state shape from `state`. +/// +/// Dispatches over the per-fork upgrade functions by [`ForkName`] so a caller +/// that only knows the target fork as a name, such as `process_slots` +/// crossing a fork boundary mid-loop, does not have to match on it itself. +/// +/// Rejects any `to` whose upgrade does not apply to `state`'s current shape, +/// which covers both ways a caller could misuse this: skipping a fork (asking +/// for capella's shape from a still-altair state, say) and going backwards +/// (asking for bellatrix's shape from a state already past it). Neither needs +/// a check here: every `upgrade_to_` function already requires its +/// specific predecessor's shape (via its own fork-state projection), so a +/// mismatched `to` fails inside whichever function this dispatches to, with +/// the same [`Error::UnsupportedForFork`] any other fork-mismatched call in +/// this module produces. +pub fn upgrade_state(state: &BeaconState, to: ForkName, config: &Config) -> Result { + match to { + ForkName::Phase0 => Err(Error::UnsupportedForFork { + function: "upgrade_state", + fork: to, + }), + ForkName::Altair => { + let pre = crate::beacon::stf::phase0_state_ref(state, "upgrade_state")?; + Ok(BeaconState::Altair(upgrade_to_altair(pre, config)?)) + } + ForkName::Bellatrix => upgrade_to_bellatrix(state, config), + ForkName::Capella => upgrade_to_capella(state, config), + ForkName::Deneb => upgrade_to_deneb(state, config), + ForkName::Electra => upgrade_to_electra(state, config), + ForkName::Fulu => upgrade_to_fulu(state, config), + // The `fork:` form, not `state:`: this dispatches on the requested + // target, so it is the argument that is wrong, not what `state` holds. + ForkName::Lean => lean_fork_unreachable("upgrade_state"), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Extracts the phase0 state `with_validators` builds, for tests that need + /// the concrete struct `upgrade_to_altair` takes rather than the enum. + fn phase0_test_state(count: usize) -> phase0::BeaconState { + match crate::beacon::helpers::test_state::with_validators(count) { + BeaconState::Phase0(state) => state, + _ => panic!("with_validators returns a phase0 state"), + } + } + + #[test] + fn previous_version_carries_the_pre_states_current_version() { + let mut pre = phase0_test_state(4); + // `with_validators` leaves `fork` at its all-zero default, which would + // make `previous_version == current_version` trivially true even if + // the upgrade forgot to read `pre` at all. A distinct sentinel value + // rules that out. + pre.fork.current_version = [9, 9, 9, 9]; + + let config = Config::mainnet(); + let post = upgrade_to_altair(&pre, &config).expect("upgrade succeeds"); + + assert_eq!(post.fork.previous_version, [9, 9, 9, 9]); + assert_eq!(post.fork.current_version, config.altair_fork_version); + } + + #[test] + fn participation_and_inactivity_lists_have_one_entry_per_validator() { + let pre = phase0_test_state(7); + let config = Config::mainnet(); + + let post = upgrade_to_altair(&pre, &config).expect("upgrade succeeds"); + + assert_eq!( + post.previous_epoch_participation.len(), + pre.validators.len() + ); + assert_eq!(post.current_epoch_participation.len(), pre.validators.len()); + assert_eq!(post.inactivity_scores.len(), pre.validators.len()); + } + + /// Advances a fresh phase0 test state through every upgrade up to and + /// including `to`, via [`upgrade_state`] itself. + /// + /// Chaining the real upgrade functions rather than hand-writing a struct + /// literal for each fork keeps every fixture below a state some upgrade + /// function in this file actually produced, which is exactly the kind of + /// input the function under test in each case below is checked against. + fn advance_to(to: ForkName, count: usize) -> (BeaconState, Config) { + let config = Config::mainnet(); + let mut state = crate::beacon::helpers::test_state::with_validators(count); + for fork in ForkName::ALL.into_iter().skip(1) { + state = upgrade_state(&state, fork, &config).expect("upgrade succeeds"); + if fork == to { + break; + } + } + (state, config) + } + + #[test] + fn bellatrix_carries_altairs_fields_and_starts_an_empty_payload_header() { + let (altair_state, config) = advance_to(ForkName::Altair, 4); + let BeaconState::Altair(altair_state) = altair_state else { + panic!("advance_to(Altair) returns an altair state"); + }; + + let post = upgrade_to_bellatrix(&BeaconState::Altair(altair_state.clone()), &config) + .expect("upgrade succeeds"); + let BeaconState::Bellatrix(post) = post else { + panic!("upgrade_to_bellatrix returns a bellatrix state"); + }; + + assert_eq!( + post.fork.previous_version, + altair_state.fork.current_version + ); + assert_eq!(post.fork.current_version, config.bellatrix_fork_version); + assert_eq!(post.validators.len(), altair_state.validators.len()); + assert_eq!(post.genesis_time, altair_state.genesis_time); + assert_eq!(post.latest_execution_payload_header.block_number, 0); + assert!(post.latest_execution_payload_header.block_hash.is_zero()); + } + + #[test] + fn bellatrix_rejects_a_state_that_skipped_altair() { + let phase0_state = crate::beacon::helpers::test_state::with_validators(4); + let config = Config::mainnet(); + assert!(upgrade_to_bellatrix(&phase0_state, &config).is_err()); + } + + #[test] + fn capella_carries_the_execution_header_across_and_leaves_historical_roots_alone() { + let (bellatrix_state, config) = advance_to(ForkName::Bellatrix, 4); + let BeaconState::Bellatrix(mut bellatrix_state) = bellatrix_state else { + panic!("advance_to(Bellatrix) returns a bellatrix state"); + }; + // A field genuinely carried across, distinguishable from the header's + // otherwise all-zero starting value. + bellatrix_state.latest_execution_payload_header.block_number = 42; + bellatrix_state + .historical_roots + .push(crate::beacon::primitives::Root::repeat_byte(7)) + .expect("well below HISTORICAL_ROOTS_LIMIT"); + + let post = upgrade_to_capella(&BeaconState::Bellatrix(bellatrix_state.clone()), &config) + .expect("upgrade succeeds"); + let BeaconState::Capella(post) = post else { + panic!("upgrade_to_capella returns a capella state"); + }; + + assert_eq!(post.fork.current_version, config.capella_fork_version); + assert_eq!(post.latest_execution_payload_header.block_number, 42); + assert!( + post.latest_execution_payload_header + .withdrawals_root + .is_zero() + ); + // Left alone, not truncated: capella freezes `historical_roots` in + // place rather than clearing it, since `historical_summaries` is + // where new history accumulates from here on. + assert_eq!( + post.historical_roots.into_inner(), + bellatrix_state.historical_roots.into_inner() + ); + assert_eq!(post.next_withdrawal_index, 0); + assert_eq!(post.next_withdrawal_validator_index, 0); + assert!(post.historical_summaries.is_empty()); + } + + #[test] + fn capella_rejects_a_state_that_skipped_bellatrix() { + let (altair_state, config) = advance_to(ForkName::Altair, 4); + assert!(upgrade_to_capella(&altair_state, &config).is_err()); + } + + #[test] + fn deneb_gains_blob_gas_fields_at_zero_and_carries_withdrawals_root() { + let (capella_state, config) = advance_to(ForkName::Capella, 4); + let BeaconState::Capella(mut capella_state) = capella_state else { + panic!("advance_to(Capella) returns a capella state"); + }; + capella_state + .latest_execution_payload_header + .withdrawals_root = crate::beacon::primitives::Root::repeat_byte(3); + capella_state.next_withdrawal_index = 5; + + let post = upgrade_to_deneb(&BeaconState::Capella(capella_state.clone()), &config) + .expect("upgrade succeeds"); + let BeaconState::Deneb(post) = post else { + panic!("upgrade_to_deneb returns a deneb state"); + }; + + assert_eq!(post.fork.current_version, config.deneb_fork_version); + assert_eq!(post.latest_execution_payload_header.blob_gas_used, 0); + assert_eq!(post.latest_execution_payload_header.excess_blob_gas, 0); + assert_eq!( + post.latest_execution_payload_header.withdrawals_root, + capella_state + .latest_execution_payload_header + .withdrawals_root + ); + // The state's own field count does not change at this fork: only + // `latest_execution_payload_header`'s shape does. + assert_eq!( + post.next_withdrawal_index, + capella_state.next_withdrawal_index + ); + } + + #[test] + fn deneb_rejects_a_state_that_skipped_capella() { + let (bellatrix_state, config) = advance_to(ForkName::Bellatrix, 4); + assert!(upgrade_to_deneb(&bellatrix_state, &config).is_err()); + } + + #[test] + fn upgrade_state_rejects_phase0_as_a_target() { + let phase0_state = crate::beacon::helpers::test_state::with_validators(4); + let config = Config::mainnet(); + assert!(upgrade_state(&phase0_state, ForkName::Phase0, &config).is_err()); + } + + #[test] + fn upgrade_state_rejects_going_backwards() { + let (deneb_state, config) = advance_to(ForkName::Deneb, 4); + // `deneb_state` is already past bellatrix; asking to upgrade it *to* + // bellatrix is a backwards move, and must fail the same way skipping + // a fork does. + assert!(upgrade_state(&deneb_state, ForkName::Bellatrix, &config).is_err()); + } + + #[test] + fn electra_sets_the_fork_version_and_deposit_requests_sentinel() { + let (deneb_state, config) = advance_to(ForkName::Deneb, 4); + let post = upgrade_to_electra(&deneb_state, &config).expect("upgrade succeeds"); + let BeaconState::Electra(post) = post else { + panic!("upgrade_to_electra returns an electra state"); + }; + + assert_eq!(post.fork.current_version, config.electra_fork_version); + assert_eq!( + post.deposit_requests_start_index, + constants::UNSET_DEPOSIT_REQUESTS_START_INDEX + ); + // Never overwritten by this upgrade; see its own doc. + assert_eq!(post.deposit_balance_to_consume, 0); + } + + #[test] + fn electra_earliest_exit_epoch_tracks_the_largest_pending_exit() { + let (deneb_state, config) = advance_to(ForkName::Deneb, 4); + let BeaconState::Deneb(mut deneb_state) = deneb_state else { + panic!("advance_to(Deneb) returns a deneb state"); + }; + let epoch = compute_epoch_at_slot(deneb_state.slot); + let default_earliest_exit_epoch = compute_activation_exit_epoch(epoch); + // Comfortably past the default, so the scan over `pre.validators` + // below is what has to produce this value, not the epoch-only + // fallback every other validator would leave it at. + let sentinel_exit_epoch = default_earliest_exit_epoch + 100; + deneb_state.validators[0].exit_epoch = sentinel_exit_epoch; + + let post = upgrade_to_electra(&BeaconState::Deneb(deneb_state), &config) + .expect("upgrade succeeds"); + let BeaconState::Electra(post) = post else { + panic!("upgrade_to_electra returns an electra state"); + }; + + assert_eq!(post.earliest_exit_epoch, sentinel_exit_epoch + 1); + } + + #[test] + fn electra_migrates_a_not_yet_active_validator_into_pending_deposits() { + let (deneb_state, config) = advance_to(ForkName::Deneb, 4); + let BeaconState::Deneb(mut deneb_state) = deneb_state else { + panic!("advance_to(Deneb) returns a deneb state"); + }; + let migrated_pubkey = deneb_state.validators[0].pubkey; + let migrated_credentials = deneb_state.validators[0].withdrawal_credentials; + deneb_state.validators[0].activation_epoch = constants::FAR_FUTURE_EPOCH; + deneb_state.balances[0] = 1_000_000_000; + + let post = upgrade_to_electra(&BeaconState::Deneb(deneb_state), &config) + .expect("upgrade succeeds"); + let BeaconState::Electra(post) = post else { + panic!("upgrade_to_electra returns an electra state"); + }; + + assert_eq!(post.balances[0], 0); + assert_eq!(post.validators[0].effective_balance, 0); + assert_eq!( + post.validators[0].activation_eligibility_epoch, + constants::FAR_FUTURE_EPOCH + ); + assert_eq!(post.pending_deposits.len(), 1); + let deposit = &post.pending_deposits[0]; + assert_eq!(deposit.amount, 1_000_000_000); + assert_eq!(deposit.pubkey, migrated_pubkey); + assert_eq!(deposit.withdrawal_credentials, migrated_credentials); + } + + #[test] + fn electra_churn_fields_are_populated_from_the_post_state() { + let (deneb_state, config) = advance_to(ForkName::Deneb, 4); + let post = upgrade_to_electra(&deneb_state, &config).expect("upgrade succeeds"); + let BeaconState::Electra(electra_post) = &post else { + panic!("upgrade_to_electra returns an electra state"); + }; + + // None of `advance_to`'s validators are pre-activation or + // compounding, so both migrations below ran as no-ops and total + // active balance is unchanged from the moment churn was computed: + // recomputing the churn limits against the finished state must + // reproduce exactly what `upgrade_to_electra` already stored, which + // is what proves the two calls were actually wired in rather than + // leaving the fields at their zero placeholder. + let expected_exit_churn = + crate::beacon::helpers::electra::get_activation_exit_churn_limit(&post, &config) + .unwrap(); + let expected_consolidation_churn = + crate::beacon::helpers::electra::get_consolidation_churn_limit(&post, &config).unwrap(); + + assert_eq!(electra_post.exit_balance_to_consume, expected_exit_churn); + assert_eq!( + electra_post.consolidation_balance_to_consume, + expected_consolidation_churn + ); + assert!(expected_exit_churn > 0); + } + + #[test] + fn electra_rejects_a_state_that_skipped_deneb() { + let (capella_state, config) = advance_to(ForkName::Capella, 4); + assert!(upgrade_to_electra(&capella_state, &config).is_err()); + } + + #[test] + fn fulu_proposer_lookahead_matches_initialize_proposer_lookahead() { + let (electra_state, config) = advance_to(ForkName::Electra, 4); + let post = upgrade_to_fulu(&electra_state, &config).expect("upgrade succeeds"); + let BeaconState::Fulu(post) = post else { + panic!("upgrade_to_fulu returns a fulu state"); + }; + + let expected = crate::beacon::helpers::fulu::initialize_proposer_lookahead(&electra_state) + .expect("initialize_proposer_lookahead succeeds"); + assert_eq!(post.proposer_lookahead.into_inner(), expected); + assert_eq!(post.fork.current_version, config.fulu_fork_version); + } + + #[test] + fn fulu_rejects_a_state_that_skipped_electra() { + let (deneb_state, config) = advance_to(ForkName::Deneb, 4); + assert!(upgrade_to_fulu(&deneb_state, &config).is_err()); + } + + #[test] + fn upgrade_state_walks_every_fork_boundary_end_to_end() { + // A cheap integration check on top of the per-function tests above: + // `advance_to` already exercises every arm of `upgrade_state`, so + // reaching fulu without an error proves the whole dispatch chain + // (not just each function in isolation) is wired correctly. + let (fulu_state, _config) = advance_to(ForkName::Fulu, 4); + assert_eq!(fulu_state.fork_name(), ForkName::Fulu); + } +} diff --git a/crates/blockchain/state_transition/src/lib.rs b/crates/blockchain/state_transition/src/lib.rs index d03f74b23..a8792d430 100644 --- a/crates/blockchain/state_transition/src/lib.rs +++ b/crates/blockchain/state_transition/src/lib.rs @@ -10,6 +10,15 @@ use ethlambda_types::{ }; use tracing::{info, warn}; +/// The Ethereum **Beacon Chain** state transition, phase0 through fulu. +/// +/// A different protocol from the Lean consensus the rest of this crate +/// implements, kept in its own namespace for the same reason +/// `ethlambda_types::beacon` is: one crate can then hold both chains' rules, so +/// a caller dispatching on a state's fork reaches either without the two living +/// in separate dependency trees. Nothing above `beacon` here reads anything +/// inside it, and nothing inside it reads lean's own module tree. +pub mod beacon; pub mod justified_slots_ops; pub mod metrics; diff --git a/crates/blockchain/state_transition/tests/beacon_spec/bls.rs b/crates/blockchain/state_transition/tests/beacon_spec/bls.rs new file mode 100644 index 000000000..df6371240 --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/bls.rs @@ -0,0 +1,175 @@ +//! The `bls` runner. +//! +//! Covers the two BLS handlers the release ships: `eth_aggregate_pubkeys` +//! (summing a list of public keys into one) and `eth_fast_aggregate_verify` +//! (verifying an aggregate signature against a shared message, with the eth2 +//! empty-committee carve-out). Both live in `crates/blockchain/state_transition/src/beacon/bls.rs`; see +//! that module's own doc for why they return the shapes they do +//! (`crate::Result` for aggregation, plain `bool` for verification). +//! +//! # Why `general`, not a preset +//! +//! Every other runner in this harness picks its fixture tree by [`super::PRESET`], +//! because the functions it exercises read a preset constant somewhere in their +//! call graph (committee sizes, epoch lengths, and so on). Neither BLS handler +//! does: aggregating public keys and checking a pairing equation are BLS12-381 +//! operations with no notion of a validator count or a slots-per-epoch. The +//! release ships exactly one copy of these fixtures, under `general`, rather +//! than one per preset, which is what `general` signals across this whole +//! fixture tree (see `crates/blockchain/state_transition/tests/beacon_spec/mod.rs`'s module doc): a suite +//! that does not vary with the compiled-in preset. +//! +//! # What `output: null` means +//! +//! `eth_aggregate_pubkeys` can fail: the specification asserts `len(pubkeys) > 0` +//! and that every key passes `KeyValidate` before summing, and a fixture case +//! whose `output` is `null` is exactly one of those assertions firing (an empty +//! list, the all-zero encoding, a malformed compression flag, or the point at +//! infinity, which fails `KeyValidate`'s non-identity check). That is the same +//! contract [`super::check_transition`] enforces for a case with no `post` +//! state: absence of the success value is the expectation, not a gap in the +//! fixture, so a run that returns `Ok` for such a case is exactly as wrong as +//! one that returns the wrong pubkey. `eth_fast_aggregate_verify` has no such +//! case: it returns a plain `bool` because the specification gives it no failure +//! mode distinct from "the check did not pass", so every fixture under that +//! handler ships a `true` or `false`, never a `null`. + +use ethlambda_state_transition::beacon::bls; +use ethlambda_state_transition::beacon::primitives::{ + BLS_PUBKEY_SIZE, BlsPubkey, BlsSignature, Root, +}; +use libtest_mimic::Trial; + +/// `eth_aggregate_pubkeys///data.yaml`'s shape: a list of hex +/// pubkeys in, one hex pubkey out, or `null` when the input must be rejected. +#[derive(serde::Deserialize)] +struct AggregatePubkeysCase { + input: Vec, + output: Option, +} + +/// `eth_fast_aggregate_verify///data.yaml`'s `input` key: the +/// pubkeys and message the signature is checked against. +#[derive(serde::Deserialize)] +struct FastAggregateVerifyInput { + pubkeys: Vec, + message: String, + signature: String, +} + +/// `eth_fast_aggregate_verify///data.yaml`'s shape. `output` is +/// always a plain bool; see the module doc for why this handler has no `null` +/// case the way `eth_aggregate_pubkeys` does. +#[derive(serde::Deserialize)] +struct FastAggregateVerifyCase { + input: FastAggregateVerifyInput, + output: bool, +} + +/// Decodes a `0x`-prefixed hex string into raw bytes. +fn decode_hex(value: &str) -> Result, String> { + let digits = value.strip_prefix("0x").unwrap_or(value); + hex::decode(digits).map_err(|err| format!("invalid hex `{value}`: {err}")) +} + +/// Decodes a `0x`-prefixed hex string into an exact-size byte array. +/// +/// Every fixed-length value these fixtures carry (pubkeys, signatures) has a +/// named size in [`ethlambda_state_transition::beacon::primitives`], so a mismatch is a fixture +/// bug worth reporting through the case's own failure message rather than +/// panicking the whole run on it. +fn parse_hex(value: &str) -> Result<[u8; N], String> { + decode_hex(value)? + .try_into() + .map_err(|bytes: Vec| format!("expected {N} bytes, got {} in `{value}`", bytes.len())) +} + +/// Runs one `eth_aggregate_pubkeys` case. +fn eth_aggregate_pubkeys_case(case: &super::Case) -> Result<(), String> { + let fixture: AggregatePubkeysCase = case.yaml("data"); + + let mut pubkeys = Vec::with_capacity(fixture.input.len()); + for hex in &fixture.input { + pubkeys.push(BlsPubkey(parse_hex(hex)?)); + } + + let result = bls::eth_aggregate_pubkeys(&pubkeys); + + match fixture.output { + // A hex pubkey: aggregation must succeed and land exactly on it. + Some(expected_hex) => { + let expected: [u8; BLS_PUBKEY_SIZE] = parse_hex(&expected_hex)?; + let actual = result.map_err(|err| format!("expected Ok(pubkey), got Err({err})"))?; + if actual.0 != expected { + return Err(format!( + "aggregated to 0x{}, expected 0x{}", + hex::encode(actual.0), + hex::encode(expected) + )); + } + Ok(()) + } + // `output: null`: one of the spec's own assertions must have rejected + // this input (see the module doc). Accepting it here would mean the + // implementation is looser than the spec, not that the fixture allows + // it either way. + None => { + if result.is_ok() { + return Err( + "accepted, but the fixture's output is null, so it must be rejected" + .to_string(), + ); + } + Ok(()) + } + } +} + +/// Runs one `eth_fast_aggregate_verify` case. +fn eth_fast_aggregate_verify_case(case: &super::Case) -> Result<(), String> { + let fixture: FastAggregateVerifyCase = case.yaml("data"); + + let mut pubkeys = Vec::with_capacity(fixture.input.pubkeys.len()); + for hex in &fixture.input.pubkeys { + pubkeys.push(BlsPubkey(parse_hex(hex)?)); + } + // `Root` (an alias of `H256`) has no fixed-size-array constructor of its + // own to call through the alias, so this goes through `from_slice` + // instead, matching how the rest of this harness turns a hex root into + // one (see `shuffling.rs`). + let message = Root::from_slice(&decode_hex(&fixture.input.message)?); + let signature = BlsSignature(parse_hex(&fixture.input.signature)?); + + let actual = bls::eth_fast_aggregate_verify(&pubkeys, message, &signature); + if actual != fixture.output { + return Err(format!( + "eth_fast_aggregate_verify returned {actual}, expected {}", + fixture.output + )); + } + Ok(()) +} + +/// This suite is not gated here: [`super::case_trial`] applies +/// [`super::Case::in_scope`]'s gate itself, and every case this handler +/// collects lands under altair, which is always in scope, so nothing here +/// needs to check the fork. +pub fn trials() -> Vec { + let cases = super::collect_all_handlers("general", "bls"); + let mut trials = vec![super::discovery_trial("bls", cases.len())]; + + for (handler, case) in cases { + trials.push(super::case_trial("bls", case, move |case| { + match handler.as_str() { + "eth_aggregate_pubkeys" => eth_aggregate_pubkeys_case(case), + "eth_fast_aggregate_verify" => eth_fast_aggregate_verify_case(case), + // A release that adds a handler must fail loudly here rather + // than silently matching zero cases, the same rule + // `epoch_processing`'s own dispatch follows. + other => Err(format!("unhandled bls handler `{other}`")), + } + })); + } + + trials +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec/epoch_processing.rs b/crates/blockchain/state_transition/tests/beacon_spec/epoch_processing.rs new file mode 100644 index 000000000..2df06c9b8 --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/epoch_processing.rs @@ -0,0 +1,236 @@ +//! The `epoch_processing` runner. +//! +//! Each handler names one step of epoch processing and each case runs that step +//! alone against a `pre` state. Testing the steps in isolation is what makes a +//! failure here diagnostic: the `sanity` and `finality` suites run whole blocks, +//! so a wrong rounding in one step surfaces there as an opaque state root +//! mismatch, while here it names the step. +//! +//! Altair keeps most of phase0's steps unchanged (`registry_updates`, +//! `slashings`, and the four resets, plus `historical_roots_update`, which does +//! not become `historical_summaries_update` until capella) and replaces two +//! outright: `justification_and_finalization` now reads participation flags +//! instead of replaying `PendingAttestation`s, and `rewards_and_penalties` scores +//! those same flags instead of the five phase0 delta components. It also adds +//! three steps of its own (`inactivity_updates`, `participation_flag_updates`, +//! `sync_committee_updates`) that have no phase0 handler at all, so [`apply`] +//! matches on `(handler, fork)` rather than on the handler name alone wherever a +//! handler's function actually differs between the two. +//! +//! Later forks split further along that same `(handler, fork)` axis, and each +//! boundary below is transcribed from `beacon-chain.md`'s own "Modified in +//! " markers rather than assumed: +//! +//! - `registry_updates`: deneb's own change (EIP-7514's activation-churn cap) +//! is selected internally, by fork, inside `registry::process_registry_updates` +//! itself, so phase0 through deneb still share one call here. Electra +//! rewrites the function outright around a balance budget instead of a +//! per-epoch headcount, and fulu never revives the older rule, so both route +//! to electra's version instead. +//! - `effective_balance_updates`: phase0 through deneb round every validator +//! toward the one ceiling every validator shared before EIP-7251. Electra's +//! version reads a per-validator ceiling instead, since a compounding +//! validator's can be far higher, and fulu never reverts that, so both route +//! to electra's version too. +//! - `historical_roots_update` becomes `historical_summaries_update`, a +//! different handler name rather than a different fork's version of this +//! one, starting at capella. +//! - Electra adds `pending_deposits` and `pending_consolidations`, with no +//! earlier-fork counterpart at all; fulu carries both forward unchanged and +//! adds `proposer_lookahead` of its own, likewise with no earlier-fork +//! counterpart. + +use std::sync::Arc; + +use ethlambda_state_transition::beacon::ForkName; +use ethlambda_state_transition::beacon::config::Config; +use ethlambda_state_transition::beacon::containers::BeaconState; +use ethlambda_state_transition::beacon::stf::epoch; +use libtest_mimic::{Failed, Trial}; + +use super::{Case, PRESET, collect_all_handlers}; + +/// Runs the single epoch-processing step the handler names. +fn apply( + handler: &str, + fork: ForkName, + state: &mut BeaconState, + config: &Config, +) -> Result<(), String> { + let outcome = match handler { + // `epoch::process_justification_and_finalization` dispatches on + // `state.fork_name()` itself, unlike `rewards_and_penalties` below, + // which has no such wrapper yet: calling it here rather than reaching + // into `epoch::justification` (phase0-only) or `epoch::altair` + // directly is what keeps this arm correct as later forks add their + // own justification changes, with no edit needed here when they do. + "justification_and_finalization" => { + epoch::process_justification_and_finalization(state, config) + } + // Altair rewrites this to score participation flags instead of + // replaying `PendingAttestation`s. No later fork's `beacon-chain.md` + // touches it again: bellatrix, capella, deneb, electra, and fulu each + // call it straight through as part of reusing altair's larger driver + // (see each fork module's own doc), so altair's version serves + // everything from altair on, the same boundary + // `process_justification_and_finalization` above already encodes for + // its own step. + "rewards_and_penalties" => match fork { + ForkName::Phase0 => epoch::rewards::process_rewards_and_penalties(state, config), + _ => epoch::altair::process_rewards_and_penalties(state, config), + }, + // Deneb's own change (EIP-7514's activation-churn cap) is selected + // internally, by fork, inside `process_registry_updates` itself, so + // phase0 through deneb share one call here. Electra replaces the + // function outright with a balance-budget version, and fulu never + // revives the validator-count rule after that, so both route to + // electra's instead: the shared function refuses to run for either on + // purpose (`Error::UnsupportedForFork`), rather than silently applying + // deneb's superseded rule, so routing them here would fail loudly, not + // incorrectly. + "registry_updates" => match fork { + ForkName::Electra | ForkName::Fulu => { + epoch::electra::process_registry_updates(state, config) + } + _ => epoch::registry::process_registry_updates(state, config), + }, + // Altair's and bellatrix's own changes here are scoped to the + // proportional multiplier `registry::process_slashings` already selects + // by fork through `preset::retuned`, so one copy serves them. Electra is + // different: it restructures the division itself, dividing the adjusted + // slashing balance by the increment count once and multiplying per + // validator, rather than dividing by the total balance per validator and + // multiplying by the increment at the end. Those disagree under integer + // rounding, so electra and fulu need their own function, not just their + // own constant. + "slashings" => match fork { + ForkName::Electra | ForkName::Fulu => epoch::electra::process_slashings(state, config), + _ => epoch::registry::process_slashings(state, config), + }, + "eth1_data_reset" => epoch::process_eth1_data_reset(state), + // Phase0 through deneb round each validator toward the single ceiling + // every validator shared before EIP-7251. Electra's version instead + // reads a per-validator ceiling (`get_max_effective_balance`), since a + // compounding validator's can be far higher, and fulu never reverts + // that, so both route to electra's. + "effective_balance_updates" => match fork { + ForkName::Electra | ForkName::Fulu => { + epoch::electra::process_effective_balance_updates(state) + } + _ => epoch::process_effective_balance_updates(state), + }, + "slashings_reset" => epoch::process_slashings_reset(state), + "randao_mixes_reset" => epoch::process_randao_mixes_reset(state), + // Still `historical_roots_update` through bellatrix; the specification + // renames this to `historical_summaries_update` starting at capella, + // which is a different handler name, not a different fork's version + // of this one. + "historical_roots_update" => epoch::process_historical_roots_update(state), + // New in capella, replacing `historical_roots_update` above, and + // carried unchanged through every later fork: `historical_summaries_mut` + // itself accepts capella, deneb, electra, and fulu states alike (see + // its own doc for why), so one call here serves all four. + "historical_summaries_update" => epoch::capella::process_historical_summaries_update(state), + // Phase0 only: altair replaces the backlog this replays with + // participation flags, which have no epoch-end "roll the backlog + // over" step of their own to speak of here (see + // `participation_flag_updates` below). + "participation_record_updates" => epoch::process_participation_record_updates(state), + // New in altair; no phase0 case ever reaches these, and no later + // fork's own `process_epoch` redefines any of the three (each calls + // straight through to `epoch::altair`, per its own module doc), so one + // call per handler serves every fork that has it. + "inactivity_updates" => epoch::altair::process_inactivity_updates(state, config), + "participation_flag_updates" => epoch::altair::process_participation_flag_updates(state), + "sync_committee_updates" => epoch::altair::process_sync_committee_updates(state), + // New in electra (EIP-7251); fulu carries both pending queues forward + // unchanged, calling the very same functions (see + // `electra::process_epoch`'s own doc for why fulu's driver needs no + // rewrite of either). + "pending_deposits" => epoch::electra::process_pending_deposits(state, config), + "pending_consolidations" => epoch::electra::process_pending_consolidations(state, config), + // New in fulu (EIP-7917); no earlier fork has this handler at all. + "proposer_lookahead" => epoch::fulu::process_proposer_lookahead(state), + other => return Err(format!("unhandled epoch step `{other}`")), + }; + + outcome.map_err(|err| format!("{err:?}")) +} + +pub fn trials() -> Vec { + let config = Arc::new(Config::active()); + let cases = collect_all_handlers(PRESET, "epoch_processing"); + let mut trials = vec![super::discovery_trial("epoch_processing", cases.len())]; + + for (handler, case) in cases { + let config = Arc::clone(&config); + trials.push(super::case_trial("epoch_processing", case, move |case| { + let mut state = BeaconState::from_ssz(case.fork, &case.ssz_bytes("pre")) + .map_err(|err| format!("the fixture's pre-state does not decode: {err:?}"))?; + + let outcome = apply(&handler, case.fork, &mut state, &config); + super::check_transition(case, outcome, &state) + })); + } + + trials.push(every_shipped_handler_is_dispatched()); + + trials +} + +/// Builds the trial checking that every handler the fixture release ships is +/// dispatched by [`apply`]. +/// +/// A missing arm in `apply` would otherwise be reported per case as a failure, +/// which is correct but noisy. This checks the set of handlers is the one the +/// runner knows about, so a fixture release that adds a step fails here, once, +/// with a clear message. The list is flat across forks (it does not say which +/// handler belongs to which fork) because that is exactly what [`apply`]'s +/// `(handler, fork)` match already encodes and enforces at run time; duplicating +/// it here would only give the two a chance to drift apart. +/// +/// Built with [`Trial::test`] directly rather than [`super::case_trial`], +/// since it checks the whole handler set rather than one fixture case. +fn every_shipped_handler_is_dispatched() -> Trial { + Trial::test( + "epoch_processing/every_shipped_handler_is_dispatched", + || { + let known = [ + "justification_and_finalization", + "rewards_and_penalties", + "registry_updates", + "slashings", + "eth1_data_reset", + "effective_balance_updates", + "slashings_reset", + "randao_mixes_reset", + "historical_roots_update", + "historical_summaries_update", + "participation_record_updates", + "inactivity_updates", + "participation_flag_updates", + "sync_committee_updates", + "pending_deposits", + "pending_consolidations", + "proposer_lookahead", + ]; + + let mut unknown: Vec = collect_all_handlers(PRESET, "epoch_processing") + .into_iter() + .filter(|(_, case): &(String, Case)| case.in_scope()) + .map(|(handler, _)| handler) + .filter(|handler| !known.contains(&handler.as_str())) + .collect(); + unknown.sort_unstable(); + unknown.dedup(); + + if !unknown.is_empty() { + return Err(Failed::from(format!( + "the fixture release ships epoch steps this runner does not dispatch: {unknown:?}" + ))); + } + + Ok(()) + }, + ) +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec/fork.rs b/crates/blockchain/state_transition/tests/beacon_spec/fork.rs new file mode 100644 index 000000000..7a51b7311 --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/fork.rs @@ -0,0 +1,92 @@ +//! The `fork` runner, handler `fork`. +//! +//! Each case ships a `pre` state in the *previous* fork's shape and a `post` +//! state in the *new* fork's shape, with no block: the case is purely a check +//! of the irregular state change itself. `case.fork` names the target fork +//! (the directory this crate's harness walks is `tests///...`, +//! where `` is the one the case upgrades *to*), matching every case's +//! `meta.yaml`, which carries the same name under its own `fork` key. The +//! source fork is not carried anywhere in the fixture beyond that: it is +//! always `ForkName::previous` of the target, since every upgrade in the +//! specification is defined from the one fork immediately before it. +//! +//! Gated on [`super::HIGHEST_IMPLEMENTED_FORK`] like every other runner, so +//! cases whose target this crate does not implement yet are counted as +//! skipped rather than silently dropped, the way `ssz_static` counts +//! container/fork pairs it does not decode. [`super::HIGHEST_IMPLEMENTED_FORK`] +//! is now fulu, and [`ethlambda_state_transition::beacon::upgrade::upgrade_state`] routes every +//! fork through its own `upgrade_to_*` function, so the two agree by +//! construction all the way to fulu; the two are still checking different +//! things, though: this gate is "has this crate's state transition caught up +//! to this fork at all," which is deliberately conservative, since running a +//! fork's upgrade before its state transition exists would let this suite go +//! green on a fork nothing else here can actually process yet. +//! +//! This exercises [`ethlambda_state_transition::beacon::upgrade::upgrade_state`] rather than each +//! fork's own `upgrade_to_*` function directly, so the dispatch by +//! `ForkName` gets fixture coverage too, not just the per-fork function it +//! delegates to. That is also what makes picking up a later fork here a +//! one-line change once its own `upgrade_to_*` lands: `upgrade_state` already +//! routes to it by name, so once [`super::HIGHEST_IMPLEMENTED_FORK`] moves +//! past this fork, [`fork_case`] finds its `pre` and `post` shapes on its own. + +use std::sync::Arc; + +use ethlambda_state_transition::beacon::config::Config; +use ethlambda_state_transition::beacon::containers::BeaconState; +use ethlambda_state_transition::beacon::upgrade::upgrade_state; +use libtest_mimic::Trial; + +use super::{Case, PRESET, collect}; + +/// Runs one case: decode `pre` in the source fork's shape, upgrade it, and +/// compare against `post` by `hash_tree_root`. +/// +/// Does not go through `super::check_transition`: that helper assumes the +/// post-state has the same fork as the pre-state, which is exactly what a +/// fork-upgrade case never does, so it is reimplemented here without the +/// `has("post")` branch that a rejection-capable runner needs. Every case in +/// this handler ships a `post`; none of the specification's `upgrade_to_*` +/// functions have an assertion that can fail on a wellformed pre-state, so +/// there is no rejection case to model. +fn fork_case(case: &Case, config: &Config) -> Result<(), String> { + let source = case + .fork + .previous() + .ok_or_else(|| format!("fork `{}` has no previous fork to upgrade from", case.fork))?; + let pre = BeaconState::from_ssz(source, &case.ssz_bytes("pre")) + .map_err(|err| format!("decoding the fixture's pre-state: {err:?}"))?; + + let actual = + upgrade_state(&pre, case.fork, config).map_err(|err| format!("upgrade_state: {err}"))?; + + let expected = BeaconState::from_ssz(case.fork, &case.ssz_bytes("post")) + .map_err(|err| format!("decoding the fixture's post-state: {err:?}"))?; + + let actual_root = actual.hash_tree_root(); + let expected_root = expected.hash_tree_root(); + if actual_root != expected_root { + return Err(format!( + "post-state root 0x{} != expected 0x{}", + hex::encode(actual_root.0), + hex::encode(expected_root.0) + )); + } + + Ok(()) +} + +pub fn trials() -> Vec { + let config = Arc::new(Config::active()); + let cases = collect(PRESET, "fork", "fork"); + let mut trials = vec![super::discovery_trial("fork", cases.len())]; + + for case in cases { + let config = Arc::clone(&config); + trials.push(super::case_trial("fork", case, move |case| { + fork_case(case, &config) + })); + } + + trials +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec/fork_choice.rs b/crates/blockchain/state_transition/tests/beacon_spec/fork_choice.rs new file mode 100644 index 000000000..52f689934 --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/fork_choice.rs @@ -0,0 +1,861 @@ +//! The `fork_choice` runner. +//! +//! Exercises `specs/phase0/fork-choice.md` end to end, plus every later +//! fork's modifications to it. Each case builds a [`Store`] from an anchor +//! state and block via [`fork_choice::get_forkchoice_store`], then replays +//! `steps.yaml` in order. A step is one of `tick`, `block`, `attestation`, +//! `attester_slashing`, or `on_merge_block` (bellatrix's own `pow_block` +//! step), driving the correspondingly named handler, or `checks`, which +//! asserts on the store's own fields and on [`fork_choice::get_head`], +//! [`fork_choice::get_proposer_head`], and +//! [`fork_choice::should_override_forkchoice_update`]. See +//! `tests/formats/fork_choice/README.md` in the pinned specification checkout +//! for the format in full. +//! +//! No released fixture targets phase0 directly: the earliest suite is +//! altair's, built from altair-shaped states because the generator needs a +//! later fork's containers even though altair changes nothing about fork +//! choice itself. This runner is gated on [`HIGHEST_IMPLEMENTED_FORK`] like +//! every other, so it picks up a phase0 suite automatically should a future +//! release add one, and a later fork's automatically once this crate catches +//! up to it. +//! +//! # A step's `valid: false` means the call must be rejected +//! +//! Matching [`super::check_transition`]'s rule for a missing `post` state, +//! `valid: false` on a `block`, `attestation`, or `attester_slashing` step +//! means the handler must return an error, and the store must be left exactly +//! as it was; treating a should-fail call that happens to succeed as a pass +//! would let this suite go green while checking nothing. `on_tick` cannot +//! fail in this crate, nor in the specification (it has no assertion to +//! fail), so a `tick` step asking for rejection is reported as a failure of +//! this suite's own assumptions rather than silently accepted. +//! +//! # An `on_block` step implies more than the README documents +//! +//! `tests/formats/fork_choice/README.md` says a successful `block` step +//! replays every attestation in the block's body through `on_attestation` +//! (with `is_from_block` true) once the block itself is accepted. The +//! reference test generator does one more thing the README omits: it also +//! replays every attester slashing in the block's body through +//! `on_attester_slashing`. See `add_block` in the pinned specification +//! checkout's `tests/core/pyspec/eth2spec/test/helpers/fork_choice.py`. Every +//! released fixture was generated against that code, not just the README's +//! prose, so skipping the slashing half would silently diverge from what a +//! case's later `checks` actually expect. [`apply_block`] does both. +//! +//! # `electra` and `fulu` need a different attestation and slashing shape +//! +//! `phase0::Attestation`/`phase0::AttesterSlashing` decode phase0 through +//! deneb's blocks and standalone `attestation_`/ +//! `attester_slashing_` files unchanged; electra and fulu need +//! `electra::Attestation`/`electra::AttesterSlashing` instead (EIP-7549). Both +//! [`fork_choice::Attestation`] and [`fork_choice::AttesterSlashing`] wrap the +//! two shapes, so [`decode_attestation`], [`decode_attester_slashing`], and +//! [`block_attestations_and_slashings`] each dispatch on `case.fork` once, +//! matching how [`decode_anchor_block`] already dispatches for blocks. +//! +//! # Checks this runner does not model +//! +//! `viable_for_head_roots_and_weights` is part of the format, but no case at +//! any implemented fork's `checks` step names it, on either preset, so it is +//! not modeled here rather than guessed at. `should_override_forkchoice_update` +//! *is* exercised, once per fork from bellatrix on, and [`apply_checks`] +//! checks it. +//! +//! # `columns: []` means "simulate unavailable", not "vacuously available" +//! +//! Fulu's own `is_data_available` (`specs/fulu/fork-choice.md`) is `all(... +//! for column_sidecar in column_sidecars)`, which is vacuously true over an +//! empty list. The reference test generator's own mock of +//! `retrieve_column_sidecars` disagrees on purpose: `with_blob_data_fulu` in +//! `tests/core/pyspec/eth2spec/test/helpers/fork_choice.py` asserts `False` +//! ("Simulation: not all required columns have been sampled") whenever it is +//! asked to return zero sidecars, rather than returning the empty list +//! literally. So a `columns: []` field on a `block` step means the block +//! must be rejected before this crate's own `is_data_available` ever runs; +//! [`block_blob_evidence`] enforces that directly, rather than trusting +//! [`fork_choice::is_data_available_columns`] to reject it (it will not: an +//! absent `columns` field, meaning a block that never samples any column at +//! all, has to reach that same vacuous truth for an ordinary non-blob block +//! to validate). +//! +//! # `anchor_block.ssz_snappy` is unsigned; `get_forkchoice_store` wants signed +//! +//! [`fork_choice::get_forkchoice_store`] takes a [`SignedBeaconBlock`], +//! matching what `Store::blocks` holds (see that module's own documentation +//! for why the store holds a signed block at all). The fixture's +//! `anchor_block.ssz_snappy` is an unsigned `BeaconBlock`, so +//! [`decode_anchor_block`] decodes it as the fork's own unsigned container +//! and wraps it in a zero-signature signed one; the anchor block's signature +//! is never actually checked, since a trusted anchor is not verified against +//! anything. A `block` step's own file is already a signed block, so +//! [`decode_signed_block`] just decodes it directly through +//! [`SignedBeaconBlock::from_ssz`]. + +use std::sync::Arc; + +use ethlambda_state_transition::beacon::ForkName; +use ethlambda_state_transition::beacon::config::Config; +use ethlambda_state_transition::beacon::containers::{ + BeaconState, Checkpoint, SignedBeaconBlock, altair, bellatrix, capella, deneb, electra, fulu, + phase0, +}; +use ethlambda_state_transition::beacon::fork_choice::{self, DataAvailability, Store}; +use ethlambda_state_transition::beacon::preset; +use ethlambda_state_transition::beacon::primitives::{KzgProof, Root}; +use libssz::SszDecode; +use libssz_types::SszList; +use libtest_mimic::Trial; + +use super::{Case, PRESET, collect_all_handlers, lean_is_not_a_fixture_fork}; + +// --------------------------------------------------------------------------- +// `steps.yaml` deserialization +// --------------------------------------------------------------------------- + +/// One entry of a case's `steps.yaml`. +/// +/// The format overlays six step kinds into one YAML sequence item: exactly +/// one of [`Step::tick`], [`Step::block`], [`Step::attestation`], +/// [`Step::attester_slashing`], and [`Step::pow_block`] is set for an +/// execution step, or none of them for a [`Step::checks`] step. Modeled as +/// one struct with every field optional, rather than a `#[serde(untagged)]` +/// enum over five variants, because the four execution kinds that carry a +/// validity outcome also share [`Step::valid`], which an enum would have to +/// repeat on every variant instead of naming once. +#[derive(serde::Deserialize)] +struct Step { + /// The Unix-second time to advance the store to, for an `on_tick` step. + tick: Option, + /// The `block_` file naming the block for an `on_block` step. + block: Option, + /// `[New in Deneb/Electra]` the `blobs_` file naming this `block` + /// step's blob evidence, paired positionally with [`Step::proofs`]. + blobs: Option, + /// `[New in Deneb/Electra]` this `block` step's proofs, one per blob in + /// [`Step::blobs`], as `0x`-prefixed byte48 hex strings rather than a + /// separate file. + proofs: Option>, + /// `[New in Fulu]` the `column_` files naming this `block` step's + /// column evidence, replacing [`Step::blobs`]/[`Step::proofs`]. See the + /// module documentation for why an empty (but present) list is not the + /// same as an absent one. + columns: Option>, + /// The `attestation_` file naming the attestation for an + /// `on_attestation` step. + attestation: Option, + /// The `attester_slashing_` file naming the slashing for an + /// `on_attester_slashing` step. + attester_slashing: Option, + /// `[New in Bellatrix]` the `pow_block_` file naming the PoW block + /// an `on_merge_block` step adds to the store for later `get_pow_block` + /// lookups. + pow_block: Option, + /// Whether this step's call is expected to succeed. Only `block`, + /// `attestation`, and `attester_slashing` steps carry `false` in any + /// released fixture, but the format allows it on any execution step. + #[serde(default = "default_valid")] + valid: bool, + /// The assertions to check against the current store. + checks: Option, +} + +/// [`Step::valid`]'s default: a step not naming its own validity is expected +/// to succeed. +fn default_valid() -> bool { + true +} + +/// A `checks` step's assertions against the store. +/// +/// See the module documentation for the one field of the format this leaves +/// out, and why. +#[derive(serde::Deserialize)] +struct Checks { + time: Option, + genesis_time: Option, + head: Option, + justified_checkpoint: Option, + finalized_checkpoint: Option, + proposer_boost_root: Option, + get_proposer_head: Option, + /// `[New in Bellatrix]` see + /// [`fork_choice::should_override_forkchoice_update`]. + should_override_forkchoice_update: Option, +} + +/// The expected value of [`fork_choice::get_head`], as `checks.head` gives it: +/// the root and, redundantly, the slot of the block it names. +#[derive(serde::Deserialize)] +struct HeadCheck { + slot: u64, + root: String, +} + +/// The expected value of a checkpoint field (`justified_checkpoint` or +/// `finalized_checkpoint`). +#[derive(serde::Deserialize)] +struct CheckpointCheck { + epoch: u64, + root: String, +} + +/// The expected value of +/// [`fork_choice::should_override_forkchoice_update`]: the fixed +/// `validator_is_connected` answer to call it with, and the result it must +/// then return. +#[derive(serde::Deserialize)] +struct ShouldOverrideForkchoiceUpdateCheck { + validator_is_connected: bool, + result: bool, +} + +/// Parses a fixture's `0x`-prefixed hex root. +/// +/// Duplicated from `ssz_static`'s private helper of the same purpose rather +/// than shared, matching how each runner in this test suite is otherwise +/// self-contained. +fn parse_root(hex_root: &str) -> Root { + let stripped = hex_root.strip_prefix("0x").unwrap_or(hex_root); + let bytes = hex::decode(stripped).expect("the fixture's root is valid hex"); + Root::from_slice(&bytes) +} + +/// Parses a fixture's `0x`-prefixed byte48 hex string into a [`KzgProof`], +/// the shape a `block` step's inline `proofs` field carries them in rather +/// than a separate file. +fn parse_kzg_proof(hex_proof: &str) -> KzgProof { + let stripped = hex_proof.strip_prefix("0x").unwrap_or(hex_proof); + let bytes = hex::decode(stripped).expect("the fixture's proof is valid hex"); + KzgProof( + bytes + .try_into() + .expect("a KZG proof is KZG_POINT_SIZE bytes"), + ) +} + +// --------------------------------------------------------------------------- +// Decoding blocks, attestations, and slashings +// --------------------------------------------------------------------------- + +/// Decodes `.ssz_snappy` as `T`, turning a decode failure into a case +/// failure rather than a panic: a block, attestation, or slashing this crate +/// cannot parse is exactly the kind of thing this suite exists to catch. +fn decode(case: &Case, name: &str) -> Result { + T::from_ssz_bytes(&case.ssz_bytes(name)).map_err(|err| format!("decoding {name}: {err:?}")) +} + +/// Decodes `anchor_block.ssz_snappy` for [`fork_choice::get_forkchoice_store`]. +/// +/// The file is an unsigned `BeaconBlock`; see the module documentation for +/// why this wraps it in a signed container with a zero signature rather than +/// decoding straight into one. `ForkName::Fulu` decodes as +/// [`electra::SignedBeaconBlock`], matching how [`SignedBeaconBlock::Fulu`] +/// wraps that same type rather than a `fulu`-specific one. +fn decode_anchor_block(case: &Case) -> Result { + match case.fork { + ForkName::Phase0 => Ok(SignedBeaconBlock::Phase0(phase0::SignedBeaconBlock { + message: decode(case, "anchor_block")?, + signature: Default::default(), + })), + ForkName::Altair => Ok(SignedBeaconBlock::Altair(altair::SignedBeaconBlock { + message: decode(case, "anchor_block")?, + signature: Default::default(), + })), + ForkName::Bellatrix => Ok(SignedBeaconBlock::Bellatrix(bellatrix::SignedBeaconBlock { + message: decode(case, "anchor_block")?, + signature: Default::default(), + })), + ForkName::Capella => Ok(SignedBeaconBlock::Capella(capella::SignedBeaconBlock { + message: decode(case, "anchor_block")?, + signature: Default::default(), + })), + ForkName::Deneb => Ok(SignedBeaconBlock::Deneb(deneb::SignedBeaconBlock { + message: decode(case, "anchor_block")?, + signature: Default::default(), + })), + ForkName::Electra => Ok(SignedBeaconBlock::Electra(electra::SignedBeaconBlock { + message: decode(case, "anchor_block")?, + signature: Default::default(), + })), + ForkName::Fulu => Ok(SignedBeaconBlock::Fulu(electra::SignedBeaconBlock { + message: decode(case, "anchor_block")?, + signature: Default::default(), + })), + ForkName::Lean => lean_is_not_a_fixture_fork("fork_choice"), + } +} + +/// Decodes a `block_.ssz_snappy` file named by an `on_block` step. The +/// file is already a signed block of the case's own fork, so this is a +/// direct decode through the fork-generic decoder, unlike +/// [`decode_anchor_block`]. +fn decode_signed_block(case: &Case, name: &str) -> Result { + SignedBeaconBlock::from_ssz(case.fork, &case.ssz_bytes(name)) + .map_err(|err| format!("decoding {name}: {err:?}")) +} + +/// Decodes an `attestation_.ssz_snappy` file, in whichever of +/// [`fork_choice::Attestation`]'s two shapes `case.fork` needs. See the +/// module documentation for why electra and fulu need +/// [`electra::Attestation`] rather than [`phase0::Attestation`]. +fn decode_attestation(case: &Case, name: &str) -> Result { + match case.fork { + ForkName::Electra | ForkName::Fulu => { + Ok(fork_choice::Attestation::Electra(decode(case, name)?)) + } + _ => Ok(fork_choice::Attestation::Phase0(decode(case, name)?)), + } +} + +/// Decodes an `attester_slashing_.ssz_snappy` file. See +/// [`decode_attestation`] for why the fork decides the shape. +fn decode_attester_slashing( + case: &Case, + name: &str, +) -> Result { + match case.fork { + ForkName::Electra | ForkName::Fulu => { + Ok(fork_choice::AttesterSlashing::Electra(decode(case, name)?)) + } + _ => Ok(fork_choice::AttesterSlashing::Phase0(decode(case, name)?)), + } +} + +/// The attestations and attester slashings carried in `block`'s body, each +/// already wrapped in [`fork_choice::Attestation`]/ +/// [`fork_choice::AttesterSlashing`]. Phase0 through deneb share +/// `phase0::Attestation`/`phase0::AttesterSlashing`; electra and fulu share +/// `electra::Attestation`/`electra::AttesterSlashing`. See the module +/// documentation. +fn block_attestations_and_slashings( + block: &SignedBeaconBlock, +) -> ( + Vec, + Vec, +) { + match block { + SignedBeaconBlock::Phase0(block) => ( + block + .message + .body + .attestations + .iter() + .cloned() + .map(fork_choice::Attestation::Phase0) + .collect(), + block + .message + .body + .attester_slashings + .iter() + .cloned() + .map(fork_choice::AttesterSlashing::Phase0) + .collect(), + ), + SignedBeaconBlock::Altair(block) => ( + block + .message + .body + .attestations + .iter() + .cloned() + .map(fork_choice::Attestation::Phase0) + .collect(), + block + .message + .body + .attester_slashings + .iter() + .cloned() + .map(fork_choice::AttesterSlashing::Phase0) + .collect(), + ), + SignedBeaconBlock::Bellatrix(block) => ( + block + .message + .body + .attestations + .iter() + .cloned() + .map(fork_choice::Attestation::Phase0) + .collect(), + block + .message + .body + .attester_slashings + .iter() + .cloned() + .map(fork_choice::AttesterSlashing::Phase0) + .collect(), + ), + SignedBeaconBlock::Capella(block) => ( + block + .message + .body + .attestations + .iter() + .cloned() + .map(fork_choice::Attestation::Phase0) + .collect(), + block + .message + .body + .attester_slashings + .iter() + .cloned() + .map(fork_choice::AttesterSlashing::Phase0) + .collect(), + ), + SignedBeaconBlock::Deneb(block) => ( + block + .message + .body + .attestations + .iter() + .cloned() + .map(fork_choice::Attestation::Phase0) + .collect(), + block + .message + .body + .attester_slashings + .iter() + .cloned() + .map(fork_choice::AttesterSlashing::Phase0) + .collect(), + ), + SignedBeaconBlock::Electra(block) => ( + block + .message + .body + .attestations + .iter() + .cloned() + .map(fork_choice::Attestation::Electra) + .collect(), + block + .message + .body + .attester_slashings + .iter() + .cloned() + .map(fork_choice::AttesterSlashing::Electra) + .collect(), + ), + SignedBeaconBlock::Fulu(block) => ( + block + .message + .body + .attestations + .iter() + .cloned() + .map(fork_choice::Attestation::Electra) + .collect(), + block + .message + .body + .attester_slashings + .iter() + .cloned() + .map(fork_choice::AttesterSlashing::Electra) + .collect(), + ), + } +} + +/// Decodes a `pow_block_.ssz_snappy` file named by an `on_merge_block` +/// step. +fn decode_pow_block(case: &Case, name: &str) -> Result { + decode(case, name) +} + +/// Extracts a `block` step's blob evidence, if it carries any: deneb and +/// electra's `blobs`/`proofs` fields, or fulu's `columns` field. Absent +/// either, this is [`DataAvailability::NotRequired`], the right value for +/// every pre-deneb block and for a later-fork block with no blob +/// commitments. +/// +/// See the module documentation for why an empty (but present) `columns` +/// list is rejected directly here rather than passed through to +/// [`fork_choice::is_data_available_columns`]. +fn block_blob_evidence(case: &Case, step: &Step) -> Result { + if let Some(names) = &step.columns { + if names.is_empty() { + return Err( + "columns: [] simulates the reference generator's retrieve_column_sidecars \ + raising \"not all required columns have been sampled\" (see this runner's \ + module documentation), so the block must be rejected before \ + is_data_available_columns ever runs" + .to_string(), + ); + } + let sidecars = names + .iter() + .map(|name| decode::(case, name)) + .collect::, _>>()?; + return Ok(DataAvailability::Columns(sidecars)); + } + + if let Some(name) = &step.blobs { + let blobs: SszList = + case.ssz(name); + let proofs = step + .proofs + .as_deref() + .unwrap_or_default() + .iter() + .map(|hex_proof| parse_kzg_proof(hex_proof)) + .collect(); + return Ok(DataAvailability::Blobs { + blobs: blobs.into_inner(), + proofs, + }); + } + + Ok(DataAvailability::NotRequired) +} + +// --------------------------------------------------------------------------- +// Applying a step +// --------------------------------------------------------------------------- + +/// Applies one `block` step: decodes the named file and its blob evidence, +/// calls `on_block`, and, only if the block was accepted, replays every +/// attestation and attester slashing carried in its body. See the module +/// documentation for why the slashing half belongs here even though the +/// format's own README omits it. +fn apply_block( + store: &mut Store, + case: &Case, + step: &Step, + name: &str, + expect_valid: bool, + config: &Config, +) -> Result<(), String> { + let signed_block = decode_signed_block(case, name)?; + + let blob_evidence = match block_blob_evidence(case, step) { + Ok(evidence) => evidence, + // A simulated-unavailable `columns: []` never even reaches + // `on_block` (see `block_blob_evidence`'s documentation), but the + // fixture is asking about exactly the same "was this block + // rejected" question `on_block`'s own `Err` below answers, so this + // is folded into the same `expect_valid` check rather than treated + // as this suite's own setup failing. + Err(simulated_unavailable) => { + return if expect_valid { + Err(format!("{name} was rejected: {simulated_unavailable}")) + } else { + Ok(()) + }; + } + }; + // Collected before `on_block` moves `signed_block` in, so they are still + // available for the replay below after a successful call. + let (attestations, attester_slashings) = block_attestations_and_slashings(&signed_block); + + match ( + fork_choice::on_block(store, signed_block, config, &blob_evidence), + expect_valid, + ) { + (Ok(()), false) => { + return Err(format!( + "{name} was accepted, but the step expects it to be rejected" + )); + } + (Err(err), true) => return Err(format!("{name} was rejected: {err:?}")), + // Correctly rejected: the handler's contract leaves `store` untouched, + // so there is nothing from this block left to replay. + (Err(_), false) => return Ok(()), + (Ok(()), true) => {} + } + + for attestation in &attestations { + fork_choice::on_attestation(store, attestation, true, config).map_err(|err| { + format!("on_attestation for an attestation carried in {name}: {err:?}") + })?; + } + for attester_slashing in &attester_slashings { + fork_choice::on_attester_slashing(store, attester_slashing).map_err(|err| { + format!("on_attester_slashing for a slashing carried in {name}: {err:?}") + })?; + } + + Ok(()) +} + +/// Applies one non-`checks` execution step, dispatching on which of +/// [`Step::tick`], [`Step::block`], [`Step::attestation`], +/// [`Step::attester_slashing`], or [`Step::pow_block`] is set. +fn apply_execution_step( + store: &mut Store, + case: &Case, + step: &Step, + config: &Config, +) -> Result<(), String> { + if let Some(time) = step.tick { + if !step.valid { + // The specification's `on_tick` has no assertion to fail, and + // neither does this crate's: there is no way to honor a fixture + // that asked for a rejected tick, so this fails loudly instead of + // quietly treating the step as a pass. No released fixture + // exercises this; see the module documentation. + return Err( + "a tick step expects rejection, but on_tick cannot fail in this crate".to_string(), + ); + } + fork_choice::on_tick(store, time, config); + return Ok(()); + } + + if let Some(name) = &step.block { + return apply_block(store, case, step, name, step.valid, config); + } + + if let Some(name) = &step.attestation { + let attestation = decode_attestation(case, name)?; + return match ( + fork_choice::on_attestation(store, &attestation, false, config), + step.valid, + ) { + (Ok(()), false) => Err(format!( + "{name} was accepted, but the step expects it to be rejected" + )), + (Err(err), true) => Err(format!("{name} was rejected: {err:?}")), + _ => Ok(()), + }; + } + + if let Some(name) = &step.attester_slashing { + let attester_slashing = decode_attester_slashing(case, name)?; + return match ( + fork_choice::on_attester_slashing(store, &attester_slashing), + step.valid, + ) { + (Ok(()), false) => Err(format!( + "{name} was accepted, but the step expects it to be rejected" + )), + (Err(err), true) => Err(format!("{name} was rejected: {err:?}")), + _ => Ok(()), + }; + } + + if let Some(name) = &step.pow_block { + // No validity outcome to honor here: an `on_merge_block` step only + // ever adds data a fixture suite already trusts (see + // `fork_choice::insert_pow_block`'s own documentation), so there is + // nothing for `step.valid` to mean. + let pow_block = decode_pow_block(case, name)?; + fork_choice::insert_pow_block(store, pow_block); + return Ok(()); + } + + Err( + "step has none of tick, block, attestation, attester_slashing, or pow_block set" + .to_string(), + ) +} + +// --------------------------------------------------------------------------- +// Checking the store +// --------------------------------------------------------------------------- + +/// Checks one scalar field against its expected value. +fn check_u64(label: &str, expected: u64, actual: u64) -> Result<(), String> { + if actual == expected { + Ok(()) + } else { + Err(format!("{label}: expected {expected}, got {actual}")) + } +} + +/// Checks one root-valued field against its expected, hex-encoded value. +fn check_root(label: &str, expected_hex: &str, actual: Root) -> Result<(), String> { + let expected = parse_root(expected_hex); + if actual == expected { + Ok(()) + } else { + Err(format!( + "{label}: expected 0x{}, got 0x{}", + hex::encode(expected.0), + hex::encode(actual.0), + )) + } +} + +/// Checks `justified_checkpoint` or `finalized_checkpoint` against its +/// expected epoch and root. +fn check_checkpoint( + label: &str, + expected: &CheckpointCheck, + actual: Checkpoint, +) -> Result<(), String> { + let expected_checkpoint = Checkpoint { + epoch: expected.epoch, + root: parse_root(&expected.root), + }; + if actual == expected_checkpoint { + Ok(()) + } else { + Err(format!( + "{label}: expected {{epoch: {}, root: 0x{}}}, got {{epoch: {}, root: 0x{}}}", + expected_checkpoint.epoch, + hex::encode(expected_checkpoint.root.0), + actual.epoch, + hex::encode(actual.root.0), + )) + } +} + +/// Checks `head` against [`fork_choice::get_head`]'s root, and that root's +/// slot in `store.blocks` against the fixture's redundant `slot` field. +fn check_head(expected: &HeadCheck, store: &Store, config: &Config) -> Result<(), String> { + let actual_root = + fork_choice::get_head(store, config).map_err(|err| format!("get_head: {err:?}"))?; + let actual_slot = store + .blocks + .get(&actual_root) + .map(|block| block.slot()) + .ok_or_else(|| { + format!( + "get_head returned 0x{}, which is not in store.blocks", + hex::encode(actual_root.0) + ) + })?; + + let expected_root = parse_root(&expected.root); + if actual_root == expected_root && actual_slot == expected.slot { + Ok(()) + } else { + Err(format!( + "head: expected {{slot: {}, root: 0x{}}}, got {{slot: {actual_slot}, root: 0x{}}}", + expected.slot, + hex::encode(expected_root.0), + hex::encode(actual_root.0), + )) + } +} + +/// Checks `get_proposer_head`, computed the same way the reference test +/// harness does: from the current head and current slot, not a value the +/// fixture supplies separately. +fn check_get_proposer_head( + expected_hex: &str, + store: &Store, + config: &Config, +) -> Result<(), String> { + let head = fork_choice::get_head(store, config).map_err(|err| format!("get_head: {err:?}"))?; + let slot = fork_choice::get_current_slot(store, config); + let actual = fork_choice::get_proposer_head(store, head, slot, config) + .map_err(|err| format!("get_proposer_head: {err:?}"))?; + check_root("get_proposer_head", expected_hex, actual) +} + +/// Checks `should_override_forkchoice_update`, the same way +/// [`check_get_proposer_head`] checks `get_proposer_head`: from the current +/// head, not a root the fixture supplies separately. `validator_is_connected` +/// is a fixed answer regardless of which proposer index is asked, matching +/// what the fixture format itself supplies: one bool for the whole call, not +/// a per-validator registry. +fn check_should_override_forkchoice_update( + expected: &ShouldOverrideForkchoiceUpdateCheck, + store: &Store, + config: &Config, +) -> Result<(), String> { + let head = fork_choice::get_head(store, config).map_err(|err| format!("get_head: {err:?}"))?; + let actual = fork_choice::should_override_forkchoice_update( + store, + head, + |_| expected.validator_is_connected, + config, + ) + .map_err(|err| format!("should_override_forkchoice_update: {err:?}"))?; + if actual == expected.result { + Ok(()) + } else { + Err(format!( + "should_override_forkchoice_update: expected {}, got {actual}", + expected.result + )) + } +} + +/// Applies one `checks` step: every field the fixture sets must match. +fn apply_checks(store: &Store, checks: &Checks, config: &Config) -> Result<(), String> { + if let Some(expected) = checks.time { + check_u64("time", expected, store.time)?; + } + if let Some(expected) = checks.genesis_time { + check_u64("genesis_time", expected, store.genesis_time)?; + } + if let Some(expected) = &checks.justified_checkpoint { + check_checkpoint("justified_checkpoint", expected, store.justified_checkpoint)?; + } + if let Some(expected) = &checks.finalized_checkpoint { + check_checkpoint("finalized_checkpoint", expected, store.finalized_checkpoint)?; + } + if let Some(expected) = &checks.proposer_boost_root { + check_root("proposer_boost_root", expected, store.proposer_boost_root)?; + } + if let Some(expected) = &checks.head { + check_head(expected, store, config)?; + } + if let Some(expected) = &checks.get_proposer_head { + check_get_proposer_head(expected, store, config)?; + } + if let Some(expected) = &checks.should_override_forkchoice_update { + check_should_override_forkchoice_update(expected, store, config)?; + } + Ok(()) +} + +// --------------------------------------------------------------------------- +// Running a case +// --------------------------------------------------------------------------- + +/// Runs one case: builds the store from its anchor, then applies every step +/// in `steps.yaml` in order, stopping at the first one that fails. +/// +/// Stopping rather than continuing matches how a rejected call leaves `store` +/// untouched but a call that unexpectedly succeeds (or fails) leaves it in a +/// state the fixture's remaining steps were never written to expect; nothing +/// past that point would be checking anything meaningful. +fn run_case(case: &Case, config: &Config) -> Result<(), String> { + let anchor_state = BeaconState::from_ssz(case.fork, &case.ssz_bytes("anchor_state")) + .map_err(|err| format!("decoding anchor_state: {err:?}"))?; + let anchor_block = decode_anchor_block(case)?; + + let mut store = fork_choice::get_forkchoice_store(anchor_state, anchor_block, config) + .map_err(|err| format!("get_forkchoice_store: {err:?}"))?; + + let steps: Vec = case.yaml("steps"); + for (index, step) in steps.iter().enumerate() { + let outcome = match &step.checks { + Some(checks) => apply_checks(&store, checks, config), + None => apply_execution_step(&mut store, case, step, config), + }; + outcome.map_err(|err| format!("step {index}: {err}"))?; + } + + Ok(()) +} + +/// The handler half of [`collect_all_handlers`]'s pair is discarded: every +/// case in this suite runs through [`run_case`] the same way regardless of +/// which handler it came from, unlike `ssz_static`, which dispatches on it. +pub fn trials() -> Vec { + let config = Arc::new(Config::active()); + let cases = collect_all_handlers(PRESET, "fork_choice"); + let mut trials = vec![super::discovery_trial("fork_choice", cases.len())]; + + for (_handler, case) in cases { + let config = Arc::clone(&config); + trials.push(super::case_trial("fork_choice", case, move |case| { + run_case(case, &config) + })); + } + + trials +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec/genesis.rs b/crates/blockchain/state_transition/tests/beacon_spec/genesis.rs new file mode 100644 index 000000000..db800e936 --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/genesis.rs @@ -0,0 +1,141 @@ +//! The `genesis` runner. +//! +//! Two handlers, matching the specification's own split of the topic. +//! `initialization` replays Eth1 deposit history through +//! `initialize_beacon_state_from_eth1` and checks the resulting candidate +//! state against a fixture-provided expected state. `validity` feeds a +//! ready-made candidate state straight to `is_valid_genesis_state` and checks +//! the boolean it returns. +//! +//! This release's fixtures ship `genesis` cases for the `minimal` preset only +//! (there is no `genesis` directory anywhere under `mainnet` in the extracted +//! tree), so this whole runner is gated on the `preset-minimal` feature. That +//! keeps the mainnet build from failing [`super::discovery_trial`]'s "matched +//! no fixture cases" check over a suite the release never populates for it, +//! without having to teach the shared harness a new kind of "expected empty" +//! outcome for one runner. +#![cfg(feature = "preset-minimal")] + +use std::sync::Arc; + +use ethlambda_state_transition::beacon::config::Config; +use ethlambda_state_transition::beacon::containers::{BeaconState, phase0, shared}; +use ethlambda_state_transition::beacon::genesis::{ + initialize_beacon_state_from_eth1, is_valid_genesis_state, +}; +use ethlambda_state_transition::beacon::primitives::{HashTreeRoot as _, Root}; +use libssz::SszDecode as _; +use libtest_mimic::Trial; + +use super::{Case, PRESET, collect}; + +#[derive(serde::Deserialize)] +struct Eth1 { + eth1_block_hash: String, + eth1_timestamp: u64, +} + +#[derive(serde::Deserialize)] +struct Meta { + deposits_count: usize, +} + +fn parse_root(hex_root: &str) -> Root { + let stripped = hex_root.strip_prefix("0x").unwrap_or(hex_root); + let bytes = hex::decode(stripped).expect("the fixture holds a hex-encoded 32-byte root"); + Root::from_slice(&bytes) +} + +/// Replays one `initialization` case and compares the resulting candidate's +/// root against the fixture's expected state. +/// +/// Compared by `hash_tree_root` rather than by full structural equality, +/// matching how `ssz_static` checks a container: the root is the +/// specification's own notion of "the same state", and is far more readable +/// on failure than a field-by-field dump of two multi-thousand-validator +/// states would be. +fn initialization_case(case: &Case, config: &Config) -> Result<(), String> { + let eth1: Eth1 = case.yaml("eth1"); + let meta: Meta = case.yaml("meta"); + + let eth1_block_hash = parse_root(ð1.eth1_block_hash); + let deposits: Vec = (0..meta.deposits_count) + .map(|index| case.ssz::(&format!("deposits_{index}"))) + .collect(); + + let expected = phase0::BeaconState::from_ssz_bytes(&case.ssz_bytes("state")) + .map_err(|err| format!("decoding the fixture's expected state: {err:?}"))?; + + let actual = + initialize_beacon_state_from_eth1(eth1_block_hash, eth1.eth1_timestamp, &deposits, config) + .map_err(|err| format!("initialize_beacon_state_from_eth1: {err}"))?; + + let expected_root = expected.hash_tree_root(); + let actual_root = actual.hash_tree_root(); + if actual_root != expected_root { + return Err(format!( + "hash_tree_root 0x{} != expected 0x{}", + hex::encode(actual_root.0), + hex::encode(expected_root.0), + )); + } + + Ok(()) +} + +/// Runs one `validity` case: decode the candidate state the fixture ships and +/// check `is_valid_genesis_state` against the fixture's expected boolean. +fn validity_case(case: &Case, config: &Config) -> Result<(), String> { + let state = phase0::BeaconState::from_ssz_bytes(&case.ssz_bytes("genesis")) + .map_err(|err| format!("decoding the candidate state: {err:?}"))?; + let expected: bool = case.yaml("is_valid"); + + let actual = is_valid_genesis_state(&BeaconState::Phase0(state), config); + if actual != expected { + return Err(format!( + "is_valid_genesis_state returned {actual}, expected {expected}" + )); + } + + Ok(()) +} + +pub fn trials() -> Vec { + let config = Arc::new(Config::minimal()); + + let initialization_cases = collect(PRESET, "genesis", "initialization"); + let mut trials = vec![super::discovery_trial( + "genesis/initialization", + initialization_cases.len(), + )]; + + for case in initialization_cases { + let config = Arc::clone(&config); + // Only phase0 has a genesis-construction fixture suite in this + // release; a later fork adding one would need its own state type + // here rather than silently being decoded as phase0's. Gated through + // [`super::case_trial`]'s own `in_scope` check rather than a bespoke + // phase0 check here, which keeps this runner consistent with the rest + // even though, today, there is nothing after phase0 for it to skip. + trials.push(super::case_trial( + "genesis/initialization", + case, + move |case| initialization_case(case, &config), + )); + } + + let validity_cases = collect(PRESET, "genesis", "validity"); + trials.push(super::discovery_trial( + "genesis/validity", + validity_cases.len(), + )); + + for case in validity_cases { + let config = Arc::clone(&config); + trials.push(super::case_trial("genesis/validity", case, move |case| { + validity_case(case, &config) + })); + } + + trials +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec/harness.rs b/crates/blockchain/state_transition/tests/beacon_spec/harness.rs new file mode 100644 index 000000000..de0b885a7 --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/harness.rs @@ -0,0 +1,142 @@ +//! Self-tests for the fixture harness. +//! +//! These check the harness itself, not the crate under test: that it finds the +//! fixture tree, that discovery reaches every supported fork, that it skips +//! forks this crate does not implement, and that snappy decompression produces +//! bytes an SSZ decoder accepts. A harness bug otherwise shows up as a suite +//! that quietly matches nothing. +//! +//! No case collection to guard here, unlike every other runner: these trials +//! are fixed in number and known before the fixture tree is even walked, so +//! there is no [`super::discovery_trial`] alongside them. + +use ethlambda_state_transition::beacon::ForkName; +use ethlambda_state_transition::beacon::primitives::{HashTreeRoot as _, Root}; +use libssz::{SszDecode as _, SszEncode as _}; +use libssz_derive::{HashTreeRoot, SszDecode, SszEncode}; +use libtest_mimic::Trial; + +use super::{Case, PRESET, collect, fixture_root}; + +#[derive(serde::Deserialize)] +struct RootFile { + root: String, +} + +/// The specification's `Checkpoint`, declared here rather than imported. +/// +/// This is the harness proving out the whole chain a container runner depends +/// on: raw-snappy decompression, SSZ decoding, merkleization, and re-encoding, +/// checked against a fixture's own expected root. `Checkpoint` is the smallest +/// container that exists in every fork, so it isolates that chain from anything +/// fork-specific. The real containers land with their own suites. +#[derive(Debug, Clone, PartialEq, SszEncode, SszDecode, HashTreeRoot)] +struct Checkpoint { + epoch: u64, + root: Root, +} + +pub fn trials() -> Vec { + vec![ + Trial::test("harness/fixture_tree_is_present", || { + let root = fixture_root(); + assert!( + root.join(PRESET).is_dir(), + "no {PRESET} fixtures under {}", + root.display() + ); + assert!( + root.join("general").is_dir(), + "no general fixtures under {}", + root.display() + ); + Ok(()) + }), + Trial::test("harness/discovery_finds_a_known_suite", || { + // Checkpoint exists in every fork's ssz_static suite, and is the smallest + // container that does, which makes it a stable canary for discovery. + let cases = collect(PRESET, "ssz_static", "Checkpoint"); + assert!(!cases.is_empty(), "no ssz_static/Checkpoint cases found"); + + for case in &cases { + assert!( + case.has("serialized"), + "{} has no serialized file", + case.id() + ); + assert!(case.has("roots"), "{} has no roots file", case.id()); + } + Ok(()) + }), + Trial::test("harness/discovery_covers_every_supported_fork", || { + let cases = collect(PRESET, "ssz_static", "Checkpoint"); + for fork in ForkName::ALL { + assert!( + cases.iter().any(|case| case.fork == fork), + "discovery found no {fork} cases; the fixture release is expected to \ + cover every fork this crate implements" + ); + } + Ok(()) + }), + Trial::test("harness/discovery_skips_forks_out_of_scope", || { + // The release ships suites for forks after fulu, and for standalone EIPs. + // Those must not reach a runner, since this crate has no types for them. + let cases = collect(PRESET, "ssz_static", "Checkpoint"); + for case in &cases { + assert!( + ForkName::ALL.contains(&case.fork), + "{} is outside the implemented forks", + case.id() + ); + } + Ok(()) + }), + Trial::test("harness/snappy_decompression_yields_decodable_ssz", || { + let cases = collect(PRESET, "ssz_static", "Checkpoint"); + let case: &Case = cases.first().expect("at least one Checkpoint case"); + + // A Checkpoint is an epoch and a root, so its SSZ encoding is fixed-length. + let bytes = case.ssz_bytes("serialized"); + assert_eq!( + bytes.len(), + 40, + "a Checkpoint is a u64 epoch followed by a 32-byte root" + ); + + let roots: RootFile = case.yaml("roots"); + assert!(roots.root.starts_with("0x"), "roots.yaml holds a hex root"); + Ok(()) + }), + Trial::test( + "harness/container_round_trip_matches_the_fixture_root", + || { + for case in collect(PRESET, "ssz_static", "Checkpoint") { + let bytes = case.ssz_bytes("serialized"); + let expected: RootFile = case.yaml("roots"); + + let checkpoint = Checkpoint::from_ssz_bytes(&bytes) + .map_err(|err| format!("{}: decode failed: {err:?}", case.id()))?; + let root = format!("0x{}", hex::encode(checkpoint.hash_tree_root().0)); + if root != expected.root { + return Err(format!( + "{}: root {root} != expected {}", + case.id(), + expected.root + ) + .into()); + } + if checkpoint.to_ssz() != bytes { + return Err(format!( + "{}: re-encoding did not reproduce the fixture bytes", + case.id() + ) + .into()); + } + } + + Ok(()) + }, + ), + ] +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec/kzg.rs b/crates/blockchain/state_transition/tests/beacon_spec/kzg.rs new file mode 100644 index 000000000..6bdbe0bd7 --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/kzg.rs @@ -0,0 +1,473 @@ +//! The `kzg` runner. +//! +//! Covers every function `crates/blockchain/state_transition/src/beacon/kzg.rs` wraps from `c-kzg`: deneb's +//! seven blob-commitment handlers (`blob_to_kzg_commitment`, +//! `compute_kzg_proof`, `compute_blob_kzg_proof`, `verify_kzg_proof`, +//! `verify_blob_kzg_proof`, `verify_blob_kzg_proof_batch`, `compute_challenge`) +//! and fulu's five cell-proof handlers for PeerDAS +//! (`compute_cells`, `compute_cells_and_kzg_proofs`, +//! `recover_cells_and_kzg_proofs`, `verify_cell_kzg_proof_batch`, +//! `compute_verify_cell_kzg_proof_batch_challenge`). Before this runner, no +//! fixture exercised any of them outside `kzg.rs`'s own ad hoc test module, +//! which predates this crate's shared fixture harness and is not wired into +//! `spec_tests` or its per-case reporting. +//! +//! # Why `general`, not a preset +//! +//! [`super::PRESET`] selects between `minimal` and `mainnet` because container +//! bounds like `SLOTS_PER_EPOCH` are compiled in. Nothing about a blob, a cell, +//! or a KZG point is preset-dependent in that sense: `BYTES_PER_BLOB`, +//! `CELLS_PER_EXT_BLOB`, and the rest come from the KZG trusted setup and the +//! EIP-4844/EIP-7594 scheme itself, which is one fixed size regardless of which +//! preset the beacon state around it uses. So the release ships exactly one +//! `kzg` tree per fork, under `general`, the same reason [`super::collect_all_handlers`]'s +//! own doc gives for BLS. +//! +//! # What `output: null` means +//! +//! A case whose `output` is `null` means the operation must be rejected, the +//! same rule [`super::check_transition`] enforces elsewhere in this harness for +//! a case with no `post` state. The two look different only because a state +//! transition case expresses "no expected result" by omitting a file, while a +//! KZG case has no state to omit and expresses it with YAML's null instead. A +//! run that returns a value for such a case has to fail, not pass by +//! coincidence: the KZG suite spends a large share of its cases on malformed +//! input precisely because acceptance is easy to get right by accident and +//! rejection is not, so that half of the suite is where most of its value is. +//! +//! Some of this crate's KZG functions cannot even be called on a case that +//! must be rejected, rather than being called and returning `Err`: a case +//! whose `z`, `y`, `commitment`, `proof`, or `cell` field is not the exact byte +//! length its typed argument requires ([`Bytes32`], [`KzgCommitment`], +//! [`KzgProof`], [`Cell`]) fails before this runner can construct the value to +//! pass in. [`expect_rejected`] covers both paths with one check, since the +//! fixture's contract is the same either way: `output` must be `null`. +//! +//! # Why dispatch is on the handler alone +//! +//! [`super::ssz_static`] and [`super::epoch_processing`] match on +//! `(handler, fork)`, because the same handler name can select a different +//! function per fork there (`rewards_and_penalties` is phase0's replaying +//! `PendingAttestation`s versus altair's scoring participation flags, for +//! instance). Nothing here has that shape: deneb's seven handlers and fulu's +//! five are two disjoint sets, no name appears in both, and neither fork's +//! `polynomial-commitments*.md` redefines a function the other fork also +//! defines. So [`run`] matches on the handler name by itself; adding the fork +//! to the match would be dead weight, not a safety net, since no arm could +//! ever need it. + +use c_kzg::Cell; +use ethlambda_state_transition::beacon::kzg; +use ethlambda_state_transition::beacon::primitives::{Bytes32, H256, KzgCommitment, KzgProof}; +use libtest_mimic::Trial; +use serde_yaml_ng::Value; + +use super::{Case, collect_all_handlers}; + +/// Decodes a `0x`-prefixed hex string into bytes of whatever length it has. +/// +/// This is how a blob is decoded: its typed argument is `&[u8]`, not a fixed +/// array, so [`kzg`]'s own length check (`to_blob`, inside every function that +/// takes one) is what rejects a case whose blob is the wrong length, not this +/// runner. Every fixed-size field below builds on this, then narrows further. +fn hex_bytes(value: &Value) -> Vec { + let hex_str = value.as_str().expect("value is a hex string"); + hex::decode( + hex_str + .strip_prefix("0x") + .expect("hex string has a 0x prefix"), + ) + .expect("value is valid hex") +} + +/// Decodes a hex string into exactly `N` bytes, or `None` if its length does +/// not match. +/// +/// `N` is not a spec constant, only the width one of this module's own byte +/// arrays needs, so nothing here reaches for a name; the constant that does +/// matter, e.g. `BYTES_PER_CELL`, only lives inside `c-kzg` and this module +/// never repeats its value. +fn hex_array(value: &Value) -> Option<[u8; N]> { + hex_bytes(value).try_into().ok() +} + +/// Decodes a 32-byte field element (`z`, `y`, or a coset evaluation). +fn hex_bytes32(value: &Value) -> Option { + hex_array::<32>(value).map(H256) +} + +/// Decodes a compressed G1 point as a commitment. +fn hex_commitment(value: &Value) -> Option { + hex_array(value).map(KzgCommitment) +} + +/// Decodes a compressed G1 point as a proof. +fn hex_proof(value: &Value) -> Option { + hex_array(value).map(KzgProof) +} + +/// Decodes one cell of an extended blob. +/// +/// Unlike the fixed arrays above, [`Cell::from_bytes`] does its own length +/// check rather than this runner doing it through `try_into`, since `Cell` is +/// `c-kzg`'s type, not this crate's; `None` on a length mismatch either way. +fn hex_cell(value: &Value) -> Option { + Cell::from_bytes(&hex_bytes(value)).ok() +} + +/// Parses a YAML list of plain integers (`cell_indices`, `commitment_indices`), +/// as opposed to the hex-string lists every other list field in this suite +/// holds. +fn u64_list(value: &Value) -> Vec { + value + .as_sequence() + .expect("value is a list") + .iter() + .map(|entry| entry.as_u64().expect("list entry is an integer")) + .collect() +} + +/// Parses every element of a YAML list with `parse`, unconditionally. +/// +/// For fields whose own function call rejects a bad element instead of this +/// runner needing to notice first, e.g. blobs in a batch: `kzg`'s own +/// per-blob length check runs inside the call itself, not here. +fn hex_list(value: &Value, parse: impl Fn(&Value) -> T) -> Vec { + value + .as_sequence() + .expect("value is a list") + .iter() + .map(parse) + .collect() +} + +/// Parses every element of a YAML list with a fallible `parse`, or `None` if +/// any element fails. +/// +/// For fields whose typed element (a commitment, a proof, a cell) this runner +/// must construct itself before it can even call the function under test, so +/// one malformed element has to short-circuit the whole case to a rejection +/// before that call happens. +fn hex_list_opt(value: &Value, parse: impl Fn(&Value) -> Option) -> Option> { + value + .as_sequence() + .expect("value is a list") + .iter() + .map(parse) + .collect() +} + +/// Checks that `actual` equals `expected`, formatting either mismatch. +fn expect_eq(actual: T, expected: T) -> Result<(), String> { + if actual == expected { + Ok(()) + } else { + Err(format!("{actual:?} != {expected:?}")) + } +} + +/// Checks that `output` is `null`, the fixture's way of demanding a rejection. +/// +/// `reason` names why this case could not produce a value: either an input +/// field failed to parse at its required fixed size, before this crate's KZG +/// function could even be called, or that function itself returned `Err`. See +/// the module doc for why both collapse to the same check. +fn expect_rejected(output: &Value, reason: &str) -> Result<(), String> { + if output.is_null() { + Ok(()) + } else { + Err(format!( + "rejected ({reason}), but the fixture expects output {output:?}" + )) + } +} + +/// Checks a list of cells against the fixture's own list, element by element. +fn expect_cells_eq(actual: &[Cell], expected: &[Value]) -> Result<(), String> { + if actual.len() != expected.len() { + return Err(format!( + "produced {} cells, fixture expects {}", + actual.len(), + expected.len() + )); + } + for (cell, expected_cell) in actual.iter().zip(expected) { + expect_eq(Some(*cell), hex_cell(expected_cell))?; + } + Ok(()) +} + +/// Checks a list of proofs against the fixture's own list, element by element. +fn expect_proofs_eq(actual: &[KzgProof], expected: &[Value]) -> Result<(), String> { + if actual.len() != expected.len() { + return Err(format!( + "produced {} proofs, fixture expects {}", + actual.len(), + expected.len() + )); + } + for (proof, expected_proof) in actual.iter().zip(expected) { + expect_eq(Some(*proof), hex_proof(expected_proof))?; + } + Ok(()) +} + +fn check_blob_to_kzg_commitment(input: &Value, output: &Value) -> Result<(), String> { + let blob = hex_bytes(&input["blob"]); + match kzg::blob_to_kzg_commitment(&blob) { + Ok(commitment) => expect_eq(Some(commitment), hex_commitment(output)), + Err(err) => expect_rejected(output, &format!("{err:?}")), + } +} + +fn check_compute_kzg_proof(input: &Value, output: &Value) -> Result<(), String> { + let blob = hex_bytes(&input["blob"]); + let Some(z) = hex_bytes32(&input["z"]) else { + return expect_rejected(output, "z is not 32 bytes"); + }; + match kzg::compute_kzg_proof(&blob, &z) { + Ok((proof, y)) => { + let expected = output + .as_sequence() + .ok_or_else(|| format!("output {output:?} is not [proof, y]"))?; + expect_eq(Some(proof), hex_proof(&expected[0]))?; + expect_eq(Some(y), hex_bytes32(&expected[1])) + } + Err(err) => expect_rejected(output, &format!("{err:?}")), + } +} + +fn check_compute_blob_kzg_proof(input: &Value, output: &Value) -> Result<(), String> { + let blob = hex_bytes(&input["blob"]); + let Some(commitment) = hex_commitment(&input["commitment"]) else { + return expect_rejected(output, "commitment is not 48 bytes"); + }; + match kzg::compute_blob_kzg_proof(&blob, &commitment) { + Ok(proof) => expect_eq(Some(proof), hex_proof(output)), + Err(err) => expect_rejected(output, &format!("{err:?}")), + } +} + +fn check_verify_kzg_proof(input: &Value, output: &Value) -> Result<(), String> { + let (Some(commitment), Some(z), Some(y), Some(proof)) = ( + hex_commitment(&input["commitment"]), + hex_bytes32(&input["z"]), + hex_bytes32(&input["y"]), + hex_proof(&input["proof"]), + ) else { + return expect_rejected(output, "commitment, z, y, or proof is the wrong length"); + }; + match kzg::verify_kzg_proof(&commitment, &z, &y, &proof) { + Ok(verified) => expect_eq(Some(verified), output.as_bool()), + Err(err) => expect_rejected(output, &format!("{err:?}")), + } +} + +fn check_verify_blob_kzg_proof(input: &Value, output: &Value) -> Result<(), String> { + let blob = hex_bytes(&input["blob"]); + let (Some(commitment), Some(proof)) = ( + hex_commitment(&input["commitment"]), + hex_proof(&input["proof"]), + ) else { + return expect_rejected(output, "commitment or proof is the wrong length"); + }; + match kzg::verify_blob_kzg_proof(&blob, &commitment, &proof) { + Ok(verified) => expect_eq(Some(verified), output.as_bool()), + Err(err) => expect_rejected(output, &format!("{err:?}")), + } +} + +fn check_verify_blob_kzg_proof_batch(input: &Value, output: &Value) -> Result<(), String> { + // Blobs are decoded unconditionally, unlike commitments and proofs below: + // a batch member's own length check happens inside `verify_blob_kzg_proof_batch` + // itself (`to_blob`, per element), not here. + let blobs = hex_list(&input["blobs"], hex_bytes); + let blob_refs: Vec<&[u8]> = blobs.iter().map(Vec::as_slice).collect(); + let (Some(commitments), Some(proofs)) = ( + hex_list_opt(&input["commitments"], hex_commitment), + hex_list_opt(&input["proofs"], hex_proof), + ) else { + return expect_rejected(output, "a commitment or proof is the wrong length"); + }; + match kzg::verify_blob_kzg_proof_batch(&blob_refs, &commitments, &proofs) { + Ok(verified) => expect_eq(Some(verified), output.as_bool()), + Err(err) => expect_rejected(output, &format!("{err:?}")), + } +} + +/// `compute_challenge`'s fixtures carry no `output: null` case: unlike every +/// handler above, hashing a Fiat-Shamir transcript never fails on the +/// *content* of `blob` or `commitment`, only on `blob`'s length, which +/// [`kzg::compute_challenge`] itself checks (see its own doc). The `Err` arm +/// stays here anyway, matching every other handler, so a future fixture that +/// does exercise that length check is still handled rather than silently +/// mismatching the return type. +fn check_compute_challenge(input: &Value, output: &Value) -> Result<(), String> { + let blob = hex_bytes(&input["blob"]); + let Some(commitment) = hex_commitment(&input["commitment"]) else { + return expect_rejected(output, "commitment is not 48 bytes"); + }; + match kzg::compute_challenge(&blob, &commitment) { + Ok(challenge) => expect_eq(Some(challenge), hex_bytes32(output)), + Err(err) => expect_rejected(output, &format!("{err:?}")), + } +} + +fn check_compute_cells(input: &Value, output: &Value) -> Result<(), String> { + let blob = hex_bytes(&input["blob"]); + match kzg::compute_cells(&blob) { + Ok(cells) => { + let expected = output + .as_sequence() + .ok_or_else(|| format!("output {output:?} is not a list of cells"))?; + expect_cells_eq(cells.as_ref(), expected) + } + Err(err) => expect_rejected(output, &format!("{err:?}")), + } +} + +fn check_compute_cells_and_kzg_proofs(input: &Value, output: &Value) -> Result<(), String> { + let blob = hex_bytes(&input["blob"]); + match kzg::compute_cells_and_kzg_proofs(&blob) { + Ok((cells, proofs)) => { + let expected = output + .as_sequence() + .ok_or_else(|| format!("output {output:?} is not [cells, proofs]"))?; + let expected_cells = expected[0] + .as_sequence() + .ok_or_else(|| "cells is not a list".to_string())?; + let expected_proofs = expected[1] + .as_sequence() + .ok_or_else(|| "proofs is not a list".to_string())?; + expect_cells_eq(cells.as_ref(), expected_cells)?; + expect_proofs_eq(proofs.as_ref(), expected_proofs) + } + Err(err) => expect_rejected(output, &format!("{err:?}")), + } +} + +fn check_recover_cells_and_kzg_proofs(input: &Value, output: &Value) -> Result<(), String> { + let cell_indices = u64_list(&input["cell_indices"]); + let Some(cells) = hex_list_opt(&input["cells"], hex_cell) else { + return expect_rejected(output, "a cell is the wrong length"); + }; + match kzg::recover_cells_and_kzg_proofs(&cell_indices, &cells) { + Ok((recovered_cells, recovered_proofs)) => { + let expected = output + .as_sequence() + .ok_or_else(|| format!("output {output:?} is not [cells, proofs]"))?; + let expected_cells = expected[0] + .as_sequence() + .ok_or_else(|| "cells is not a list".to_string())?; + let expected_proofs = expected[1] + .as_sequence() + .ok_or_else(|| "proofs is not a list".to_string())?; + expect_cells_eq(recovered_cells.as_ref(), expected_cells)?; + expect_proofs_eq(recovered_proofs.as_ref(), expected_proofs) + } + Err(err) => expect_rejected(output, &format!("{err:?}")), + } +} + +fn check_verify_cell_kzg_proof_batch(input: &Value, output: &Value) -> Result<(), String> { + // A length mismatch *between* the four arrays (some `invalid_missing_*` + // cases supply fewer cells than cell_indices, for instance) is not caught + // here: every element still decodes at its own correct size, so + // `hex_list_opt` succeeds, and it is `verify_cell_kzg_proof_batch` itself + // that rejects the mismatched lengths (see its own doc). + let cell_indices = u64_list(&input["cell_indices"]); + let (Some(commitments), Some(cells), Some(proofs)) = ( + hex_list_opt(&input["commitments"], hex_commitment), + hex_list_opt(&input["cells"], hex_cell), + hex_list_opt(&input["proofs"], hex_proof), + ) else { + return expect_rejected(output, "a commitment, cell, or proof is the wrong length"); + }; + match kzg::verify_cell_kzg_proof_batch(&commitments, &cell_indices, &cells, &proofs) { + Ok(verified) => expect_eq(Some(verified), output.as_bool()), + Err(err) => expect_rejected(output, &format!("{err:?}")), + } +} + +/// Like `compute_challenge`, this fixture set carries no `output: null` case, +/// for the same reason: the transcript is raw bytes and indices, hashed, with +/// no curve-point validation along the way. What it can still fail on is the +/// array-length agreement [`kzg::compute_verify_cell_kzg_proof_batch_challenge`] +/// checks itself (`commitment_indices`, `cell_indices`, and `proofs` one entry +/// per coset), so the `Err` arm is kept for the same forward-compatibility +/// reason `check_compute_challenge` keeps its own. +fn check_compute_verify_cell_kzg_proof_batch_challenge( + input: &Value, + output: &Value, +) -> Result<(), String> { + let commitment_indices = u64_list(&input["commitment_indices"]); + let cell_indices = u64_list(&input["cell_indices"]); + let (Some(commitments), Some(cosets_evals), Some(proofs)) = ( + hex_list_opt(&input["commitments"], hex_commitment), + hex_list_opt(&input["cosets_evals"], |coset| { + hex_list_opt(coset, hex_bytes32) + }), + hex_list_opt(&input["proofs"], hex_proof), + ) else { + return expect_rejected( + output, + "a commitment, coset evaluation, or proof is the wrong length", + ); + }; + match kzg::compute_verify_cell_kzg_proof_batch_challenge( + &commitments, + &commitment_indices, + &cell_indices, + &cosets_evals, + &proofs, + ) { + Ok(challenge) => expect_eq(Some(challenge), hex_bytes32(output)), + Err(err) => expect_rejected(output, &format!("{err:?}")), + } +} + +/// Dispatches one case to the check function its handler names. +/// +/// See the module doc for why this matches on `handler` alone rather than on +/// `(handler, fork)`. +fn run(handler: &str, case: &Case) -> Result<(), String> { + let data: Value = case.yaml("data"); + let input = &data["input"]; + let output = &data["output"]; + + match handler { + "blob_to_kzg_commitment" => check_blob_to_kzg_commitment(input, output), + "compute_kzg_proof" => check_compute_kzg_proof(input, output), + "compute_blob_kzg_proof" => check_compute_blob_kzg_proof(input, output), + "verify_kzg_proof" => check_verify_kzg_proof(input, output), + "verify_blob_kzg_proof" => check_verify_blob_kzg_proof(input, output), + "verify_blob_kzg_proof_batch" => check_verify_blob_kzg_proof_batch(input, output), + "compute_challenge" => check_compute_challenge(input, output), + "compute_cells" => check_compute_cells(input, output), + "compute_cells_and_kzg_proofs" => check_compute_cells_and_kzg_proofs(input, output), + "recover_cells_and_kzg_proofs" => check_recover_cells_and_kzg_proofs(input, output), + "verify_cell_kzg_proof_batch" => check_verify_cell_kzg_proof_batch(input, output), + "compute_verify_cell_kzg_proof_batch_challenge" => { + check_compute_verify_cell_kzg_proof_batch_challenge(input, output) + } + // A fixture release that adds a thirteenth handler must fail loudly + // here rather than pass by never being dispatched: an unmatched + // handler has no check function to fall back on, unlike a fork this + // crate has not implemented yet, which `case_trial` marks ignored + // instead of failed. + other => Err(format!("unhandled kzg handler `{other}`")), + } +} + +pub fn trials() -> Vec { + let cases = collect_all_handlers("general", "kzg"); + let mut trials = vec![super::discovery_trial("kzg", cases.len())]; + + for (handler, case) in cases { + trials.push(super::case_trial("kzg", case, move |case| { + run(&handler, case) + })); + } + + trials +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec/mod.rs b/crates/blockchain/state_transition/tests/beacon_spec/mod.rs new file mode 100644 index 000000000..f35f365a0 --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/mod.rs @@ -0,0 +1,460 @@ +//! Loading the Ethereum consensus spec test fixtures. +//! +//! The fixture tree is the definition of correctness for this crate. Every +//! runner below discovers its cases from disk rather than listing them, so a +//! fixture release that adds cases is picked up without touching code, and a +//! suite that silently stops matching any case fails instead of reporting green. +//! +//! # Layout +//! +//! The three release tarballs all unpack to `tests//...`, so they extract +//! into one directory: +//! +//! ```text +//! consensus-spec-tests/tests/////// +//! ``` +//! +//! `` is `general` for the configuration-independent suites (BLS, KZG), +//! and the preset name otherwise. Since the preset is compiled in, a test run +//! walks only the tree matching its own build. +//! +//! # File formats +//! +//! State and container files are `.ssz_snappy`: SSZ, compressed with *raw* +//! snappy, not the framed format. Everything else is YAML. + +#![allow( + dead_code, + reason = "each runner uses a different part of this harness" +)] + +pub mod bls; +pub mod epoch_processing; +pub mod fork; +pub mod fork_choice; +pub mod genesis; +pub mod harness; +pub mod kzg; +pub mod operations; +pub mod rewards; +pub mod sanity; +pub mod shuffling; +pub mod ssz_static; +pub mod transition; + +use std::collections::BTreeSet; +use std::fs; +use std::path::{Path, PathBuf}; + +use ethlambda_state_transition::beacon::ForkName; +use ethlambda_state_transition::beacon::containers::BeaconState; +use libssz::SszDecode; +use libtest_mimic::{Failed, Trial}; +use serde::de::DeserializeOwned; + +/// The configuration directory whose fixtures match the compiled-in preset. +pub const PRESET: &str = if cfg!(feature = "preset-minimal") { + "minimal" +} else { + "mainnet" +}; + +/// The newest fork whose state transition this crate implements. +/// +/// Every runner gates on this, and a case past it becomes an ignored test +/// rather than a missing one, so the output can never imply more coverage than +/// exists. Turning on a fork is a one-line change here once its state +/// transition lands: bump this constant and every runner picks up that fork's +/// cases on its own, since [`case_trial`] reads the gate itself. A runner may +/// still need its own edit to *map* a fork's new or changed handlers to the +/// right function, since that mapping is specific to each runner; only the gate +/// is one line. +pub const HIGHEST_IMPLEMENTED_FORK: ForkName = ForkName::Fulu; + +/// The root of the extracted fixture tree. +/// +/// Panics rather than skipping when the fixtures are absent. A spec suite that +/// reports success because it found nothing to run is worse than one that fails. +pub fn fixture_root() -> PathBuf { + let root = Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../../../consensus-spec-tests") + .join("tests"); + assert!( + root.is_dir(), + "spec test fixtures are missing from {}; run `make consensus-spec-tests`", + root.display() + ); + root +} + +/// One fixture case: a directory of input and expected-output files. +#[derive(Debug, Clone)] +pub struct Case { + /// The case directory. + pub path: PathBuf, + /// The fork whose rules apply. + pub fork: ForkName, + /// The suite directory name, which groups related cases. + pub suite: String, + /// The case directory name, which is what test output should identify. + pub name: String, +} + +impl Case { + /// A human-readable identifier for failure messages. + /// + /// Includes the two directory levels above the case, since case names repeat + /// across handlers and a bare name would not say which one failed. + pub fn id(&self) -> String { + let handler = self + .path + .parent() + .and_then(|suite| suite.parent()) + .and_then(|handler| handler.file_name()) + .map(|name| name.to_string_lossy().into_owned()) + .unwrap_or_default(); + format!("{}/{}/{}/{}", self.fork, handler, self.suite, self.name) + } + + /// Whether the case carries the named file. + /// + /// Absence is meaningful: an operations case with no `post` expects the + /// operation to be rejected. + pub fn has(&self, name: &str) -> bool { + self.path.join(format!("{name}.ssz_snappy")).is_file() + || self.path.join(format!("{name}.yaml")).is_file() + } + + /// Reads and decompresses `.ssz_snappy`, returning the SSZ bytes. + /// + /// Containers whose shape depends on the fork are decoded by the caller, + /// which knows the fork, so this stops at the bytes. + pub fn ssz_bytes(&self, name: &str) -> Vec { + let path = self.path.join(format!("{name}.ssz_snappy")); + let compressed = + fs::read(&path).unwrap_or_else(|err| panic!("reading {}: {err}", path.display())); + snap::raw::Decoder::new() + .decompress_vec(&compressed) + .unwrap_or_else(|err| panic!("decompressing {}: {err}", path.display())) + } + + /// Decodes `.ssz_snappy` into a fork-independent container. + pub fn ssz(&self, name: &str) -> T { + let bytes = self.ssz_bytes(name); + T::from_ssz_bytes(&bytes) + .unwrap_or_else(|err| panic!("decoding {} of {}: {err:?}", name, self.id())) + } + + /// Decodes an indexed file such as `blocks_0.ssz_snappy`. + pub fn ssz_bytes_indexed(&self, name: &str, index: usize) -> Vec { + self.ssz_bytes(&format!("{name}_{index}")) + } + + /// Parses `.yaml`. + pub fn yaml(&self, name: &str) -> T { + let path = self.path.join(format!("{name}.yaml")); + let text = fs::read_to_string(&path) + .unwrap_or_else(|err| panic!("reading {}: {err}", path.display())); + serde_yaml_ng::from_str(&text) + .unwrap_or_else(|err| panic!("parsing {}: {err}", path.display())) + } + + /// Parses `.yaml` if it exists. + pub fn yaml_opt(&self, name: &str) -> Option { + self.path + .join(format!("{name}.yaml")) + .is_file() + .then(|| self.yaml(name)) + } + + /// Whether this case's fork has a state transition this crate implements. + /// + /// The one gate every runner checks before running a case. Forks after + /// [`HIGHEST_IMPLEMENTED_FORK`] fail this, and [`case_trial`] marks such a + /// case ignored rather than running it, so a fixture release this crate has + /// only partially caught up with is never misreported as fully covered. + pub fn in_scope(&self) -> bool { + self.fork <= HIGHEST_IMPLEMENTED_FORK + } +} + +/// Collects every case for one runner and handler across all supported forks. +/// +/// `config` selects the fixture tree: [`PRESET`] for the preset-dependent +/// suites, or `"general"` for the configuration-independent ones. Forks this +/// crate does not implement are skipped, so an upstream release that adds a fork +/// does not break the build. +pub fn collect(config: &str, runner: &str, handler: &str) -> Vec { + let root = fixture_root().join(config); + let mut cases = Vec::new(); + + for fork_entry in read_dir_sorted(&root) { + let Some(fork) = fork_entry.file_name().to_str().and_then(ForkName::parse) else { + continue; + }; + + let handler_dir = fork_entry.path().join(runner).join(handler); + collect_suites(&handler_dir, fork, &mut |case| cases.push(case)); + } + + cases +} + +/// Collects cases for one runner across every handler it has. +/// +/// Returns pairs of handler name and case, which suits runners like +/// `epoch_processing` where the handler names the sub-function under test. +pub fn collect_all_handlers(config: &str, runner: &str) -> Vec<(String, Case)> { + let root = fixture_root().join(config); + let mut out = Vec::new(); + + for fork_entry in read_dir_sorted(&root) { + let Some(fork) = fork_entry.file_name().to_str().and_then(ForkName::parse) else { + continue; + }; + let runner_dir = fork_entry.path().join(runner); + if !runner_dir.is_dir() { + continue; + } + + for handler_entry in read_dir_sorted(&runner_dir) { + let handler = handler_entry.file_name().to_string_lossy().into_owned(); + // Walk this fork's handler directory directly. Delegating to + // `collect` here would be wrong: `collect` walks every fork itself, + // so nesting it inside this fork loop would yield each case once per + // fork that happens to ship the runner. + collect_suites(&handler_entry.path(), fork, &mut |case| { + out.push((handler.clone(), case)) + }); + } + } + + out +} + +/// Walks the suite and case directories under one fork's handler directory. +/// +/// Shared by both collectors so there is one definition of what a case directory +/// is, and so neither can drift from the other. +fn collect_suites(handler_dir: &Path, fork: ForkName, emit: &mut impl FnMut(Case)) { + if !handler_dir.is_dir() { + return; + } + + for suite_entry in read_dir_sorted(handler_dir) { + let suite = suite_entry.file_name().to_string_lossy().into_owned(); + for case_entry in read_dir_sorted(&suite_entry.path()) { + emit(Case { + path: case_entry.path(), + fork, + suite: suite.clone(), + name: case_entry.file_name().to_string_lossy().into_owned(), + }); + } + } +} + +/// Directory entries, sorted, so a failing run is reproducible and its output +/// is comparable between runs. +fn read_dir_sorted(path: &Path) -> Vec { + let mut entries: Vec<_> = match fs::read_dir(path) { + Ok(entries) => entries.filter_map(Result::ok).collect(), + Err(_) => return Vec::new(), + }; + entries.sort_by_key(fs::DirEntry::file_name); + entries +} + +/// Fixture fork directories this crate deliberately does not model. +/// +/// `gloas` is the fork after fulu, and this crate stops at fulu. `eip7805` is not +/// a fork in the sequence at all: the release ships a directory per in-flight EIP +/// whose cases are generated against a variant of some fork's rules, so there is +/// no [`ForkName`] for it to parse as. +/// +/// Naming them is not bookkeeping for its own sake. A directory [`ForkName::parse`] +/// does not recognize is how [`collect`] skips a fork, and that skip is *silent* +/// in a way [`Case::in_scope`] is not: the cases never become tests at all, so +/// they are not counted as ignored either, and nothing in the output says they +/// exist. This module's own doc promises the opposite, that a suite which stops +/// matching fails rather than reporting green, and an unparsed fork slips past +/// [`HIGHEST_IMPLEMENTED_FORK`] entirely because the gate never sees the case. +/// So [`fixture_fork_trials`] checks this list against the tree instead. +pub const UNMODELED_FORKS: &[&str] = &["gloas", "eip7805"]; + +/// Panics: a fixture case cannot be a lean case. +/// +/// [`ForkName`] carries a `Lean` variant, because `ethlambda-types` holds one +/// fork name for both chains, so every match on a case's own fork needs an arm +/// for it. No case can ever take that arm: a case's fork comes from +/// [`ForkName::parse`] on a fixture directory name, and `Lean` is deliberately +/// absent from `ForkName::ALL`, which is what `parse` searches. Written once +/// here rather than as a catch-all `_` at each site, so that a *real* fork added +/// to the enum still breaks every match that has to grow an arm for it. +/// +/// `#[track_caller]` so the panic reports the runner's own arm rather than this +/// file, matching the two functions the module under test uses for its own +/// lean arms. +#[cold] +#[track_caller] +pub fn lean_is_not_a_fixture_fork(handler: &str) -> ! { + unreachable!( + "ForkName::Lean reached the {handler} fixture handler; \ + a case's fork is parsed from a directory name, and lean is not one" + ) +} + +/// Accounts for every fork directory the fixture release ships. +/// +/// Reports each directory in [`UNMODELED_FORKS`] as an ignored test, so a +/// deliberate exclusion is visible in the output rather than inferred from its +/// absence, and fails when the tree holds a fork directory that is neither +/// parseable nor listed. That failure is the point: a release that adds a fork +/// would otherwise have its cases skipped without a trace, and someone has to +/// decide whether to implement it or name it here. +pub fn fixture_fork_trials() -> Vec { + let mut unknown: Vec = Vec::new(); + let mut unmodeled: BTreeSet = BTreeSet::new(); + + // Both trees, since `collect` is called with `general` for the + // configuration-independent suites as well as with the preset's own name. + for config in [PRESET, "general"] { + for entry in read_dir_sorted(&fixture_root().join(config)) { + if !entry.path().is_dir() { + continue; + } + let name = entry.file_name().to_string_lossy().into_owned(); + if ForkName::parse(&name).is_some() { + continue; + } + if UNMODELED_FORKS.contains(&name.as_str()) { + unmodeled.insert(name); + } else { + unknown.push(format!("{config}/{name}")); + } + } + } + + let mut trials: Vec = unmodeled + .into_iter() + .map(|name| { + Trial::test(format!("fixture_forks/unmodeled/{name}"), || Ok(())) + .with_ignored_flag(true) + }) + .collect(); + + trials.push(Trial::test( + "fixture_forks/every_directory_is_accounted_for", + move || { + if unknown.is_empty() { + return Ok(()); + } + Err(Failed::from(format!( + "the fixture release ships fork directories this harness neither parses nor \ + lists in UNMODELED_FORKS, so every case under them is skipped without \ + appearing anywhere in the output: {}", + unknown.join(", ") + ))) + }, + )); + + trials +} + +/// Wraps one fixture case as a test of its own. +/// +/// Each case becomes a separate entry in the test binary, named for the case +/// rather than for the suite around it, so a failure points at the one case that +/// failed and every other case in that suite still reports its own result. The +/// suites used to be one test apiece, aggregating outcomes and failing as a +/// whole, which meant a single bad case marked thousands of passing ones as part +/// of a failed test and the name in the output was the suite's. +/// +/// The name is prefixed with `runner` so that a filter can select a whole suite +/// (`cargo test --test spec_tests -- operations`) as well as one case. The +/// runner name is not part of [`Case::id`], which starts at the fork, so nothing +/// is repeated here. +/// +/// A case whose fork this crate does not implement is marked ignored rather than +/// run, which is what [`Case::in_scope`] gates. The harness used to tally those +/// itself and print the count; the test harness counts ignored tests already, +/// and names each one, which is strictly more than the tally said. +/// +/// A panic inside `run` fails this case alone: the harness catches it per test. +/// So a fixture that will not decode takes its own case down and no other. +pub fn case_trial( + runner: &str, + case: Case, + run: impl FnOnce(&Case) -> Result<(), String> + Send + 'static, +) -> Trial { + let ignored = !case.in_scope(); + let name = format!("{runner}/{}", case.id()); + Trial::test(name, move || run(&case).map_err(Failed::from)).with_ignored_flag(ignored) +} + +/// Asserts a suite matched at least one fixture case. +/// +/// The aggregate each suite used to report through carried this check, and +/// dropping it along with that aggregate would have quietly given up the thing +/// it guarded: a suite whose +/// fixtures moved, or whose runner or handler name went stale upstream, matches +/// nothing, and a run of no cases at all passes. Per-case tests make that worse +/// rather than better, since a suite that matches nothing now contributes no +/// tests to even look for. Hence one test per suite whose whole job is to fail +/// when the suite is empty. +/// +/// A case that matched but was skipped still counts as matching: the fixture +/// layout is fine, this crate just does not implement that fork yet, which is +/// what the ignored tests report. +pub fn discovery_trial(runner: &str, matched: usize) -> Trial { + let runner = runner.to_string(); + Trial::test(format!("{runner}/matched_fixture_cases"), move || { + if matched == 0 { + return Err(Failed::from(format!( + "{runner} matched no fixture cases; the fixture layout or the suite name is wrong" + ))); + } + Ok(()) + }) +} + +/// Judges a state transition against what the case expects. +/// +/// The rule the whole fixture format rests on: a case with a `post` state must +/// succeed and land exactly on it, and a case *without* one must be rejected. +/// Getting the second half right is what keeps the suites honest, since an +/// implementation that accepted everything would otherwise pass every case that +/// ships a `post`. +/// +/// Comparison is by `hash_tree_root` rather than field by field, because that is +/// the value consensus actually agrees on, and a mismatch anywhere in the state +/// changes it. +pub fn check_transition( + case: &Case, + outcome: Result<(), String>, + state: &BeaconState, +) -> Result<(), String> { + match (case.has("post"), outcome) { + (true, Ok(())) => { + let expected = BeaconState::from_ssz(case.fork, &case.ssz_bytes("post")) + .map_err(|err| format!("the fixture's post-state does not decode: {err:?}"))?; + let actual_root = state.hash_tree_root(); + let expected_root = expected.hash_tree_root(); + if actual_root != expected_root { + return Err(format!( + "post-state root 0x{} != expected 0x{}", + hex::encode(actual_root.0), + hex::encode(expected_root.0) + )); + } + Ok(()) + } + (true, Err(err)) => Err(format!( + "rejected, but the case expects a post-state: {err}" + )), + (false, Ok(())) => { + Err("accepted, but the case has no post-state, so it must be rejected".to_string()) + } + (false, Err(_)) => Ok(()), + } +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec/operations.rs b/crates/blockchain/state_transition/tests/beacon_spec/operations.rs new file mode 100644 index 000000000..83c640828 --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/operations.rs @@ -0,0 +1,500 @@ +//! The `operations` runner. +//! +//! Each case holds a `pre` state, one operation, and a `post` state. The absence +//! of `post` is the assertion: the operation must be rejected, and a run that +//! accepts it fails. That makes this suite the crate's main check that invalid +//! input is refused rather than absorbed, so the "expected rejection" path gets +//! as much attention here as the success path. +//! +//! The handler names the operation, and the operation's file is named after the +//! handler, except `block_header` (a whole block), `execution_payload` (a whole +//! body, since checking a payload needs the block's blob commitments and, for +//! deneb on, occasionally the version raising that count), and `withdrawals` +//! (a bare `ExecutionPayload`, since the sweep needs nothing else from the +//! body) and `bls_to_execution_change` (named `address_change` in the fixture +//! tree). +//! +//! Unlike [`super::sanity`], which runs whole blocks through +//! [`ethlambda_state_transition::beacon::stf::state_transition`], this calls each operation's own +//! function directly, so nothing here can lean on `process_block`'s per-fork +//! dispatch: every handler that changed shape or behavior between forks has to +//! be routed to the right function by hand, keyed on [`Case::fork`]. Each +//! routing decision below is justified by a "Modified" or "New" marker in the +//! pinned specification's own table of contents for that fork, not by +//! inspection of this crate's source; a handler with no such marker for a +//! given fork keeps calling whichever earlier fork's function last introduced +//! or changed it. +//! +//! - `proposer_slashing` needs no routing at all: no fork's specification ever +//! lists a modified `process_proposer_slashing`, so phase0's function serves +//! every fork this crate implements. +//! - `attester_slashing` and `deposit` need no *function* routing through +//! deneb (neither fork's specification lists either as modified before +//! electra), but `attester_slashing`'s container does change shape at +//! electra (see below), and electra's own specification lists both +//! `process_attester_slashing` (transcribed against the new container, not +//! behaviorally different) and `process_deposit` (behaviorally different: +//! a deposit is queued rather than credited) as its own functions from +//! there on. +//! - `attestation` needs both. The container +//! ([`phase0::Attestation`]) is the one phase0, altair, bellatrix, capella, +//! and deneb all share, and [`electra::Attestation`] (EIP-7549's committee +//! bitfield) takes over at electra. *How* an attestation is scored changes +//! twice more within that container-stable range: phase0 defers to the +//! epoch boundary ([`operations::process_attestation`]), altair scores it +//! immediately ([`altair_stf::process_attestation`]) and that version +//! serves bellatrix and capella too since neither fork's specification +//! modifies it again, and deneb widens the inclusion window and the +//! timely-target condition (EIP-7045) with its own version +//! ([`deneb_stf::process_attestation`]). Calling an earlier fork's version +//! on a later case would not even fail loudly in every instance, since it +//! would return [`ethlambda_state_transition::beacon::Error::UnsupportedForFork`] only where +//! the two forks' state shapes actually differ, which is still a rejection, +//! just not the one the fixture is testing for. +//! - `voluntary_exit` changes twice after phase0: deneb pins the signature to +//! a fixed fork version for EIP-7044, and electra adds a +//! pending-partial-withdrawal check and swaps in electra's own +//! exit-queue accounting for EIP-7251. +//! - `block_header`'s file is a whole `BeaconBlock`, and that type is +//! different per fork (altair's carries a `sync_aggregate` its body root +//! folds in, bellatrix's an execution payload on top of that, and so on). +//! [`block::process_block_header`] itself takes only the four +//! fork-invariant fields a header needs, not a block, precisely so this +//! runner (and every per-fork `process_block_*` driver) can decode with the +//! fork's own concrete type and still call one shared function. +//! - `sync_aggregate` is new in altair, with no phase0 case, and no later +//! fork's specification ever lists a modified version of it, so it needs +//! no fork match beyond that. +//! - `execution_payload` is new in bellatrix and its specification lists a +//! modified version at every fork from capella on: capella and later drop +//! the still-mid-merge-transition check, deneb folds in the blob +//! commitment count, electra reads a different configuration field for +//! that same count, and fulu reads a schedule instead of a fixed field. +//! Five forks, five distinct functions, none reusable for another fork's +//! case. +//! - `bls_to_execution_change` and `withdrawals` are both new in capella. +//! `bls_to_execution_change` is never listed as modified again: its +//! function reads and writes only fork-invariant fields, so capella's own +//! serves every later fork too. `withdrawals` is listed as modified once +//! more, at electra (EIP-7251's partial-withdrawal queue); deneb's own +//! specification lists no change to it at all, so deneb's copy exists only +//! to hold a differently-typed `payload` parameter, not different logic. +//! - `consolidation_request`, `deposit_request`, and `withdrawal_request` are +//! all new in electra, alongside `withdrawals`, `process_attestation`, +//! `process_deposit`, and `process_voluntary_exit`; fulu's specification +//! lists none of the seven as modified again, so electra's functions serve +//! fulu's cases too. +use std::sync::Arc; + +use ethlambda_state_transition::beacon::ForkName; +use ethlambda_state_transition::beacon::config::Config; +use ethlambda_state_transition::beacon::containers::{ + BeaconState, altair, bellatrix, capella, deneb, electra, phase0, shared, +}; +use ethlambda_state_transition::beacon::primitives::HashTreeRoot as _; +use ethlambda_state_transition::beacon::stf::altair as altair_stf; +use ethlambda_state_transition::beacon::stf::bellatrix as bellatrix_stf; +use ethlambda_state_transition::beacon::stf::capella as capella_stf; +use ethlambda_state_transition::beacon::stf::deneb as deneb_stf; +use ethlambda_state_transition::beacon::stf::electra as electra_stf; +use ethlambda_state_transition::beacon::stf::fulu as fulu_stf; +use ethlambda_state_transition::beacon::stf::{ExecutionEngine, block, operations}; +use libtest_mimic::{Failed, Trial}; + +use super::{Case, PRESET, collect_all_handlers, lean_is_not_a_fixture_fork}; + +/// The `{execution_valid: bool}` an `execution_payload` case ships alongside +/// its block, standing in for whatever a real execution client would have +/// answered. See [`ExecutionEngine`]'s own documentation for why this crate +/// collapses that whole interface to one boolean. +#[derive(serde::Deserialize)] +struct ExecutionYaml { + execution_valid: bool, +} + +/// Applies one operation to the case's pre-state. +/// +/// Returns the post-state on success. Anything the crate rejects comes back as an +/// error, which the caller compares against whether the case has a `post`. +fn apply( + handler: &str, + case: &Case, + state: &mut BeaconState, + config: &Config, +) -> Result<(), String> { + let outcome = match handler { + // Every fork's own `BeaconBlock` carries a different concrete body + // (altair's adds a sync aggregate, bellatrix's an execution payload, + // and so on), but `process_block_header` reads only the four + // fork-invariant fields below, so decoding with the fork's own type + // and then handing those four fields to one shared function is all + // this needs; see this module's own documentation. + "block_header" => match case.fork { + ForkName::Phase0 => { + let block: phase0::BeaconBlock = case.ssz("block"); + block::process_block_header( + state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + ) + } + ForkName::Altair => { + let block: altair::BeaconBlock = case.ssz("block"); + block::process_block_header( + state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + ) + } + ForkName::Bellatrix => { + let block: bellatrix::BeaconBlock = case.ssz("block"); + block::process_block_header( + state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + ) + } + ForkName::Capella => { + let block: capella::BeaconBlock = case.ssz("block"); + block::process_block_header( + state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + ) + } + ForkName::Deneb => { + let block: deneb::BeaconBlock = case.ssz("block"); + block::process_block_header( + state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + ) + } + // Electra and fulu share one `BeaconBlock`: fulu's specification + // changes nothing about the block or body shape, only + // `process_execution_payload` (see the `execution_payload` arm + // below), so there is no `fulu::BeaconBlock` to decode. + ForkName::Electra | ForkName::Fulu => { + let block: electra::BeaconBlock = case.ssz("block"); + block::process_block_header( + state, + block.slot, + block.proposer_index, + block.parent_root, + block.body.hash_tree_root(), + ) + } + // No `other` arm: the patterns above already cover every `ForkName` + // there is, so a catch-all here would be dead code rather than a + // safety net. `Lean` is covered by name for the same reason, rather + // than swept into one; see `lean_is_not_a_fixture_fork`. + ForkName::Lean => lean_is_not_a_fixture_fork("block_header"), + }, + "attestation" => match case.fork { + // Phase0 defers every attestation's reward to the epoch boundary. + ForkName::Phase0 => { + let attestation: phase0::Attestation = case.ssz("attestation"); + operations::process_attestation(state, &attestation, config) + } + // Altair scores an attestation immediately instead, and neither + // bellatrix's nor capella's specification lists a further change, + // so altair's own function serves both. + ForkName::Altair | ForkName::Bellatrix | ForkName::Capella => { + let attestation: phase0::Attestation = case.ssz("attestation"); + altair_stf::process_attestation(state, &attestation) + } + // Deneb widens the inclusion window and the timely-target + // condition (EIP-7045); the container is still phase0's. + ForkName::Deneb => { + let attestation: phase0::Attestation = case.ssz("attestation"); + deneb_stf::process_attestation(state, &attestation) + } + // Electra reshapes the container itself (EIP-7549's + // `committee_bits`), and fulu's specification makes no further + // change to either the container or the function. + ForkName::Electra | ForkName::Fulu => { + let attestation: electra::Attestation = case.ssz("attestation"); + electra_stf::process_attestation(state, &attestation) + } + ForkName::Lean => lean_is_not_a_fixture_fork("attestation"), + }, + "attester_slashing" => match case.fork { + // Unchanged from phase0 through deneb, container included. + ForkName::Phase0 + | ForkName::Altair + | ForkName::Bellatrix + | ForkName::Capella + | ForkName::Deneb => { + let slashing: phase0::AttesterSlashing = case.ssz("attester_slashing"); + operations::process_attester_slashing(state, &slashing, config) + } + // Electra's container widens the same way `Attestation`'s does + // (see the `attestation` arm above); the function itself is not + // behaviorally modified, only transcribed against the new type. + // Fulu's specification changes neither. + ForkName::Electra | ForkName::Fulu => { + let slashing: electra::AttesterSlashing = case.ssz("attester_slashing"); + electra_stf::process_attester_slashing(state, &slashing, config) + } + ForkName::Lean => lean_is_not_a_fixture_fork("attester_slashing"), + }, + // `ProposerSlashing` never changes shape, and no fork's specification + // ever lists a modified `process_proposer_slashing`, so this needs no + // per-fork routing at all. + "proposer_slashing" => { + let slashing: shared::ProposerSlashing = case.ssz("proposer_slashing"); + operations::process_proposer_slashing(state, &slashing, config) + } + "deposit" => match case.fork { + // The `Deposit` container never changes shape; through deneb a + // deposit's amount is credited the moment it is processed. + ForkName::Phase0 + | ForkName::Altair + | ForkName::Bellatrix + | ForkName::Capella + | ForkName::Deneb => { + let deposit: shared::Deposit = case.ssz("deposit"); + operations::process_deposit(state, &deposit, config) + } + // Electra queues a deposit's amount instead of crediting it + // directly (EIP-7251), so the epoch boundary can rate-limit + // activation by balance rather than by validator count; fulu's + // specification makes no further change. + ForkName::Electra | ForkName::Fulu => { + let deposit: shared::Deposit = case.ssz("deposit"); + electra_stf::process_deposit(state, &deposit, config) + } + ForkName::Lean => lean_is_not_a_fixture_fork("deposit"), + }, + "voluntary_exit" => match case.fork { + // Unchanged through capella. + ForkName::Phase0 | ForkName::Altair | ForkName::Bellatrix | ForkName::Capella => { + let exit: shared::SignedVoluntaryExit = case.ssz("voluntary_exit"); + operations::process_voluntary_exit(state, &exit, config) + } + // Deneb pins the signature to `CAPELLA_FORK_VERSION` (EIP-7044), + // so an exit signed long before it takes effect never expires + // out from under its own signer at a later fork boundary. + ForkName::Deneb => { + let exit: shared::SignedVoluntaryExit = case.ssz("voluntary_exit"); + deneb_stf::process_voluntary_exit(state, &exit, config) + } + // Electra adds a pending-partial-withdrawal check and its own + // balance-churn exit-queue accounting (EIP-7251); fulu's + // specification changes neither. + ForkName::Electra | ForkName::Fulu => { + let exit: shared::SignedVoluntaryExit = case.ssz("voluntary_exit"); + electra_stf::process_voluntary_exit(state, &exit, config) + } + ForkName::Lean => lean_is_not_a_fixture_fork("voluntary_exit"), + }, + // New in altair, and never listed as modified again, so this needs no + // further fork match. + "sync_aggregate" => { + let sync_aggregate: altair::SyncAggregate = case.ssz("sync_aggregate"); + altair_stf::process_sync_aggregate(state, &sync_aggregate) + } + // The fixture's operation file is a whole `BeaconBlockBody`, not a + // bare payload: checking one needs fields that live on the body + // alongside it (deneb's and later's blob commitments), not on the + // payload itself. See this module's own documentation for why every + // fork from bellatrix on gets its own arm here. + "execution_payload" => { + let execution: ExecutionYaml = case.yaml("execution"); + let engine = ExecutionEngine { + execution_valid: execution.execution_valid, + }; + match case.fork { + ForkName::Bellatrix => { + let body: bellatrix::BeaconBlockBody = case.ssz("body"); + bellatrix_stf::process_execution_payload( + state, + &body.execution_payload, + config, + &engine, + ) + } + // Capella's specification drops the still-mid-merge-transition + // check bellatrix's version makes, on the grounds that no + // chain reaching capella can still be pre-merge. + ForkName::Capella => { + let body: capella::BeaconBlockBody = case.ssz("body"); + capella_stf::process_execution_payload( + state, + &body.execution_payload, + config, + &engine, + ) + } + // Deneb adds the blob commitment count check (EIP-4844), + // which reads the body's own `blob_kzg_commitments` rather + // than anything on the payload. + ForkName::Deneb => { + let body: deneb::BeaconBlockBody = case.ssz("body"); + deneb_stf::process_execution_payload( + state, + &body.execution_payload, + &body.blob_kzg_commitments, + config, + &engine, + ) + } + // Electra reads a configuration field of its own for that + // same count (EIP-7691) rather than deneb's fixed one, so it + // is not deneb's function under a new name; both take the + // whole body directly instead of a payload and a commitment + // list separately. + ForkName::Electra => { + let body: electra::BeaconBlockBody = case.ssz("body"); + electra_stf::process_execution_payload(state, &body, config, &engine) + } + // Fulu reads a schedule-aware limit instead of electra's + // fixed configuration field (EIP-7892), and carries no + // `BeaconBlockBody` of its own to decode, since fulu changes + // nothing else about the block or body shape. + ForkName::Fulu => { + let body: electra::BeaconBlockBody = case.ssz("body"); + fulu_stf::process_execution_payload(state, &body, config, &engine) + } + other => { + return Err(format!( + "execution_payload has no handler for fork `{other}`" + )); + } + } + } + // New in capella, named `address_change` in the fixture tree even + // though the handler is `bls_to_execution_change`. Reads and writes + // only fork-invariant fields (the validator registry and the + // genesis validators root), and no later fork's specification lists + // a modified version, so capella's own function serves every fork + // from here on. + "bls_to_execution_change" => { + let signed_change: capella::SignedBLSToExecutionChange = case.ssz("address_change"); + capella_stf::process_bls_to_execution_change(state, &signed_change, config) + } + "withdrawals" => match case.fork { + ForkName::Capella => { + let payload: capella::ExecutionPayload = case.ssz("execution_payload"); + capella_stf::process_withdrawals(state, &payload) + } + // Deneb's own specification lists no modified `process_withdrawals` + // at all: this is identical to capella's beyond the type of + // `payload` it takes, since `payload.withdrawals` has to compare + // against a `deneb::ExecutionPayload`, a different Rust type from + // `capella::ExecutionPayload` even though both alias the same + // element type for the list itself. + ForkName::Deneb => { + let payload: deneb::ExecutionPayload = case.ssz("execution_payload"); + deneb_stf::process_withdrawals(state, &payload) + } + // Electra adds the partial-withdrawal queue sweep (EIP-7251); + // fulu's specification changes nothing further, and both share + // deneb's `ExecutionPayload` type for the `payload` parameter, + // the same reuse `execution_payload`'s electra arm above relies + // on. + ForkName::Electra | ForkName::Fulu => { + let payload: deneb::ExecutionPayload = case.ssz("execution_payload"); + electra_stf::process_withdrawals(state, &payload) + } + other => return Err(format!("withdrawals has no handler for fork `{other}`")), + }, + // All three are new in electra, alongside `withdrawals`; fulu's + // specification lists none of them as modified, so electra's own + // functions serve fulu's cases too. + "consolidation_request" => { + let request: electra::ConsolidationRequest = case.ssz("consolidation_request"); + electra_stf::process_consolidation_request(state, &request, config) + } + "deposit_request" => { + let request: electra::DepositRequest = case.ssz("deposit_request"); + electra_stf::process_deposit_request(state, &request) + } + "withdrawal_request" => { + let request: electra::WithdrawalRequest = case.ssz("withdrawal_request"); + electra_stf::process_withdrawal_request(state, &request, config) + } + other => return Err(format!("unhandled operation `{other}`")), + }; + + outcome.map_err(|err| format!("{err:?}")) +} + +pub fn trials() -> Vec { + let config = Arc::new(Config::active()); + let cases = collect_all_handlers(PRESET, "operations"); + let mut trials = vec![super::discovery_trial("operations", cases.len())]; + + for (handler, case) in cases { + let config = Arc::clone(&config); + trials.push(super::case_trial("operations", case, move |case| { + let mut state = BeaconState::from_ssz(case.fork, &case.ssz_bytes("pre")) + .map_err(|err| format!("the fixture's pre-state does not decode: {err:?}"))?; + + let outcome = apply(&handler, case, &mut state, &config); + super::check_transition(case, outcome, &state) + })); + } + + trials.push(Trial::test( + "operations/every_shipped_handler_is_dispatched", + every_shipped_handler_is_dispatched, + )); + + trials +} + +/// Handlers the fixture release ships that this runner does not dispatch. +/// +/// A missing arm in [`apply`] would otherwise be reported per case as a +/// failure, which is correct but noisy. This asserts the set of handlers is +/// the one the runner knows about, so a fixture release that adds an +/// operation fails here, once, with a clear message. The list is flat across +/// forks (it does not say which handler belongs to which fork) because that +/// is exactly what [`apply`]'s per-handler, per-fork match already encodes +/// and enforces at run time; duplicating it here would only give the two a +/// chance to drift apart. +fn every_shipped_handler_is_dispatched() -> Result<(), Failed> { + let known = [ + "attestation", + "attester_slashing", + "block_header", + "bls_to_execution_change", + "consolidation_request", + "deposit", + "deposit_request", + "execution_payload", + "proposer_slashing", + "sync_aggregate", + "voluntary_exit", + "withdrawal_request", + "withdrawals", + ]; + + let mut unknown: Vec = collect_all_handlers(PRESET, "operations") + .into_iter() + .filter(|(_, case): &(String, Case)| case.in_scope()) + .map(|(handler, _)| handler) + .filter(|handler| !known.contains(&handler.as_str())) + .collect(); + unknown.sort_unstable(); + unknown.dedup(); + + if !unknown.is_empty() { + return Err(Failed::from(format!( + "the fixture release ships operations this runner does not dispatch: {unknown:?}" + ))); + } + + Ok(()) +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec/rewards.rs b/crates/blockchain/state_transition/tests/beacon_spec/rewards.rs new file mode 100644 index 000000000..d97853f54 --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/rewards.rs @@ -0,0 +1,191 @@ +//! The `rewards` runner. +//! +//! Unlike the other suites, these cases do not compare states. They compare +//! per-component delta vectors directly, each as a `Deltas` container of +//! rewards and penalties indexed by validator. That is a much sharper instrument +//! than a post-state comparison: `process_rewards_and_penalties` sums every +//! component into balances, so a sign error in one component and a compensating +//! error in another would produce the right balances and the wrong deltas. +//! +//! Phase0 and altair ship different components, because altair pays an +//! attestation's reward the moment it is included rather than at the epoch +//! boundary (see [`super::epoch_processing`]'s module doc for the same point +//! made about the epoch-processing steps this reward change is entangled +//! with). Phase0 ships `source_deltas`, `target_deltas`, `head_deltas`, +//! `inclusion_delay_deltas`, and `inactivity_penalty_deltas`. Altair ships the +//! same five minus `inclusion_delay_deltas`, since there is no inclusion-delay +//! reward left to isolate once inclusion itself is when the reward is paid; +//! its first three come from +//! [`altair_helpers::get_flag_index_deltas`] called once per timeliness flag +//! (source, target, head, in that order), and its `inactivity_penalty_deltas` +//! from [`altair_helpers::get_inactivity_penalty_deltas`]. [`components`] +//! below is where each fork's file list is declared, so the absence of +//! `inclusion_delay_deltas` for altair is an expected shape, not a missing +//! file to fall back from. +//! +//! Every fork's own `beacon-chain.md` was checked for a "Modified" +//! `get_flag_index_deltas` or `get_inactivity_penalty_deltas` section, since +//! either would mean altair's four-file shape stops applying somewhere past +//! it. Only bellatrix's carries one, "Modified `get_inactivity_penalty_deltas`", +//! and the change it documents is a swapped denominator constant +//! (`INACTIVITY_PENALTY_QUOTIENT_BELLATRIX` for +//! `INACTIVITY_PENALTY_QUOTIENT_ALTAIR`), not a different set of files or a +//! different function shape; capella, deneb, electra, and fulu redefine +//! neither function at all. So altair's four components, and the two helper +//! functions that produce them, serve every fork through fulu; the fixture +//! directories confirm this, shipping the same four files from altair on. + +use std::sync::Arc; + +use ethlambda_state_transition::beacon::ForkName; +use ethlambda_state_transition::beacon::Result as BeaconResult; +use ethlambda_state_transition::beacon::config::Config; +use ethlambda_state_transition::beacon::constants::{ + TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX, TIMELY_TARGET_FLAG_INDEX, +}; +use ethlambda_state_transition::beacon::containers::BeaconState; +use ethlambda_state_transition::beacon::helpers::altair as altair_helpers; +use ethlambda_state_transition::beacon::preset; +use ethlambda_state_transition::beacon::primitives::Gwei; +use ethlambda_state_transition::beacon::stf::epoch::rewards; +use libssz::SszDecode; +use libssz_derive::{HashTreeRoot, SszDecode, SszEncode}; +use libssz_types::SszList; +use libtest_mimic::Trial; + +use super::{PRESET, collect_all_handlers, lean_is_not_a_fixture_fork}; + +/// One component's reward and penalty per validator, as the fixtures encode it. +/// +/// Declared here rather than in the crate because the specification has no such +/// container: it is purely how the test format packages the two vectors that +/// every delta function returns as a pair. +#[derive(Debug, Clone, PartialEq, Eq, SszEncode, SszDecode, HashTreeRoot)] +struct Deltas { + rewards: SszList, + penalties: SszList, +} + +/// One delta function's output: a reward and a penalty per validator. +type DeltaPair = (Vec, Vec); + +/// Compares one component against its fixture file. +fn compare(name: &str, expected: &Deltas, actual: &DeltaPair) -> Result<(), String> { + let (rewards, penalties) = actual; + + for (label, computed, want) in [ + ("rewards", rewards, &*expected.rewards), + ("penalties", penalties, &*expected.penalties), + ] { + if computed.len() != want.len() { + return Err(format!( + "{name} {label}: {} entries, expected {}", + computed.len(), + want.len() + )); + } + // Report the first differing validator rather than the whole vector, + // since a systematic error differs at every index and the first one is + // enough to find it. + if let Some((index, (got, want))) = computed + .iter() + .zip(want.iter()) + .enumerate() + .find(|(_, (got, want))| got != want) + { + return Err(format!( + "{name} {label}: validator {index} got {got}, expected {want}" + )); + } + } + + Ok(()) +} + +/// The named delta components a fork's `rewards` cases ship, in the order the +/// fixture computed them. +/// +/// One place to look up "what should this fork's case directory hold," so +/// [`rewards`] itself does not have to know why the two lists differ. +fn components( + fork: ForkName, + state: &BeaconState, + config: &Config, +) -> Result, String> { + let raw: Vec<(&'static str, BeaconResult)> = match fork { + ForkName::Phase0 => vec![ + ("source_deltas", rewards::get_source_deltas(state, config)), + ("target_deltas", rewards::get_target_deltas(state, config)), + ("head_deltas", rewards::get_head_deltas(state, config)), + ( + "inclusion_delay_deltas", + rewards::get_inclusion_delay_deltas(state, config), + ), + ( + "inactivity_penalty_deltas", + rewards::get_inactivity_penalty_deltas(state, config), + ), + ], + // No `inclusion_delay_deltas` here: see this module's doc for why + // altair has nothing left for that component to compute. Bellatrix + // through fulu reuse this same list; see this module's doc for why + // none of them changes it. + ForkName::Altair + | ForkName::Bellatrix + | ForkName::Capella + | ForkName::Deneb + | ForkName::Electra + | ForkName::Fulu => vec![ + ( + "source_deltas", + altair_helpers::get_flag_index_deltas(state, TIMELY_SOURCE_FLAG_INDEX), + ), + ( + "target_deltas", + altair_helpers::get_flag_index_deltas(state, TIMELY_TARGET_FLAG_INDEX), + ), + ( + "head_deltas", + altair_helpers::get_flag_index_deltas(state, TIMELY_HEAD_FLAG_INDEX), + ), + ( + "inactivity_penalty_deltas", + altair_helpers::get_inactivity_penalty_deltas(state, config), + ), + ], + ForkName::Lean => lean_is_not_a_fixture_fork("rewards"), + }; + + raw.into_iter() + .map(|(name, result)| { + result + .map(|deltas| (name, deltas)) + .map_err(|err| format!("{name}: {err:?}")) + }) + .collect() +} + +pub fn trials() -> Vec { + let config = Arc::new(Config::active()); + let cases = collect_all_handlers(PRESET, "rewards"); + let mut trials = vec![super::discovery_trial("rewards", cases.len())]; + + for (_handler, case) in cases { + let config = Arc::clone(&config); + trials.push(super::case_trial("rewards", case, move |case| { + let state = BeaconState::from_ssz(case.fork, &case.ssz_bytes("pre")) + .map_err(|err| format!("the fixture's pre-state does not decode: {err:?}"))?; + + for (name, computed) in components(case.fork, &state, &config)? { + let bytes = case.ssz_bytes(name); + let expected = Deltas::from_ssz_bytes(&bytes) + .map_err(|err| format!("{name} does not decode: {err:?}"))?; + compare(name, &expected, &computed)?; + } + + Ok(()) + })); + } + + trials +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec/sanity.rs b/crates/blockchain/state_transition/tests/beacon_spec/sanity.rs new file mode 100644 index 000000000..5ce056006 --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/sanity.rs @@ -0,0 +1,93 @@ +//! The `sanity`, `finality`, and `random` runners. +//! +//! All three have the same shape, so they share one implementation: a `pre` +//! state, a sequence of blocks, and a `post` state, with the absence of `post` +//! meaning some block in the sequence must be rejected. They differ only in what +//! they choose to exercise, which is the whole point of keeping them separate +//! upstream: `finality` drives the four finalization rules, `random` drives +//! pseudo-random operation mixes, and `sanity` covers the ordinary cases. +//! +//! `sanity/slots` is the exception, advancing slots with no blocks at all, which +//! is what isolates epoch processing from block processing. +//! +//! Unlike the `operations` suite, these run the full [`state_transition`], so +//! they check the proposer signature and the committed `state_root` too. + +use std::sync::Arc; + +use ethlambda_state_transition::beacon::config::Config; +use ethlambda_state_transition::beacon::containers::{BeaconState, SignedBeaconBlock}; +use ethlambda_state_transition::beacon::stf::{self, ExecutionEngine}; +use libtest_mimic::Trial; + +use super::{Case, PRESET, collect}; + +#[derive(serde::Deserialize)] +struct BlocksMeta { + blocks_count: usize, +} + +/// Applies every block in the case, stopping at the first one rejected. +fn apply_blocks(case: &Case, state: &mut BeaconState, config: &Config) -> Result<(), String> { + let meta: BlocksMeta = case.yaml("meta"); + + // `sanity/blocks`, `finality`, and `random` ship no `execution.yaml` + // (unlike the fork suites from bellatrix on that exercise + // `notify_new_payload`), so there is no engine answer to read from the + // case. A valid engine is the right default here: these cases are + // testing consensus-layer rules, not execution-payload rejection, so an + // engine that never objects keeps that variable out of the result. + let engine = ExecutionEngine::valid(); + + for index in 0..meta.blocks_count { + let bytes = case.ssz_bytes_indexed("blocks", index); + let block = SignedBeaconBlock::from_ssz(case.fork, &bytes) + .map_err(|err| format!("block {index} does not decode: {err:?}"))?; + + stf::state_transition(state, &block, true, config, &engine) + .map_err(|err| format!("block {index} rejected: {err:?}"))?; + } + + Ok(()) +} + +/// Advances the state by the case's slot count, applying no blocks. +fn apply_slots(case: &Case, state: &mut BeaconState, config: &Config) -> Result<(), String> { + // `slots.yaml` holds a bare integer, and it is a count to advance BY, not a + // slot to advance TO. + let count: u64 = case.yaml("slots"); + let target = state.slot() + count; + stf::process_slots(state, target, config).map_err(|err| format!("{err:?}")) +} + +/// Builds one runner and handler pair's trials, since all four share this shape. +fn run(runner: &str, handler: &str, slots: bool) -> Vec { + let config = Arc::new(Config::active()); + let cases = collect(PRESET, runner, handler); + let mut trials = vec![super::discovery_trial(runner, cases.len())]; + + for case in cases { + let config = Arc::clone(&config); + trials.push(super::case_trial(runner, case, move |case| { + let mut state = BeaconState::from_ssz(case.fork, &case.ssz_bytes("pre")) + .map_err(|err| format!("the fixture's pre-state does not decode: {err:?}"))?; + + let outcome = if slots { + apply_slots(case, &mut state, &config) + } else { + apply_blocks(case, &mut state, &config) + }; + super::check_transition(case, outcome, &state) + })); + } + + trials +} + +pub fn trials() -> Vec { + let mut trials = run("sanity", "blocks", false); + trials.extend(run("sanity", "slots", true)); + trials.extend(run("finality", "finality", false)); + trials.extend(run("random", "random", false)); + trials +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec/shuffling.rs b/crates/blockchain/state_transition/tests/beacon_spec/shuffling.rs new file mode 100644 index 000000000..dfe74ad1f --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/shuffling.rs @@ -0,0 +1,70 @@ +//! The `shuffling` runner. +//! +//! Each case gives a seed, a set size, and the full permutation the +//! specification's shuffle produces. `mapping[i]` is where index `i` ends up, so +//! checking every entry pins down `compute_shuffled_index` exactly, for every +//! index rather than for a sampled few. +//! +//! This is the only fixture suite that tests the shuffle directly. Everything +//! else depends on it only through committee assignment, where a subtle error +//! would show up as a confusing signature failure much later, so it is worth +//! getting green on its own before any of that is built. + +use ethlambda_state_transition::beacon::helpers::shuffling::compute_shuffled_index; +use ethlambda_state_transition::beacon::primitives::Root; +use libtest_mimic::Trial; + +use super::{PRESET, collect}; + +#[derive(serde::Deserialize)] +struct Mapping { + seed: String, + count: u64, + mapping: Vec, +} + +/// This suite is not gated here: [`super::case_trial`] applies +/// [`super::Case::in_scope`]'s gate itself, so every case collected below is +/// simply handed to it. +pub fn trials() -> Vec { + let cases = collect(PRESET, "shuffling", "core"); + let mut trials = vec![super::discovery_trial("shuffling", cases.len())]; + + for case in cases { + trials.push(super::case_trial("shuffling", case, move |case| { + let mapping: Mapping = case.yaml("mapping"); + + let stripped = mapping.seed.strip_prefix("0x").unwrap_or(&mapping.seed); + let seed_bytes = hex::decode(stripped).expect("the seed is a hex string"); + let seed = Root::from_slice(&seed_bytes); + + if mapping.mapping.len() as u64 != mapping.count { + return Err(format!( + "fixture claims count {} but lists {} entries", + mapping.count, + mapping.mapping.len() + )); + } + + for (index, expected) in mapping.mapping.iter().enumerate() { + let actual = compute_shuffled_index(index as u64, mapping.count, seed) + .map_err(|err| format!("index {index}: {err}"))?; + if actual != *expected { + return Err(format!( + "index {index} shuffled to {actual}, expected {expected}" + )); + } + } + + // An index at the boundary must be rejected rather than wrapping, + // which the fixtures do not cover but the specification asserts. + if compute_shuffled_index(mapping.count, mapping.count, seed).is_ok() { + return Err("an out-of-range index was accepted".to_string()); + } + + Ok(()) + })); + } + + trials +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec/ssz_static.rs b/crates/blockchain/state_transition/tests/beacon_spec/ssz_static.rs new file mode 100644 index 000000000..2e6a092ad --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/ssz_static.rs @@ -0,0 +1,349 @@ +//! The `ssz_static` runner. +//! +//! For each case: decode `serialized.ssz_snappy`, check its `hash_tree_root` +//! against `roots.yaml`, and check that re-encoding reproduces the fixture's +//! bytes exactly. That covers all three of the things a container has to get +//! right, and the round trip catches a field that decodes but encodes back +//! differently, which a root check alone can miss. +//! +//! The case's `value.yaml` is deliberately unused. Reading it would mean a serde +//! implementation for every container, and it tests nothing the other two files +//! do not already pin down. +//! +//! Containers this crate has not defined yet fail their own case instead of +//! being passed over quietly, so the output never implies more coverage than +//! there is. `LightClient*` is a special case within that: this crate +//! deliberately does not implement it, so those cases are marked ignored +//! instead of failed, distinct from a genuine gap. See [`trials`] for both. + +use ethlambda_state_transition::beacon::ForkName; +use ethlambda_state_transition::beacon::containers::{ + altair, bellatrix, capella, deneb, electra, fulu, phase0, shared, +}; +use ethlambda_state_transition::beacon::primitives::{HashTreeRoot, Root}; +use libssz::{SszDecode, SszEncode}; +use libtest_mimic::Trial; + +use super::{Case, PRESET, collect_all_handlers}; + +/// Decodes a case, then checks its root and its re-encoding. +fn check(case: &Case) -> Result<(), String> +where + T: SszDecode + SszEncode + HashTreeRoot, +{ + let bytes = case.ssz_bytes("serialized"); + + let value = T::from_ssz_bytes(&bytes).map_err(|err| format!("decode failed: {err:?}"))?; + + let expected: RootFile = case.yaml("roots"); + let expected_root: Root = parse_root(&expected.root); + // Disambiguated because the generic bound brings both this crate's + // convenience trait and libssz's underlying one into scope. + let actual = HashTreeRoot::hash_tree_root(&value); + if actual != expected_root { + return Err(format!( + "hash_tree_root 0x{} != expected {}", + hex::encode(actual.0), + expected.root + )); + } + + let reencoded = value.to_ssz(); + if reencoded != bytes { + return Err(format!( + "re-encoding produced {} bytes, fixture has {}", + reencoded.len(), + bytes.len() + )); + } + + Ok(()) +} + +#[derive(serde::Deserialize)] +struct RootFile { + root: String, +} + +fn parse_root(hex_root: &str) -> Root { + let stripped = hex_root.strip_prefix("0x").unwrap_or(hex_root); + let bytes = hex::decode(stripped).expect("roots.yaml holds a hex string"); + Root::from_slice(&bytes) +} + +pub fn trials() -> Vec { + let cases = collect_all_handlers(PRESET, "ssz_static"); + let mut trials = vec![super::discovery_trial("ssz_static", cases.len())]; + + for (handler, case) in cases { + // `LightClient*` is deliberately out of scope for this crate, so a + // pair with this prefix is marked ignored directly rather than run + // through `case_trial`: `case_trial`'s own ignored flag answers a + // different question (whether the case's *fork* is implemented), and + // every one of these pairs has a fork this crate does implement. The + // name still matches `case_trial`'s own shape so the two stay uniform + // in the test list. + if handler.starts_with("LightClient") { + let name = format!("ssz_static/{}", case.id()); + trials.push(Trial::test(name, || Ok(())).with_ignored_flag(true)); + continue; + } + + trials.push(super::case_trial("ssz_static", case, move |case| { + let fork = case.fork; + + // The fork-invariant containers are checked against every fork's cases, + // since a container that does not change shape should decode identically + // under all of them. That is coverage for free, and it would catch a + // container wrongly believed to be fork-invariant. + match handler.as_str() { + "Fork" => check::(case), + "ForkData" => check::(case), + "Checkpoint" => check::(case), + "Validator" => check::(case), + "AttestationData" => check::(case), + "Eth1Data" => check::(case), + "Eth1Block" => check::(case), + "DepositMessage" => check::(case), + "DepositData" => check::(case), + "Deposit" => check::(case), + "SigningData" => check::(case), + "HistoricalBatch" => check::(case), + "HistoricalSummary" => check::(case), + "BeaconBlockHeader" => check::(case), + "SignedBeaconBlockHeader" => check::(case), + "ProposerSlashing" => check::(case), + "VoluntaryExit" => check::(case), + "SignedVoluntaryExit" => check::(case), + + // Electra reshapes the attestation containers, widening the + // aggregation bits and attesting indices from one committee to a + // whole slot's worth, so phase0's definitions hold only through + // deneb, and electra's take over from electra on. Fulu makes no + // further change here, so electra's types cover it too. + "Attestation" if fork <= ForkName::Deneb => check::(case), + "Attestation" if fork >= ForkName::Electra => check::(case), + "IndexedAttestation" if fork <= ForkName::Deneb => { + check::(case) + } + "IndexedAttestation" if fork >= ForkName::Electra => { + check::(case) + } + "AttesterSlashing" if fork <= ForkName::Deneb => { + check::(case) + } + "AttesterSlashing" if fork >= ForkName::Electra => { + check::(case) + } + "AggregateAndProof" if fork <= ForkName::Deneb => { + check::(case) + } + "AggregateAndProof" if fork >= ForkName::Electra => { + check::(case) + } + "SignedAggregateAndProof" if fork <= ForkName::Deneb => { + check::(case) + } + "SignedAggregateAndProof" if fork >= ForkName::Electra => { + check::(case) + } + // Pre-electra, a lone attester's unaggregated vote reused + // Attestation itself with one bit set, since aggregation_bits was + // already scoped to a single committee. Electra's + // aggregation_bits spans a whole slot, so a lone bit no longer + // says which committee it belongs to, and SingleAttestation + // exists to carry that index explicitly instead. + "SingleAttestation" if fork >= ForkName::Electra => { + check::(case) + } + // The fixtures ship this for every fork even though no state + // after phase0 holds one; that is upstream's choice, and checking + // it costs nothing. + "PendingAttestation" => check::(case), + + // The state changes shape in almost every fork, so it gets one + // arm per fork rather than a range, unlike the block family + // below. + "BeaconState" if fork == ForkName::Phase0 => check::(case), + "BeaconState" if fork == ForkName::Altair => check::(case), + "BeaconState" if fork == ForkName::Bellatrix => { + check::(case) + } + "BeaconState" if fork == ForkName::Capella => check::(case), + "BeaconState" if fork == ForkName::Deneb => check::(case), + "BeaconState" if fork == ForkName::Electra => check::(case), + // Fulu appends proposer_lookahead to electra's state, so unlike + // the block family below it needs its own type here. + "BeaconState" if fork == ForkName::Fulu => check::(case), + + "BeaconBlock" if fork == ForkName::Phase0 => check::(case), + "BeaconBlockBody" if fork == ForkName::Phase0 => { + check::(case) + } + "SignedBeaconBlock" if fork == ForkName::Phase0 => { + check::(case) + } + + "BeaconBlock" if fork == ForkName::Altair => check::(case), + "BeaconBlockBody" if fork == ForkName::Altair => { + check::(case) + } + "SignedBeaconBlock" if fork == ForkName::Altair => { + check::(case) + } + + "BeaconBlock" if fork == ForkName::Bellatrix => { + check::(case) + } + "BeaconBlockBody" if fork == ForkName::Bellatrix => { + check::(case) + } + "SignedBeaconBlock" if fork == ForkName::Bellatrix => { + check::(case) + } + + "BeaconBlock" if fork == ForkName::Capella => check::(case), + "BeaconBlockBody" if fork == ForkName::Capella => { + check::(case) + } + "SignedBeaconBlock" if fork == ForkName::Capella => { + check::(case) + } + + "BeaconBlock" if fork == ForkName::Deneb => check::(case), + "BeaconBlockBody" if fork == ForkName::Deneb => { + check::(case) + } + "SignedBeaconBlock" if fork == ForkName::Deneb => { + check::(case) + } + + // Fulu does not change the block's shape: its body still carries + // exactly the execution_payload and execution_requests electra's + // does, so there is no fulu::BeaconBlock, fulu::BeaconBlockBody, + // or fulu::SignedBeaconBlock to define. Electra's types are + // checked against both forks' cases instead of being duplicated, + // which is the same reasoning that lets the sync committee + // containers below use one type across many forks. + "BeaconBlock" if fork >= ForkName::Electra => check::(case), + "BeaconBlockBody" if fork >= ForkName::Electra => { + check::(case) + } + "SignedBeaconBlock" if fork >= ForkName::Electra => { + check::(case) + } + + // The sync committee containers arrive in altair and, unlike the + // state, do not change shape again, so they are checked against every + // fork from altair on. + "SyncCommittee" if fork >= ForkName::Altair => check::(case), + "SyncAggregate" if fork >= ForkName::Altair => check::(case), + "SyncCommitteeMessage" if fork >= ForkName::Altair => { + check::(case) + } + "SyncCommitteeContribution" if fork >= ForkName::Altair => { + check::(case) + } + "ContributionAndProof" if fork >= ForkName::Altair => { + check::(case) + } + "SignedContributionAndProof" if fork >= ForkName::Altair => { + check::(case) + } + "SyncAggregatorSelectionData" if fork >= ForkName::Altair => { + check::(case) + } + + // The execution payload pair changes shape at bellatrix, capella, + // and deneb, then holds steady: neither electra nor fulu touches + // it, since their own changes land elsewhere (the attestation and + // pending-queue containers above, and fulu's proposer lookahead), + // so deneb's definitions cover deneb, electra, and fulu alike. + "ExecutionPayload" if fork == ForkName::Bellatrix => { + check::(case) + } + "ExecutionPayloadHeader" if fork == ForkName::Bellatrix => { + check::(case) + } + "ExecutionPayload" if fork == ForkName::Capella => { + check::(case) + } + "ExecutionPayloadHeader" if fork == ForkName::Capella => { + check::(case) + } + "ExecutionPayload" if fork >= ForkName::Deneb => { + check::(case) + } + "ExecutionPayloadHeader" if fork >= ForkName::Deneb => { + check::(case) + } + + // Transcribed from fork-choice.md rather than beacon-chain.md, and + // unchanged since the merge introduced it, so one type covers + // every fork that carries it. + "PowBlock" if fork >= ForkName::Bellatrix => check::(case), + + // The withdrawal machinery arrives in capella and does not change + // shape again through fulu. + "Withdrawal" if fork >= ForkName::Capella => check::(case), + "BLSToExecutionChange" if fork >= ForkName::Capella => { + check::(case) + } + "SignedBLSToExecutionChange" if fork >= ForkName::Capella => { + check::(case) + } + + // Blob wire types arrive in deneb and are unchanged by fulu's data + // column sampling: sampling changes how the data behind a blob's + // commitment travels over the network, not the blob sidecar or + // identifier themselves, so both keep deneb's shape through fulu. + "BlobIdentifier" if fork >= ForkName::Deneb => check::(case), + "BlobSidecar" if fork >= ForkName::Deneb => check::(case), + + // Electra's balance-churn queues and execution-layer-triggered + // requests are unchanged by fulu, so one set of types covers both. + "DepositRequest" if fork >= ForkName::Electra => { + check::(case) + } + "WithdrawalRequest" if fork >= ForkName::Electra => { + check::(case) + } + "ConsolidationRequest" if fork >= ForkName::Electra => { + check::(case) + } + "ExecutionRequests" if fork >= ForkName::Electra => { + check::(case) + } + "PendingDeposit" if fork >= ForkName::Electra => { + check::(case) + } + "PendingPartialWithdrawal" if fork >= ForkName::Electra => { + check::(case) + } + "PendingConsolidation" if fork >= ForkName::Electra => { + check::(case) + } + + // Data availability sampling is fulu-only: no earlier fork has + // these containers at all. + "DataColumnSidecar" if fork == ForkName::Fulu => { + check::(case) + } + "MatrixEntry" if fork == ForkName::Fulu => check::(case), + "DataColumnsByRootIdentifier" if fork == ForkName::Fulu => { + check::(case) + } + + // No arm matched, so this crate has no container for this + // handler/fork pair, and this is not `LightClient*` (that + // prefix is filtered out above before this trial is even + // built). That makes this a genuine gap: a handler this crate + // should cover has gone unmapped, so the case fails loudly + // instead of being silently skipped. + _ => Err(format!("no container is mapped for {fork}/{handler}")), + } + })); + } + + trials +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec/transition.rs b/crates/blockchain/state_transition/tests/beacon_spec/transition.rs new file mode 100644 index 000000000..2c2109ff6 --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec/transition.rs @@ -0,0 +1,195 @@ +//! The `transition` runner. +//! +//! Every other suite in this harness exercises one fork's rules against a +//! `pre` state already shaped for that fork. This one is the exception: its +//! block sequence starts on one fork and, partway through, crosses into the +//! next one, so the state itself has to change shape mid-run. It is the only +//! suite that drives [`upgrade::upgrade_state`] the way a real chain does, +//! from the middle of applying a chain of blocks rather than as a +//! self-contained fixture of its own, which is also why [`Config`] carries +//! fork activation epochs as runtime fields at all: see its own module doc. +//! +//! See `tests/formats/transition/README.md` in the pinned specification +//! checkout for the format in full. In outline: `meta.yaml` names +//! [`Meta::post_fork`], the fork the case ends on, and [`Meta::fork_epoch`], +//! the epoch that fork activates at (overriding [`Config`]'s own schedule for +//! that one boundary, per [`Config::with_fork_epoch`]'s own doc). The fork the +//! case *starts* on is never written down explicitly: the README states that +//! forks activate strictly in sequence, so it is always [`ForkName::previous`] +//! of `post_fork`. `pre.ssz_snappy` and `post.ssz_snappy` are a +//! [`BeaconState`] of the starting and ending fork respectively; the numbered +//! `blocks_.ssz_snappy` files are [`SignedBeaconBlock`]s, of the +//! starting fork's shape up through [`Meta::fork_block`] and the ending +//! fork's shape from the next index on, or entirely the ending fork's shape +//! if `fork_block` is absent. No released case carries an `execution.yaml`, so +//! [`ExecutionEngine::valid`] is the right default for the same reason +//! `sanity.rs` gives it one: these cases test consensus-layer rules, not +//! execution-payload rejection. +//! +//! The case directory this suite's cases live under is itself named after +//! `post_fork`, which is how [`super::collect`] assigns [`Case::fork`] and +//! therefore how [`Case::in_scope`] gates them: a case whose chain ends on a +//! fork this crate does not implement is skipped whole, without inspecting +//! its `meta.yaml` at all, matching how every other runner uses that gate. +//! [`transition`] still parses `post_fork` back out of `meta.yaml` and checks +//! it against the directory rather than trusting the directory alone, since +//! the directory-encodes-`post_fork` convention is this suite's own layout, +//! not something the format's README commits to. +//! +//! # The upgrade belongs to `process_slots`, so this runner drives blocks only +//! +//! Every fork past phase0 documents the same rule in its own `fork.md` +//! (altair's is representative): once `process_slots` advances `state.slot` to +//! exactly the first slot of that fork's activation epoch, the state's shape +//! must change there and then, inside the loop, before slot processing +//! continues. Altair's `fork.md` also says why it has to live inside the loop +//! rather than around it in the outer `state_transition`: a caller normally +//! only invokes `process_slots` for whatever slot the next block sits at, so +//! with empty slots at the boundary nothing outside `process_slots` ever +//! learns the exact slot the fork activated at in order to upgrade there. +//! +//! [`ethlambda_state_transition::beacon::stf::process_slots`] does this itself, which is what +//! lets this suite call [`stf::state_transition`] for every block exactly as +//! the other suites do, with no fork handling of its own beyond decoding each +//! block at the right shape. An earlier version of this runner drove the +//! upgrade from the outside, because `process_slots` had not yet grown the +//! check; doing that now would upgrade twice and fail, so the workaround is +//! gone rather than merely unused. +//! +//! One thing does remain this runner's own responsibility. A case whose blocks +//! all sit before the boundary still ends on `post_fork`'s shape, since that is +//! what `post.ssz_snappy` is encoded as, and with no post-boundary block to +//! carry `state_transition` across, nothing would advance `state.slot` far +//! enough to trigger the upgrade. [`apply_blocks`] finishes by advancing to the +//! boundary slot for that case, which is the same thing a real chain does when +//! it produces no block for the epoch a fork activates in. + +use std::sync::Arc; + +use ethlambda_state_transition::beacon::ForkName; +use ethlambda_state_transition::beacon::config::Config; +use ethlambda_state_transition::beacon::containers::{BeaconState, SignedBeaconBlock}; +use ethlambda_state_transition::beacon::helpers::misc::compute_start_slot_at_epoch; +use ethlambda_state_transition::beacon::primitives::Epoch; +use ethlambda_state_transition::beacon::stf::{self, ExecutionEngine}; +use libtest_mimic::Trial; + +use super::{Case, PRESET, collect}; + +/// One case's `meta.yaml`. +/// +/// See the module documentation for how [`Self::post_fork`] alone fixes the +/// starting fork too, and for what a missing [`Self::fork_block`] means. +#[derive(serde::Deserialize)] +struct Meta { + /// The fork the chain has finished upgrading to by the last block. Named + /// as a `String` here, rather than parsed straight into a [`ForkName`] by + /// a custom `Deserialize`, because a case whose fork this crate does not + /// recognize still has to produce a readable failure message rather than + /// a serde error pointing at the wrong layer. + post_fork: String, + /// The epoch [`Self::post_fork`] activates at, overriding [`Config`]'s own + /// schedule for this one boundary via [`Config::with_fork_epoch`]. + fork_epoch: Epoch, + /// The index of the last `blocks_.ssz_snappy` file still shaped + /// like the fork before [`Self::post_fork`]. Every later index, up to + /// [`Self::blocks_count`], is shaped like `post_fork` itself. Absent when + /// every block in the case already belongs to `post_fork`, per the + /// format's README. + #[serde(default)] + fork_block: Option, + /// How many `blocks_.ssz_snappy` files the case carries. + blocks_count: usize, +} + +/// Applies every block in the case, letting [`stf::process_slots`] perform the +/// shape upgrade as it advances into the fork's activation epoch. +/// +/// Each block is decoded at its own fork's shape, which is the one thing the +/// case's `meta.yaml` has to be consulted for; from there +/// [`stf::state_transition`] handles a pre-fork and a post-fork block +/// identically. See the module documentation for why the trailing +/// [`stf::process_slots`] call is still needed for a case that never gets a +/// post-boundary block. +fn apply_blocks( + case: &Case, + meta: &Meta, + pre_fork: ForkName, + post_fork: ForkName, + state: &mut BeaconState, + config: &Config, +) -> Result<(), String> { + let config = config.clone().with_fork_epoch(post_fork, meta.fork_epoch); + // A missing `fork_block` means every block already belongs to `post_fork` + // (index 0 included); otherwise `fork_block` is the *last* pre-fork + // index, so the first post-fork one is the index right after it. + let first_post_fork_index = meta.fork_block.map_or(0, |last_pre_fork_index| { + last_pre_fork_index.saturating_add(1) + }); + + let engine = ExecutionEngine::valid(); + + for index in 0..meta.blocks_count { + let fork = if index < first_post_fork_index { + pre_fork + } else { + post_fork + }; + + let bytes = case.ssz_bytes_indexed("blocks", index); + let block = SignedBeaconBlock::from_ssz(fork, &bytes) + .map_err(|err| format!("block {index} does not decode as {fork}: {err:?}"))?; + + stf::state_transition(state, &block, true, &config, &engine) + .map_err(|err| format!("block {index} rejected: {err:?}"))?; + } + + let boundary_slot = compute_start_slot_at_epoch(meta.fork_epoch); + if state.slot() < boundary_slot { + stf::process_slots(state, boundary_slot, &config) + .map_err(|err| format!("advancing to the fork boundary: {err:?}"))?; + } + + Ok(()) +} + +pub fn trials() -> Vec { + let config = Arc::new(Config::active()); + let cases = collect(PRESET, "transition", "core"); + let mut trials = vec![super::discovery_trial("transition", cases.len())]; + + for case in cases { + let config = Arc::clone(&config); + trials.push(super::case_trial("transition", case, move |case| { + let meta: Meta = case.yaml("meta"); + let post_fork = ForkName::parse(&meta.post_fork).unwrap_or_else(|| { + panic!( + "{}: meta.yaml's post_fork ({}) is not a fork this crate recognizes", + case.id(), + meta.post_fork + ) + }); + // The case directory encodes `post_fork` too (see the module doc), so + // this checks the harness's own assumption about the fixture layout + // rather than anything about this crate's state transition. A panic + // here fails this one case, same as everywhere else in this closure. + assert_eq!( + post_fork, + case.fork, + "{}: meta.yaml's post_fork does not match the case's own directory", + case.id() + ); + let pre_fork = post_fork + .previous() + .unwrap_or_else(|| panic!("{}: post_fork can never be phase0", case.id())); + + let mut state = BeaconState::from_ssz(pre_fork, &case.ssz_bytes("pre")) + .map_err(|err| format!("the fixture's pre-state does not decode: {err:?}"))?; + + let outcome = apply_blocks(case, &meta, pre_fork, post_fork, &mut state, &config); + super::check_transition(case, outcome, &state) + })); + } + + trials +} diff --git a/crates/blockchain/state_transition/tests/beacon_spec_tests.rs b/crates/blockchain/state_transition/tests/beacon_spec_tests.rs new file mode 100644 index 000000000..d17b5f8f8 --- /dev/null +++ b/crates/blockchain/state_transition/tests/beacon_spec_tests.rs @@ -0,0 +1,54 @@ +//! The Ethereum consensus spec test suites. +//! +//! One integration binary holds every runner, so the fixture harness in +//! [`beacon_spec`] is compiled once and each runner lives in its own file with a single +//! owner. Add a runner by adding a module to [`beacon_spec`] and one line below. +//! +//! Run with `make test-beacon`, which downloads the fixtures and builds the +//! crate once per preset. +//! +//! # Why this binary supplies its own harness +//! +//! Built with `harness = false`, so [`main`] below is the entry point instead of +//! the one the `#[test]` attribute generates. The reason is that a fixture case +//! is not known until the fixture tree is walked, and `#[test]` needs its tests +//! at compile time. Under the generated harness the only thing a suite could be +//! was one test looping over its own cases, which made every failure a failure +//! of the whole suite: the name in the output was the suite's, one bad case +//! marked thousands of passing ones as part of a failed test, and a run stopped +//! reporting anything per case at all. +//! +//! `libtest_mimic` takes a list of tests built at run time and otherwise behaves +//! as the standard harness does, so each case is named, counted, filtered, and +//! attributed on its own, and `--test-threads`, `--ignored`, `--list`, and a +//! plain substring filter all keep working. Every case is independent, so the +//! harness's own pool runs them concurrently, one case per work item, which is +//! finer-grained than anything a suite-per-test layout could balance. + +mod beacon_spec; + +fn main() { + let args = libtest_mimic::Arguments::from_args(); + + let mut trials = Vec::new(); + trials.extend(beacon_spec::harness::trials()); + trials.extend(beacon_spec::fixture_fork_trials()); + trials.extend(beacon_spec::bls::trials()); + trials.extend(beacon_spec::kzg::trials()); + trials.extend(beacon_spec::epoch_processing::trials()); + trials.extend(beacon_spec::fork::trials()); + trials.extend(beacon_spec::fork_choice::trials()); + trials.extend(beacon_spec::operations::trials()); + trials.extend(beacon_spec::rewards::trials()); + trials.extend(beacon_spec::sanity::trials()); + trials.extend(beacon_spec::shuffling::trials()); + trials.extend(beacon_spec::ssz_static::trials()); + trials.extend(beacon_spec::transition::trials()); + + // The release ships genesis fixtures for the minimal preset only, so the + // whole module is compiled out otherwise (see its own inner attribute). + #[cfg(feature = "preset-minimal")] + trials.extend(beacon_spec::genesis::trials()); + + libtest_mimic::run(&args, trials).exit(); +} diff --git a/crates/common/types/Cargo.toml b/crates/common/types/Cargo.toml index a3dae4d87..31f148a8e 100644 --- a/crates/common/types/Cargo.toml +++ b/crates/common/types/Cargo.toml @@ -14,7 +14,7 @@ version.workspace = true # # Container shapes are compile-time constants (SSZ list and vector bounds), so # the preset cannot be selected at runtime. Mainnet is the implicit default. -# `ethlambda-beacon`'s feature of the same name forwards to this one. +# `ethlambda-state-transition`'s feature of the same name forwards to this one. preset-minimal = [] [dependencies] diff --git a/crates/common/types/src/beacon/config.rs b/crates/common/types/src/beacon/config.rs index a82ef68da..aa0d96d9d 100644 --- a/crates/common/types/src/beacon/config.rs +++ b/crates/common/types/src/beacon/config.rs @@ -27,8 +27,8 @@ //! reads it on every phase0-era signature. The other three //! (`MIN_GENESIS_ACTIVE_VALIDATOR_COUNT`, `MIN_GENESIS_TIME`, `GENESIS_DELAY`) //! are read only while building a genesis state from Eth1 deposit history, and -//! never again once that state exists, but `ethlambda_beacon::genesis` needs them -//! and the `genesis` fixture suite checks them. +//! never again once that state exists, but the beacon STF's `genesis` module +//! needs them and the `genesis` fixture suite checks them. use crate::beacon::constants; use crate::beacon::fork::ForkName; diff --git a/crates/common/types/src/beacon/constants.rs b/crates/common/types/src/beacon/constants.rs index 8b65d1df2..5f0107e91 100644 --- a/crates/common/types/src/beacon/constants.rs +++ b/crates/common/types/src/beacon/constants.rs @@ -54,8 +54,8 @@ pub const DEPOSIT_CONTRACT_TREE_DEPTH: usize = 32; /// `Bitvector`, hence `usize`. pub const JUSTIFICATION_BITS_LENGTH: usize = 4; -/// `2**64 - 1`. Used only by `ethlambda_beacon::helpers::math`'s `integer_squareroot` -/// helper as the boundary past which the doubling-based Newton's method +/// `2**64 - 1`. Used only by the beacon STF's `helpers::math::integer_squareroot` +/// as the boundary past which the doubling-based Newton's method /// bound is replaced by a precomputed answer; unrelated to /// [`FAR_FUTURE_EPOCH`] despite the identical bit pattern. pub const UINT64_MAX: u64 = u64::MAX; diff --git a/crates/common/types/src/beacon/containers/mod.rs b/crates/common/types/src/beacon/containers/mod.rs index 1dc2cf481..cfe4993fb 100644 --- a/crates/common/types/src/beacon/containers/mod.rs +++ b/crates/common/types/src/beacon/containers/mod.rs @@ -400,8 +400,8 @@ impl BeaconState { /// /// These cannot join `shared_state_accessors`' lists, since phase0 has /// none of them, and a per-fork projection to a concrete state struct (the - /// way `ethlambda_beacon::helpers::altair::altair_state_ref` reaches them) cannot - /// serve every fork that carries them: bellatrix, capella, deneb, electra, + /// way the beacon STF's `helpers::altair::altair_state_ref` reaches them) + /// cannot serve every fork that carries them: bellatrix, capella, deneb, electra, /// and fulu all keep the identical three fields, but each is a distinct /// Rust type, so a projection typed to return `&altair::BeaconState` can /// only ever answer for an altair state. @@ -432,8 +432,8 @@ impl BeaconState { /// per-fork projection instead. /// /// Handed back together for two reasons that stack: - /// `ethlambda_beacon::stf::operations::add_validator_to_registry` genuinely needs - /// all three, since they are positionally parallel with `validators` and + /// the beacon STF's `stf::operations::add_validator_to_registry` genuinely + /// needs all three, since they are positionally parallel with `validators` and /// `balances`, so a validator entering the registry has to grow all five /// or leave the state internally inconsistent in a way nothing else would /// notice until a `hash_tree_root` came out wrong; and every caller that @@ -470,7 +470,7 @@ impl BeaconState { /// fork (see, for instance, bellatrix's own state doc), so they cannot /// join `shared_state_accessors`' lists, since phase0 predates sync /// committees entirely. A per-fork projection cannot serve here either: - /// `ethlambda_beacon::stf::altair::process_sync_aggregate` is called for every + /// the beacon STF's `stf::altair::process_sync_aggregate` is called for every /// fork from altair through fulu (see that function's own documentation), /// and a projection typed to return `&altair::BeaconState` can only ever answer /// for an altair state, not for the bellatrix, capella, deneb, electra, or @@ -489,8 +489,8 @@ impl BeaconState { /// [`Self::sync_committees`] for why this cannot be a per-fork projection. /// /// Handed back together, rather than as two separate accessors, because - /// `ethlambda_beacon::stf::epoch::altair::process_sync_committee_updates` rotates - /// the pair by replacing one with the other at each sync committee period + /// the beacon STF's `stf::epoch::altair::process_sync_committee_updates` + /// rotates the pair by replacing one with the other at each sync committee period /// boundary, which needs both mutable borrows alive for the one /// `core::mem::replace` that does it. pub fn sync_committees_mut( diff --git a/crates/common/types/src/beacon/fork.rs b/crates/common/types/src/beacon/fork.rs index 5578b548b..00b8558fc 100644 --- a/crates/common/types/src/beacon/fork.rs +++ b/crates/common/types/src/beacon/fork.rs @@ -16,7 +16,7 @@ use core::fmt; /// [`ForkName::Lean`] is last so that every such gate reads as true for a lean /// state, and is deliberately absent from [`ForkName::ALL`]: lean is not a point /// on the Beacon Chain's fork timeline, has no spec fixtures, and must never be -/// a target of `ethlambda_beacon::upgrade`-style traversal. See +/// a target of the beacon STF's `upgrade`-style traversal. See /// [`ForkName::ALL`]. /// /// Forks after fulu exist upstream but are out of scope for this crate. diff --git a/crates/common/types/src/beacon/fork_choice.rs b/crates/common/types/src/beacon/fork_choice.rs index d79d39d2a..d6c0d7695 100644 --- a/crates/common/types/src/beacon/fork_choice.rs +++ b/crates/common/types/src/beacon/fork_choice.rs @@ -1,10 +1,10 @@ //! The two fork-choice containers that are neither a block nor a state. //! -//! They live here rather than in `ethlambda-beacon`'s `fork_choice` module -//! because the DB-backed `ethlambda_storage::Store` holds them, and -//! `ethlambda-storage` cannot depend on `ethlambda-beacon`: the dependency runs -//! the other way. `ethlambda_beacon::fork_choice` re-exports both at their old -//! paths, so every use site inside that crate is unchanged. +//! They live here rather than in the `beacon::fork_choice` module of +//! `ethlambda-state-transition` because the DB-backed `ethlambda_storage::Store` +//! holds them, and `ethlambda-storage` cannot depend on that crate: the +//! dependency runs the other way. That module re-exports both at their old paths, +//! so every use site inside it is unchanged. use libssz_derive::{HashTreeRoot, SszDecode, SszEncode}; @@ -51,7 +51,7 @@ mod tests { #[test] fn a_pow_block_round_trips_through_ssz() { // The store persists these, so the derive has to survive the move out - // of `ethlambda-beacon` intact. + // of `ethlambda-state-transition` intact. let block = PowBlock { block_hash: Root::repeat_byte(1), parent_hash: Root::repeat_byte(2), diff --git a/crates/common/types/src/beacon/fork_digest.rs b/crates/common/types/src/beacon/fork_digest.rs index c20af99c3..69a42488a 100644 --- a/crates/common/types/src/beacon/fork_digest.rs +++ b/crates/common/types/src/beacon/fork_digest.rs @@ -1,10 +1,10 @@ //! The four bytes that separate one network, fork, and blob schedule from //! another on the wire. //! -//! Lives here rather than in `ethlambda-beacon` because the networking crate -//! needs it and must not depend on the state transition: `ethlambda-beacon` -//! pulls in `blst` and `c-kzg`, neither of which a gossip topic name has any -//! business requiring. `ethlambda_beacon::helpers::misc` re-exports +//! Lives here rather than in `ethlambda-state-transition` because the networking +//! crate needs it and must not depend on the state transition: that crate's +//! `beacon` module pulls in `blst` and `c-kzg`, neither of which a gossip topic +//! name has any business requiring. That module's `helpers::misc` re-exports //! [`compute_fork_data_root`] at its old path. use sha2::{Digest as _, Sha256}; diff --git a/crates/common/types/src/beacon/mod.rs b/crates/common/types/src/beacon/mod.rs index 79c231f5b..54685b337 100644 --- a/crates/common/types/src/beacon/mod.rs +++ b/crates/common/types/src/beacon/mod.rs @@ -2,7 +2,8 @@ //! //! `ethlambda-types` already has `primitives`, `constants`, and `checkpoint` //! modules of its own, and lean's `Checkpoint` is a different type from -//! beacon's by the same name. Everything moved out of `ethlambda-beacon` lives +//! beacon's by the same name. Everything moved out of the beacon state +//! transition lives //! under this module so both sets can coexist. pub mod config; diff --git a/crates/common/types/src/beacon/preset.rs b/crates/common/types/src/beacon/preset.rs index 550518d70..724c23e87 100644 --- a/crates/common/types/src/beacon/preset.rs +++ b/crates/common/types/src/beacon/preset.rs @@ -979,8 +979,9 @@ pub use minimal::*; /// (EIP-7251): its own copy restructures the division around the constant /// rather than only swapping the constant in, so from electra on a value /// selected here is no longer enough on its own to keep one shared copy of -/// that function correct. `ethlambda_beacon::stf::epoch::electra::process_slashings` is -/// a separate function for exactly that reason; see its own doc for the +/// that function correct. The beacon STF's +/// `stf::epoch::electra::process_slashings` is a separate function for exactly +/// that reason; see its own doc for the /// arithmetic. `slash_validator` never breaks the pattern this module /// describes, so it keeps reading [`retuned::min_slashing_penalty_quotient`] /// and [`retuned::whistleblower_reward_quotient`] from here through every fork this crate diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 6b6f9c500..93021316c 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -12,6 +12,10 @@ - [3SF-mini: Justification & Finalization](./3sf_mini.md) - [LMD-GHOST Fork Choice](./lmd_ghost.md) +# Beacon Chain + +- [Beacon Chain State Transition](./beacon_stf.md) + # Operations - [HTTP API](./rpc.md) diff --git a/docs/beacon_stf.md b/docs/beacon_stf.md new file mode 100644 index 000000000..221b75ab8 --- /dev/null +++ b/docs/beacon_stf.md @@ -0,0 +1,496 @@ +# Beacon Chain state transition + +The `beacon` module of `ethlambda-state-transition` +(`crates/blockchain/state_transition/src/beacon/`) implements the Ethereum +**Beacon Chain** consensus specification, +[`ethereum/consensus-specs`][specs], phase0 through fulu. + +This is not the Lean consensus protocol the rest of the crate implements. The two +sit in one crate for the reason their types sit in one crate: a caller +dispatching on a state's fork can then reach either chain's rules without the two +living in separate dependency trees. They share nothing else. Nothing above +`beacon` in this crate reads anything inside it, and nothing inside it reads +lean's own modules. + +The containers, presets, configuration and primitives this module transitions are +in `ethlambda-types`, under its own `beacon` namespace, because +`ethlambda-storage` and the networking crates need those types and must not +depend on `blst` and `c-kzg`. What lives here is the behavior: the state +transition, the fork choice store, the helpers, and the two cryptography modules. + +`blst`, `c-kzg` and `num-bigint` are therefore on the lean binary's dependency +path, since `ethlambda-blockchain`, `ethlambda-rpc` and `ethlambda-test-fixtures` +all depend on this crate. The module is not feature-gated; that is the accepted +cost of holding both chains' rules in one place. + +The types are re-exported at the paths they had when they were defined here, so +`crate::beacon::containers`, `crate::beacon::preset` and `crate::beacon::config` +still resolve, and +`ethlambda_state_transition::beacon::containers::X` and +`ethlambda_types::beacon::containers::X` +are one type by one name. Two definitions travel in the other direction, for the +same reason they moved: `fork_choice` re-exports `LatestMessage` and `PowBlock`, +which `ethlambda-storage` persists, and `helpers::misc` re-exports +`compute_fork_data_root`, which the networking crate's fork digest is built on. + +One consequence reaches every match in the module. `ethlambda-types` gives +`BeaconState` and `ForkName` a `Lean` variant, so that one state type can carry +either chain, and every match on either needs an arm for it. No lean value can +reach this module: a fixture case's fork is parsed from a directory name and +`ForkName::ALL` has no lean entry, and a beacon block or a deposit set produces a +beacon state. So those arms panic and name themselves, through +`lean_state_unreachable`/`lean_fork_unreachable` (`src/beacon/lean_boundary.rs`) and +`lean_is_not_a_fixture_fork` in the spec tests, rather than widening signatures to +a `Result` no correct caller could ever see. They are named arms rather than a +catch-all `_`, so a real fork added to the enum still breaks every match that has +to grow an arm for it. + +Correctness is defined by the released spec test fixtures, pinned in the +`Makefile`. + +## Running the tests + +```bash +make consensus-spec-tests # download the fixture tarballs (about 2.2 GB) +make test-beacon # build and test once per preset +``` + +`make test-beacon` is the two per-preset targets, `test-beacon-mainnet` and +`test-beacon-minimal`, run one after the other. Either can be run on its own, +which is what CI does: the presets get a job each, so the two build and run +concurrently instead of end to end. + +A run reads its own preset's tree plus `general`, the preset-independent BLS and +KZG vectors, and opens nothing else. `CONSENSUS_SPEC_TESTS_CONFIGS` narrows the +download to that, and CI sets it, which takes roughly 1.25 GB of tarballs down to +0.8 GB for mainnet and 0.6 GB for minimal. Locally the default fetches all three, +so both presets can be run without re-downloading. + +The download is stamped with the release it came from and the configs it holds +(`consensus-spec-tests/.version--`), so changing either wipes +the tree and fetches afresh. Without the version in that name a bump would be a +silent no-op: the extracted directories already exist, so `make` would consider +them current and both presets would report green against the old fixtures. +Without the configs, a narrowed download would mark a tree missing one preset as +complete, and that preset's next run would fail on a missing directory rather +than fetching what it needs. The wipe matters as much as the re-download, since +the tarballs unpack side by side into one directory, and layering a new release +over an old one would keep cases the new one deleted. + +`make test` runs the whole workspace with nothing excluded, and still needs no +fixture download. Two gates keep it that way, both tied to the +`beacon-spec-tests` feature that `make test-beacon` turns on: + +- The `beacon_spec_tests` target declares `required-features = + ["beacon-spec-tests"]`, so `cargo test` skips building it entirely. +- The BLS and KZG fixture vectors are unit tests inside the module, which no + target gate reaches, so each carries + `#[cfg_attr(not(feature = "beacon-spec-tests"), ignore = ...)]`. They report as + ignored rather than disappearing, which is why `make test-beacon` also passes + `--lib`: 15 tests would otherwise never run. + +Neither gate touches the module itself, which always compiles. What they stand +for is the fixture tree, not the code. + +## Layout + +| Module | Holds | +|--------|-------| +| `preset` | Compile-time constants, mainnet or minimal | +| `config` | Runtime configuration: fork schedule, churn limits, blob schedule | +| `constants` | Values the spec fixes outright: domain types, flag weights, sentinels | +| `fork` | `ForkName`, ordered oldest to newest | +| `primitives` | Scalar aliases, `Root`, and the fixed-length byte strings | +| `bls` | BLS12-381 via `blst` | +| `kzg` | KZG via `c-kzg`, plus the two challenge functions c-kzg does not export | +| `containers` | The `BeaconState` enum, fork-invariant containers, per-fork containers | +| `helpers` | The spec's helper functions | +| `stf` | The state transition: slots, blocks, operations, epoch processing | +| `genesis` | Building a genesis state from Eth1 deposits | +| `upgrade` | Fork upgrades between per-fork state shapes | +| `fork_choice` | The LMD GHOST store | +| `lean_boundary` | The two `#[track_caller]` panics for the `Lean` arm of the shared enums | + +The first five come from `ethlambda_types::beacon` and are re-exported by +`beacon/mod.rs`; the rest are defined here. + +## Three kinds of parameter + +The specification distinguishes constants, presets, and configuration, and so +does this module, because they have genuinely different lifetimes. + +**Presets** (`preset`) set container sizes, so they must be compile-time +constants: `SszVector`. The preset +therefore cannot be a runtime value or a type parameter. Stable Rust cannot take a +const-generic argument from a trait's associated const, so the preset is selected +by Cargo feature: mainnet by default, minimal with `preset-minimal`. The test +target builds the crate twice and each run walks only its own fixture tree. + +**Configuration** (`config`) is runtime, because the `transition` fixture suite +moves a fork's activation epoch per test case. That is the concrete reason fork +scheduling is not a preset. + +**Constants** (`constants`) are fixed by the specification and vary by neither. + +## Retuning a value without redefining a function + +The specification expresses a retuned constant as a fresh name per fork +(`MIN_SLASHING_PENALTY_QUOTIENT`, then `..._ALTAIR`, then `..._BELLATRIX`) and +redefines the function that reads it, so each fork carries its own copy of +that function differing in one identifier. `preset::retuned` +(`crates/common/types/src/beacon/preset.rs`, reached here as `crate::preset`) +selects the value by fork instead, in four functions, so `slash_validator` and its neighbors stay a single copy each +rather than one per fork. + +This is the one place in the crate where a preset value is chosen at runtime. +It is sound because none of these values bound a container: they are divisors +and multipliers in balance arithmetic, not container shape. + +The minimal preset is **not** a uniformly scaled mainnet: it overrides only +*phase0's* retuned values and inherits every later fork's from mainnet +unchanged. So a value can move one way across a fork boundary under mainnet +and the other way under minimal: `INACTIVITY_PENALTY_QUOTIENT` falls from +phase0 to altair under mainnet and rises under minimal. A test asserting that +slashing gets uniformly harsher across the forks holds under mainnet and is +false under minimal, so `preset::retuned`'s own tests pin the fork-to-constant +mapping directly, which holds under both presets, rather than any numeric +relationship, which does not. + +## How forks are represented + +Containers that change between forks are defined once per fork as plain structs +that derive their SSZ encoding, decoding, and merkleization, and an enum wraps +them: + +```rust +pub enum BeaconState { + Phase0(phase0::BeaconState), + // one variant per fork that changes the state's shape +} +``` + +Deriving the SSZ traits is the whole reason for that shape. Container +serialization and merkleization is the highest-risk code in the crate, and the +per-fork field lists are not a growing tail: + +- `previous_epoch_attestations` and `current_epoch_attestations` exist **only** in + phase0. From altair on they are absent from both the encoding and the merkle + tree, replaced in position by `previous_epoch_participation` and + `current_epoch_participation`, which have a different type. +- `latest_execution_payload_header` keeps its name from bellatrix on, but is a + different container only in bellatrix, capella, and deneb; electra and fulu + reuse deneb's shape unchanged. +- The field count crosses a power of two at electra, so the state's merkle tree is + five levels deep through deneb and six from electra on. The same logical field + has a different generalized index in different forks. +- `SignedBeaconBlock::Fulu` wraps `electra::SignedBeaconBlock` rather than a + `fulu` type of its own, since fulu changes no field of a block. It still + needs to be its own variant: fulu changes how a block is *processed*, since + the blob commitment limit becomes epoch-dependent, so code that dispatches + on fork still has to tell a fulu block from an electra one even though both + carry the identical payload. + +| Fork | State fields | HTR leaves | Depth | +|------|--------------|------------|-------| +| phase0 | 21 | 32 | 5 | +| altair | 24 | 32 | 5 | +| bellatrix | 25 | 32 | 5 | +| capella, deneb | 28 | 32 | 5 | +| electra | 37 | 64 | 6 | +| fulu | 38 | 64 | 6 | + +A single container with fork-conditional serialization would have to reproduce all +of that by hand. Derived codecs get it from the struct definition, which is +checked field by field against the spec text and then verified by `ssz_static`. + +Since SSZ carries no type tag, the fork cannot be recovered from the bytes, so +decoding takes it from context: `BeaconState::from_ssz(fork, bytes)`. + +### Not duplicating the state transition seven times + +The cost of per-fork structs is that a naive implementation would copy every +function once per fork. Two things prevent that: + +1. **Accessors for the fork-invariant fields.** About twenty of the state's fields + are identical in every fork. One `macro_rules!` in `containers/mod.rs` + generates their read and write accessors from a single list, and that list + doubles as the crate's statement of which fields are fork-invariant: a fork + that changes one moves it out of the list and gains an explicit match at each + use site. + +2. **Matching only where the spec diverges.** Functions take the enum and use + accessors, matching on the fork only where the specification itself changes + behavior, so a match arm can be reviewed against the spec's own diff. + +### No block-body enum + +`BeaconState` and `SignedBeaconBlock` are the only enums; there is no +`BeaconBlockBody` enum or a body trait. Such a type would have to grow a +method or match arm per fork-specific field or operation list, which defeats +the point of dispatching once: a caller of `body.attester_slashings()` would +still have to know which fork it is dealing with to make sense of what comes +back, since electra's attester slashings are not phase0's. What actually lets +one function serve every fork is narrower and cheaper: `process_block_header`, +`process_randao`, and `process_eth1_data` each take the handful of fields they +read directly, rather than a whole body, so validating a header does not care +whether the body it came from also carries a sync aggregate or an execution +payload. A shared step earns its genericity by needing less, not by being +handed a bigger abstraction to see through. See `stf/mod.rs`'s module doc for +the full reasoning. + +### Crossing a fork boundary + +`process_slots` performs the fork-boundary state upgrade itself, inside its +slot loop, at the first slot of the activation epoch, looping again in case a +single configuration activates two forks at the same epoch. `state_transition` +checks the block's fork against the state's own only *after* calling +`process_slots`, not before: a block at the first slot of an activation epoch +is legitimately post-fork shaped while the state arriving there is still +pre-fork, which is exactly what a fork transition consists of. Checking first +would reject every legitimate fork-boundary block and make crossing a fork +impossible. + +## Macros and traits + +Two `macro_rules!` in the whole crate, both local, both replacing boilerplate that +would otherwise run to hundreds of near-identical lines: the fixed-length byte +strings in `primitives`, and the state accessors in `containers`. No procedural +macros beyond the SSZ derives, and no trait abstracting over BLS or KZG backends. + +## Cryptography + +`bls` wraps `blst`, and `kzg` wraps `c-kzg` with the `eip-7594` cell and column +functions fulu needs, both matching the versions ethrex uses. + +Two details worth knowing: + +- Every BLS function re-validates its inputs on each call rather than trusting a + wrapper validated once. `BlsPubkey` is deliberately unvalidated on construction, + because deposit processing has to be able to hold a key that never validates, so + nothing upstream guarantees a key is a subgroup-correct point. +- `compute_challenge` and `compute_verify_cell_kzg_proof_batch_challenge` are + implemented directly from the spec rather than called, because c-kzg keeps them + as private steps of its own proof routines yet both have their own fixture + handlers. + +## Fixture suites + +`consensus-spec-tests/tests///////`, +where `` is `general` for the configuration-independent suites and the +preset name otherwise. Container files are `.ssz_snappy`: SSZ compressed with +*raw* snappy, not the framed format. + +Runners discover their cases from disk rather than listing them, so a fixture +release that adds cases needs no code change. Two properties are deliberate: a +suite that matches no case **fails** rather than reporting green, and a container +or fork pair with no implementation yet is counted and printed rather than passed +over silently, so the output never implies more coverage than exists. + +`value.yaml` goes unread in `ssz_static`. Using it would need a serde +implementation for every container and would pin down nothing that the serialized +bytes and expected root do not already. + +## Performance + +The mainnet spec suite went from 1576s to about 106s. Two causes: + +1. `sha2`'s `asm` feature selects the CPU's SHA-256 instructions. Without it, + `sha2` compiles the portable scalar backend on aarch64 regardless of what + the CPU supports, and merkleization is almost entirely SHA-256 + compressions, so a spec fixture case running two whole-state + merkleizations feels the difference more than anything else does. +2. Every fixture case is its own test, so the harness runs them concurrently at + one case per work item. That is finer-grained than a suite-per-test layout + could balance, where the slowest suite alone set the wall clock. + +CPU time and wall clock separate the two cleanly, since running work in +parallel cannot reduce the total CPU time it takes: + +| Measure | Before | After | Factor | +| --- | --- | --- | --- | +| CPU time | 3041s | 928s | 3.3x, the hardware SHA-256 | +| Wall clock | 1576s | 106s | 14.9x, both causes together | + +So parallelism accounts for the remaining 4.9x, taking the run from two of +eleven cores busy to about eight. The 3.3x understates the hashing change, +because the later run does strictly more work: `transition` went from failing +immediately to running every case. + +## One test per fixture case + +The suites were once one test apiece, each looping over its own cases and +aggregating outcomes. That made every failure a failure of the whole suite: the +name in the output was the suite's, and a single bad case marked thousands of +passing ones as part of one failed test. + +A fixture case is not known until the fixture tree is walked, and `#[test]` +needs its tests at compile time, so the spec binary supplies its own harness +(`harness = false`, with `libtest_mimic`) and builds its test list at run time. +Each case is then named, counted, filtered, and attributed on its own, and +`--test-threads`, `--ignored`, `--list`, and substring filters all keep working. +A filter selects a whole suite as readily as one case, since a test's name is +its runner followed by `Case::id`: + +```text +operations/electra/attester_slashing/pyspec_tests/basic_double +``` + +Two things that arrangement has to be careful about: + +- A case whose fork this module does not implement becomes an **ignored** test + rather than a missing one. The harness counts and names ignored tests, which + says more than the tally the old aggregate printed. +- A suite that matches no case at all would otherwise contribute no tests, and a + run of nothing passes. The aggregate used to assert it had matched something; + that check survives as one `/matched_fixture_cases` test per suite, so + a stale runner or handler name still fails loudly. + +## Status + +All seven forks, phase0 through fulu, have containers, fork upgrades, state +transitions, and epoch processing. Every fixture case passes on both presets: + +| Preset | Fixture cases | Ignored | Lib tests | +|--------|---------------|---------|-----------| +| mainnet | 5705, all green | 152 | 195 | +| minimal | 40009, all green | 3692 | 196 | + +The lib counts were 244 and 245 while the containers, presets, configuration and +primitives were defined here. Their 48 unit tests moved with them and run in +`ethlambda-types`; the fixture counts, which are what defines correctness here, +are unchanged. + +Minimal runs more cases because the release ships more fixtures for it, and it +runs two runners mainnet does not: `genesis`'s `initialization` and `validity`. +The release ships no mainnet `genesis` fixtures, so that whole runner is gated +behind the `preset-minimal` feature (`tests/spec/genesis.rs`). + +Nothing is ignored for being unimplemented. Every ignored case is one of two +deliberate exclusions: + +- `LightClient*` containers under `ssz_static`, 5 container types across altair + through fulu. The light-client sync protocol is a different layer from the + state transition and fork choice, and is not in this module's scope. +- The `gloas` and `eip7805` fixture trees, one ignored entry each. See + "Accounting for every fork directory" below. + +## Accounting for every fork directory + +`collect` identifies a fork by parsing the directory name into a `ForkName`, and +a name that does not parse is skipped. That skip is silent in a way the +`HIGHEST_IMPLEMENTED_FORK` gate is not: the cases never become tests, so they are +not counted as ignored either, and nothing in the output says they exist. + +The release does ship two such trees. `gloas` is the fork after fulu, and +`eip7805` is not a fork in the sequence at all, being one of the per-EIP trees +generated against a variant of some fork's rules. Between them they hold 1898 +mainnet and 17539 minimal cases, all of which were previously dropped without a +trace, which is the opposite of what this harness promises. + +So `UNMODELED_FORKS` names them, each reports as one ignored test, and +`fixture_forks/every_directory_is_accounted_for` fails if the tree holds a fork +directory that is neither parseable nor listed. A release that adds a fork now +forces a decision instead of quietly widening the gap. + +| Suite | Covers | +|-------|--------| +| `general/bls` | Cryptography, fork- and preset-independent | +| `general/kzg` | Cryptography, fork- and preset-independent | +| `ssz_static` | Every fork's containers | +| `shuffling` | Committee helpers | +| `operations`, `epoch_processing` | Every fork's operation and epoch sub-function | +| `sanity/blocks`, `sanity/slots`, `finality`, `random`, `rewards` | Whole blocks and slots, end to end | +| `fork`, `transition` | Fork upgrades, standalone and mid-chain | +| `genesis` | Genesis initialization (minimal only, see above) | +| `fork_choice` | The `Store`; see below | + +### Fork choice is fixture-verified + +150 mainnet `fork_choice` cases pass, covering bellatrix's `on_merge_block`/ +terminal-PoW validation, `should_override_forkchoice_update`, deneb's blob +data availability, and fulu's column data availability. + +The release still ships no phase0 `fork_choice` suite: the earliest is +altair's, built from altair-shaped states even though altair changes nothing +about fork choice itself (`Store` accepts a block from any fork this module +implements; see `fork_choice.rs`'s own module doc). Landing altair's state +transition is what let this suite start running at all. + +### A note on earlier case counts + +Counts reported before the runners landed were too high by roughly sevenfold. +`collect_all_handlers` walked the fork directories and then delegated to +`collect`, which walks them again, so every case was emitted once per fork +shipping that runner. The cases were always being *run*; they were counted many +times over. Both collectors now share one suite walk. + +## A recurring bug: projecting when an accessor was needed + +Reach for a concrete per-fork projection, such as `altair_state(state)`, only +when the return type must be that fork's own. Reach through a `BeaconState` +accessor when the fields involved are shared. The trap is that a projection +like `altair_state(state)` matches only `BeaconState::Altair`, so it compiles +cleanly, passes the fork that introduced the field, and returns +`UnsupportedForFork` for every later fork that shares the exact same field +through a different variant. + +This caused five separate bugs during implementation: + +- Capella's withdrawal sweep, projected to capella's own state. +- Deneb reusing that same sweep, still projected to capella's state. +- Altair's participation fields, projected to altair's state, so every one of + the five later forks that also carries participation failed. +- Deneb's `process_attestation`, projected to deneb's state. +- `slash_validator` calling phase0's `initiate_validator_exit` at electra, + which also left electra's EIP-7251 churn cursor unadvanced, mispricing every + later exit processed in the same epoch. + +## Deliberate simplifications + +- Light client containers and suites are out of scope. +- `ssz_generic` exercises the SSZ library rather than the beacon containers, so + it is not a gate. +- The state transition mutates in place, as the specification does, so a state + passed to `state_transition` is left partly modified when a block turns out to + be invalid. Callers that need the pre-state clone it first, which is what the + fixture runners do. +- `ExecutionEngine` (`stf::mod`) stands in for a real execution client: just + `execution_valid: bool`, read straight from a fixture's `execution.yaml` + rather than a payload actually validated. + +## What the fixture format asserts by omission + +A case with a `post` state must succeed and land exactly on it. A case *without* +one must be **rejected**. The second half is what keeps the suites honest: an +implementation that accepted everything would otherwise pass every case that +ships a post-state. That rule lives in one place, `check_transition`, and every +state-comparing runner goes through it. + +Two consequences worth knowing: + +- Roughly a quarter of the phase0 `operations` cases are rejection cases, so the + invalid path gets as much coverage as the valid one. +- The `rewards` suite is the exception to state comparison: it compares the five + per-component delta vectors directly. That is sharper, because the components + are summed into balances, so a sign error in one component and a compensating + error in another would produce correct balances from incorrect deltas. + +## Where the specification's Python does more than it appears to + +Two places where a faithful-looking transcription is wrong, both found by the +fixtures rather than by reading: + +- `get_matching_target_attestations` evaluates `get_block_root` **inside** a list + comprehension, so it never runs when there are no attestations. That call has + its own range assertion, which fails for the epoch a state sits at the start of. + Hoisting it out of the loop rejects states the specification accepts. +- `get_attesting_indices` returns an unordered set, and `get_indexed_attestation` + sorts it. A committee is a *shuffled* slice of the registry, so filtering it in + position order yields attesters in shuffle order, which is almost never + ascending. `is_valid_indexed_attestation` requires sorted indices, so skipping + the sort rejects every valid attestation. + +Both are cases where the Python reads as if order or evaluation point does not +matter, and both change the result. + +[specs]: https://github.com/ethereum/consensus-specs From 57bf5913306fc2ad6106c09a6e5ac5bec5acb760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Fri, 4 Sep 2026 18:27:26 -0300 Subject: [PATCH 03/49] Merge pull request #3 from lambdaclass/feat/beacon-gossip-follower feat(beacon): follow mainnet gossip behind an `ethlambda beacon` sub-command --- CLAUDE.md | 106 ++- Cargo.lock | 27 +- Cargo.toml | 5 + Dockerfile | 2 +- README.md | 74 +- bin/ethlambda/Cargo.toml | 9 +- bin/ethlambda/assets/mainnet/genesis.ssz | Bin 0 -> 5404504 bytes bin/ethlambda/src/beacon.rs | 401 +++++++++++ bin/ethlambda/src/checkpoint_sync.rs | 215 +++++- bin/ethlambda/src/cli.rs | 597 +++++++++++++---- bin/ethlambda/src/command.rs | 175 ++++- bin/ethlambda/src/main.rs | 820 +++++++++++++++++------ crates/common/types/src/enr.rs | 75 +++ crates/common/types/src/lib.rs | 1 + crates/net/p2p/Cargo.toml | 14 +- crates/net/p2p/src/beacon/decode.rs | 418 ++++++++++++ crates/net/p2p/src/beacon/encoding.rs | 85 +++ crates/net/p2p/src/beacon/handler.rs | 233 +++++++ crates/net/p2p/src/beacon/messages.rs | 209 ++++++ crates/net/p2p/src/beacon/mod.rs | 57 ++ crates/net/p2p/src/beacon/protocols.rs | 109 +++ crates/net/p2p/src/beacon/swarm.rs | 163 +++++ crates/net/p2p/src/beacon/topics.rs | 148 ++++ crates/net/p2p/src/discovery/dial.rs | 134 ++-- crates/net/p2p/src/discovery/enr.rs | 140 ++-- crates/net/p2p/src/discovery/mod.rs | 21 +- crates/net/p2p/src/gossipsub/handler.rs | 357 ++++++---- crates/net/p2p/src/gossipsub/messages.rs | 9 + crates/net/p2p/src/gossipsub/mod.rs | 4 +- crates/net/p2p/src/lean/encoding.rs | 143 ++++ crates/net/p2p/src/lean/messages.rs | 34 + crates/net/p2p/src/lean/mod.rs | 12 + crates/net/p2p/src/lean/protocols.rs | 27 + crates/net/p2p/src/lib.rs | 602 ++++++++++++----- crates/net/p2p/src/metrics.rs | 44 ++ crates/net/p2p/src/req_resp/codec.rs | 427 +++++++----- crates/net/p2p/src/req_resp/encoding.rs | 8 + crates/net/p2p/src/req_resp/handlers.rs | 299 ++++++++- crates/net/p2p/src/req_resp/messages.rs | 100 ++- crates/net/p2p/src/req_resp/mod.rs | 12 +- crates/net/rpc/src/lib.rs | 93 ++- crates/net/rpc/tests/http_servers.rs | 136 ++++ docs/SUMMARY.md | 2 + docs/beacon_wire.md | 221 ++++++ docs/cli.md | 167 +++++ docs/discovery.md | 68 +- docs/metrics.md | 4 +- 47 files changed, 5908 insertions(+), 1099 deletions(-) create mode 100644 bin/ethlambda/assets/mainnet/genesis.ssz create mode 100644 bin/ethlambda/src/beacon.rs create mode 100644 crates/common/types/src/enr.rs create mode 100644 crates/net/p2p/src/beacon/decode.rs create mode 100644 crates/net/p2p/src/beacon/encoding.rs create mode 100644 crates/net/p2p/src/beacon/handler.rs create mode 100644 crates/net/p2p/src/beacon/messages.rs create mode 100644 crates/net/p2p/src/beacon/mod.rs create mode 100644 crates/net/p2p/src/beacon/protocols.rs create mode 100644 crates/net/p2p/src/beacon/swarm.rs create mode 100644 crates/net/p2p/src/beacon/topics.rs create mode 100644 crates/net/p2p/src/lean/encoding.rs create mode 100644 crates/net/p2p/src/lean/messages.rs create mode 100644 crates/net/p2p/src/lean/mod.rs create mode 100644 crates/net/p2p/src/lean/protocols.rs create mode 100644 crates/net/rpc/tests/http_servers.rs create mode 100644 docs/beacon_wire.md create mode 100644 docs/cli.md diff --git a/CLAUDE.md b/CLAUDE.md index e85c2c8bd..1fd39f168 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,6 +13,12 @@ Not to be confused with Ethereum consensus clients AKA Beacon Chain clients AKA ``` bin/ethlambda/ # Entry point, CLI, orchestration + ├─ src/main.rs # run_node: one entry point for both chains (see below) + ├─ src/cli.rs # Options { common, network: Lean | Mainnet } + ├─ src/command.rs # Sub-command dispatch + default-subcommand injection + ├─ src/beacon.rs # Mainnet wire params: built-in genesis, fork digest + ├─ src/checkpoint_sync.rs # Lean checkpoint sync (`/lean/v0/...`) + ├─ assets/mainnet/genesis.ssz # Mainnet genesis BeaconState (eth-clients/mainnet's file) └─ src/version.rs # Build-time version info (vergen-git2) crates/ blockchain/ # State machine actor (GenServer pattern) @@ -276,15 +282,15 @@ actual_slot = finalized_slot + 1 + relative_index ### Protocols - **Transport**: QUIC over UDP (TLS 1.3), plus TCP (noise + yamux) on the same port number as a fallback: a peer whose advertised `quic` doesn't answer can still be reached over TCP, and libp2p races both addresses within one dial (list order confers no preference; the default `dial_concurrency_factor` starts both handshakes) - - Binding TCP puts `--gossipsub-port` in the HTTP servers' namespace, so it must now differ from `--api-port`/`--metrics-port` too. `NodeOptions::validate_ports` rejects every clash before anything binds + - Binding TCP puts `--gossipsub-port` in the HTTP servers' namespace, so it must now differ from `--api-port`/`--metrics-port` too. `CommonOptions::validate_ports` rejects every clash before anything binds - **Gossipsub**: Blocks + Attestations (snappy raw compression) - Topic: `/leanconsensus/{fork_digest}/{block|aggregation|attestation_N}/ssz_snappy` - `fork_digest` is a 4-byte hex string (no `0x` prefix); currently the dummy `12345678` agreed across clients - Mesh size: 8 (6-12 bounds), heartbeat: 700ms - **Req/Resp**: Status, BlocksByRoot, BlocksByRange (snappy frame compression + varint length) -### Peer Discovery (discv5, opt-in) -- Off by default; `--discovery.enable` plus `--discovery.port` (own UDP socket, must differ from `--gossipsub-port`) +### Peer Discovery (discv5) +- Always on, on both chains, on `DEFAULT_DISCOVERY_PORT` (9000) unless `--discovery.port` says otherwise (own UDP socket, must differ from `--gossipsub-port`; checked once by `CommonOptions::validate_ports`). There is no `--discovery.enable`: mainnet bootnode ENRs are not statically dialable so a crawl is its only way to find a peer, and a lean node with no `--bootnodes` is in the same position. Co-located nodes on one host must each pass `--discovery.port` - Reuses ethrex's `DiscoveryServer` + `PeerTable` with discv4 disabled; `spawn` takes the prepared lean ENR, so the record ethrex serves is the one we report - ENR follows the beacon phase0 spec: `ip`/`udp`/`quic`/`tcp`/`secp256k1`/`eth2`/`attnets` - Admission mirrors lighthouse: `eth2.fork_digest` must match, `next_fork_*` may differ, a `quic` or `tcp` entry required. Handed to the peer table as `LeanFilter: PeerFilter`, so records are judged on arrival, not at dial time; a reject is re-judged on a higher-`seq` ENR @@ -297,12 +303,104 @@ actual_slot = finalized_slot + 1 + relative_index ### Message IDs - 20-byte truncated SHA256 of: domain (valid/invalid snappy) + topic + data +## One startup path for both chains (`bin/ethlambda/src/main.rs`) + +`ethlambda node` and `ethlambda beacon` are the same entry point. Each parses +into one `cli::Options { common, network }`, where `network` is +`Network::Lean(LeanOptions)` or `Network::Mainnet`. The lean variant carries +that chain's own flags, so a lean-only flag is unreachable on the mainnet path +by construction rather than by an `Option` nobody unwraps; `Mainnet` is a unit +variant, since every flag `beacon` takes is a common one. + +`run_node` owns everything that is not chain-specific, in order: the discv5 +port check, metrics registration, the banner and version log, the +`RLIMIT_NOFILE` raise, the `HIVE_LEAN_TEST_DRIVER` early return (lean-only, and +it must still precede key loading), `--node-key` resolution, reading +`--bootnodes`, and building the aggregator, sync-status and event handles. + +It then branches **once**, on `network`, both arms inline, each evaluating to a +`ChainSetup`: the wire configuration, the ENR entries that describe it, the +`Store` the req/resp handlers answer from, the node-name roster, and an `Option` +holding the validator keys and `BlockChainConfig`. The rest of the discv5 +configuration is the node key, the ports, the bootnodes and the peer target, +which are operator input and identical either way, so `run_node` fills those in +once below the match rather than having each arm repeat them. +Everything after that match is shared again: one `build_swarm`, one +`P2P::spawn`, one `start_rpc_server`. `ChainSetup.chain` being `None` is what +ends the mainnet path, through a `let ... else` that returns into the shared +`wait_for_shutdown`; lean falls through it into `BlockChain::spawn` and the +`InitP2P`/`InitBlockChain` wiring. + +`ChainSetup` is a data bag, not an abstraction. The match that fills it stays +inline, because moving it into a method would relocate the branch rather than +remove it. + +Two consequences of "one call site" worth knowing. `P2P::spawn` now runs +*before* `BlockChain::spawn`, so gossip arriving in between hits a `P2PServer` +whose `blockchain` is still `None` and is dropped; every access is an `if let +Some`, and the window is a handful of statements. And `beacon` now binds +`--api-port` and serves the `/lean/v0` routes off an empty in-memory store, +which answers for a chain that is not running; that is an accepted placeholder, +not a design. + +`RunningNode.blockchain` is an `Option` for the same reason: the mainnet +follower decodes gossip and imports nothing, so it has no chain actor to stop or +join. It is why mainnet gets the graceful shutdown, metrics bootstrap and +fd-limit raise it previously lacked (it used to park on +`std::future::pending()`). + +`docs/cli.md` has the step-by-step table. + +### Mainnet's genesis is built into the binary + +`beacon`'s `genesis_time` and `genesis_validators_root`, which the fork digest +keying every gossip topic, the ENR `eth2` entry and discv5 admission are +computed from, come from `bin/ethlambda/assets/mainnet/genesis.ssz`. That is +`metadata/genesis.ssz` from `eth-clients/mainnet` byte for byte, the same repo +`beacon::MAINNET_BOOTNODES` is copied from, so both of this chain's hardcoded +values have one upstream; `beacon::tests::the_shipped_state_is_eth_clients_file` +pins its SHA-256 so replacing it has to be deliberate. +`beacon::mainnet_genesis_state` decodes it as a **phase0** `BeaconState`, whole +rather than reading the prefix those two fields sit in, so a corrupt asset fails +loudly at startup rather than yielding two plausible numbers. 5.4 MB stored +uncompressed and about 4 ms to decode: a deflated copy is under a third the +size, but paying for it means a zip or gzip decoder in the dependency graph to +read one build-time constant. + +Two consequences. `beacon` now takes **no** network configuration: a bare +`ethlambda beacon` boots, and `--checkpoint-sync-url` is accepted there but +unused (it is declared once for both sub-commands, and the anchor work will want +it back). And a build with `ethlambda-types/preset-minimal` on cannot decode +this asset, because the minimal preset shortens the state's fixed-size vectors; +nothing enables that feature for this binary, and failing is the right answer if +anything does. + +These values used to come from a Beacon API's `/eth/v1/beacon/genesis`, which +made a `beacon` run depend on a checkpoint provider being reachable. They are +properties of the chain, not of a provider. Lean's checkpoint sync is untouched: +it fetches a *finalized* anchor, which genuinely has no local source. +The URL cleaning, base-URL trim and first-success fan-out that the two paths +once shared through a `checkpoint_common` module now live in +`checkpoint_sync.rs`, its only remaining caller. + ## HTTP Servers (API + Metrics) The RPC crate serves the API router (`--api-port`, default 5052) and the metrics/debug routers (`--metrics-port`, default 5054). When the two ports differ it binds two independent Axum servers; when they are equal it merges all three routers onto a single listener, so pointing both flags at -one port is supported and not a misconfiguration. See [`docs/rpc.md`](docs/rpc.md) for the full reference: CLI flags and defaults, the API endpoints (health, finalized state/block, justified checkpoint, blocks by root/slot, fork-choice tree + D3.js UI, runtime aggregator toggle), the metrics/debug endpoints (Prometheus `/metrics`, jemalloc heap profiling), the Hive test-driver endpoints, plus request/response shapes, status codes, and content types. +one port is supported and not a misconfiguration. + +Both sub-commands bind through one call to `start_rpc_server`, from one site in `run_node`, so +both serve all three routers. `beacon` reaches it with placeholders: the empty in-memory `Store` +its `P2PServer` already holds, an `AggregatorController` seeded `false`, and a default +`SyncStatusController` and `EventBus`. Those endpoints therefore answer for a chain that is not +running. That is deliberate for now, to keep one HTTP call site rather than two; giving the beacon +follower its own surface belongs with the anchor work. `start_http_servers(config, api_router, +shutdown)` still takes `api_router` as an `Option` and `crates/net/rpc/tests/http_servers.rs` +still covers the `None` arm, because that is the shape the beacon follower returns to once it has +a surface of its own. + +See [`docs/rpc.md`](docs/rpc.md) for the full reference: CLI flags and defaults, the API endpoints (health, finalized state/block, justified checkpoint, blocks by root/slot, fork-choice tree + D3.js UI, runtime aggregator toggle), the metrics/debug endpoints (Prometheus `/metrics`, jemalloc heap profiling), the Hive test-driver endpoints, plus request/response shapes, status codes, and content types. ## Beacon Chain types (`crates/common/types/src/beacon/`) diff --git a/Cargo.lock b/Cargo.lock index d2448c331..b067af857 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1492,7 +1492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090" dependencies = [ "data-encoding", - "syn 2.0.117", + "syn 1.0.109", ] [[package]] @@ -1932,9 +1932,11 @@ dependencies = [ "libssz-types 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "rayon", "reqwest", + "secp256k1 0.30.0", "serde", "serde_json", "serde_yaml_ng", + "sha2", "tempfile", "thiserror 2.0.18", "tikv-jemallocator", @@ -2022,6 +2024,7 @@ dependencies = [ "futures", "hex", "libp2p", + "libp2p-mplex", "libssz 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "libssz-derive 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", "libssz-merkle 0.3.0 (git+https://github.com/lambdaclass/libssz?rev=36802dd1d3e3a83d95d2ac552647539cbe3f7fd7)", @@ -4129,6 +4132,24 @@ dependencies = [ "web-time", ] +[[package]] +name = "libp2p-mplex" +version = "0.44.0" +source = "git+https://github.com/lambdaclass/rust-libp2p.git?rev=2f14d0ec9665a01cfb6a02326c90628c4bba521c#2f14d0ec9665a01cfb6a02326c90628c4bba521c" +dependencies = [ + "asynchronous-codec", + "bytes", + "futures", + "libp2p-core", + "libp2p-identity", + "nohash-hasher", + "parking_lot", + "rand 0.8.6", + "smallvec", + "tracing", + "unsigned-varint", +] + [[package]] name = "libp2p-noise" version = "0.47.0" @@ -7821,6 +7842,10 @@ name = "unsigned-varint" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" +dependencies = [ + "asynchronous-codec", + "bytes", +] [[package]] name = "untrusted" diff --git a/Cargo.toml b/Cargo.toml index b92203c5e..4eed5b35a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,6 +81,11 @@ prometheus = "0.14" clap = { version = "4.3", features = ["derive", "env"] } +# Version pinned to ethrex's workspace: `SecretKey` crosses that API boundary. +# `rand` is re-exported as `secp256k1::rand`, so nothing needs a direct dep on it +# to seed a key. +secp256k1 = { version = "0.30.0", default-features = false, features = ["global-context", "rand"] } + # Merkleizing a beacon state is almost entirely SHA-256 compressions, so which # implementation `sha2` picks matters. What `asm` actually buys is aarch64: on # x86/x86_64, sha2 0.10.9 compiles its `x86` backend and dispatches to the SHA-NI diff --git a/Dockerfile b/Dockerfile index 16e62239c..565536c16 100644 --- a/Dockerfile +++ b/Dockerfile @@ -75,7 +75,7 @@ COPY --from=builder /app/ethlambda /usr/local/bin # Copy licenses COPY LICENSE ./ -# 9000/tcp, 9000/udp - P2P networking (discv5 when --discovery.enable) +# 9000/tcp, 9000/udp - P2P networking (discv5, always on; --discovery.port) # 9001/udp - libp2p QUIC connections # 9001/tcp - libp2p TCP (noise + yamux) connections, the fallback transport # 5052 - API RPC diff --git a/README.md b/README.md index 3f4012abf..b4fcbd7f6 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,78 @@ make docker-build DOCKER_TAG=local Run `make help` or take a look at our [`Makefile`](./Makefile) for other useful commands. +### Running the node + +The binary follows one of two chains, chosen by a sub-command: + +```sh +cargo build --release +./target/release/ethlambda [flags] +``` + +[`docs/cli.md`](./docs/cli.md) is the full flag reference for both. + +#### `ethlambda node` — the Lean consensus chain + +This is what the rest of this README is about, and it is the default: a bare +flag list with no sub-command still runs the node, so existing scripts and +Docker entrypoints keep working unchanged. + +It needs a genesis config, a validator registry, a bootnode list and this +node's own keys, all of which a devnet generates for you: + +```sh +./target/release/ethlambda node \ + --genesis config/config.yaml \ + --validators config/annotated_validators.yaml \ + --bootnodes config/nodes.yaml \ + --validator-config config/validator-config.yaml \ + --hash-sig-keys-dir config/hash-sig-keys \ + --node-key config/ethlambda_0.key \ + --node-id ethlambda_0 \ + --data-dir ./data \ + --is-aggregator +``` + +`--node-id` picks this node's entry out of `annotated_validators.yaml`, so it +is what decides which validators this process runs. + +The easiest way to get those files is `make run-devnet`, which generates them +under `lean-quickstart/local-devnet/genesis/`. See +[Running in a devnet](#running-in-a-devnet) below. + +> **Important:** at least one node on the network must run with +> `--is-aggregator`, or attestations are never aggregated into blocks and the +> chain produces blocks but never finalizes. + +#### `ethlambda beacon` — the Ethereum Beacon Chain + +Follows mainnet's gossip. It derives the fork digest from the chain's genesis, +joins discv5, subscribes to the seven global gossip topics, and logs every +block and aggregate attestation it decodes: + +```sh +./target/release/ethlambda beacon +``` + +No flag is required. The `genesis_time` and `genesis_validators_root` the fork +digest is computed from come from mainnet's genesis `BeaconState`, which is +built into the binary (`eth-clients/mainnet`'s `genesis.ssz`, byte for byte), so +startup touches no network and depends on no checkpoint provider. `--node-key` +is worth passing anyway: without one a fresh identity is generated in memory +for that run, so the PeerId and ENR change on every restart. + +Within about half a minute you should see: + +``` +Beacon block decoded slot=15115256 proposer=2241096 fork="fulu" block_root=455f66bc bytes=158301 +Beacon aggregate attestation decoded slot=15115256 aggregator=111250 attesters=442 … +``` + +This is a follower and nothing more: it keeps no chain, imports nothing, and +publishes nothing. See [`docs/beacon_wire.md`](./docs/beacon_wire.md) for what +goes on the wire and how to tell a healthy run from a broken one. + ### Running in a devnet To run a local devnet with multiple clients using [lean-quickstart](https://github.com/blockblaz/lean-quickstart): @@ -49,8 +121,6 @@ Press `Ctrl+C` to stop all nodes. > ``` > To persist across reboots, add to `/etc/sysctl.conf`. For Docker, pass `--sysctl net.core.rmem_max=7340032 --sysctl net.core.wmem_max=7340032`. -> **Important:** When running nodes manually (outside `make run-devnet`), at least one node must be started with `--is-aggregator` for attestations to be aggregated and included in blocks. Without this flag, the network will produce blocks but never finalize. - For custom devnet configurations, go to `lean-quickstart/local-devnet/genesis/validator-config.yaml` and edit the file before running the command above. See `lean-quickstart`'s documentation for more details on how to configure the devnet. ## Philosophy diff --git a/bin/ethlambda/Cargo.toml b/bin/ethlambda/Cargo.toml index 206766b14..989333c59 100644 --- a/bin/ethlambda/Cargo.toml +++ b/bin/ethlambda/Cargo.toml @@ -36,7 +36,6 @@ libssz-types.workspace = true tokio.workspace = true tokio-util.workspace = true - tracing.workspace = true tracing-subscriber = "0.3" @@ -50,6 +49,10 @@ reqwest.workspace = true thiserror.workspace = true eyre.workspace = true +# For `resolve_node_key`'s ephemeral-key generation when `--node-key` is omitted. +secp256k1.workspace = true + + tikv-jemallocator = { workspace = true, optional = true } libc.workspace = true @@ -61,5 +64,9 @@ libc.workspace = true tokio = { workspace = true, features = ["test-util"] } tempfile = "3" +# Pins the SHA-256 of the built-in mainnet genesis state, so swapping that +# asset has to be deliberate. Tests only: nothing in the binary hashes it. +sha2.workspace = true + [build-dependencies] vergen-git2.workspace = true diff --git a/bin/ethlambda/assets/mainnet/genesis.ssz b/bin/ethlambda/assets/mainnet/genesis.ssz new file mode 100644 index 0000000000000000000000000000000000000000..f68d0e967ec7d5937f8a27f8f320b2270b675ca6 GIT binary patch literal 5404504 zcmeF)b&%@9ymE z?%jKL&;GMJJM(#GoN-3<@qFh!=l47x5Nqey*EsMmUlqP899B6))0AgBhDFR1^K#`H zJMKUG?q$)}$LgINP&MhtN&os|{%?F8-k7#Y+sxM<4Jue``;^zC1|O@vY}aQu`n;O8 zqxjfQsh?c_zwz&2h5`yGpnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUg zfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7> z3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36A zpnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim} z0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7j zD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUg zfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7> z3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36A zpnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim} z0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7j zD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUg zfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7> z3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36A zpnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim} z0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7j zD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUg zfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7> z3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36A zpnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim} z0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7j zD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUg zfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7> z3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36A zpnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim} z0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7j zD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUg zfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7> z3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36A zpnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim} z0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7j zD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUg zfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7> z3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36A zpnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim}0tzUgfC36Apnw7jD4>7>3Mim} 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
_n>6gaSfjU_8;|+jA)`TP*moWnm5N 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

iuwRa?>P@BNU|P=<9{AdUcUwBpJJuf_-<< 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

x~^jzm26K6vw1YZHaAY)!5Rhs6bo4{ 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

=OJk_KeM62pGy#qWde^z#o!RC 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

hEZu3 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

UM}5JU)6Y;L0-AyjuxeL#O3b% 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

KkM91*HSSN^{PptDK$BbK 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� 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