feat(chain): implement BRIP-0008 hysteresis update for Fulu fork#3081
feat(chain): implement BRIP-0008 hysteresis update for Fulu fork#3081
Conversation
…Fulu fork Add the Fulu fork (CL component of the Fusaka hardfork) with: - BRIP-0008: Fork-gated hysteresis parameter updates that improve validator capital efficiency by reducing the upward buffer from 125% to ~110% of the effective balance increment (HysteresisQuotient: 4->100, UpwardMultiplier: 5->10, DownwardMultiplier: 1->1 unchanged). - PoL vNext: New EVMInflationAddressFulu and EVMInflationPerBlockFulu fields following the same pattern as the Genesis-to-Deneb1 inflation migration. Values are placeholders pending PoL vNext design finalization. - Fulu fork plumbing: version constant (0x06000000), fork time in chain spec, fork ordering validation, state upgrade handler, Engine API routing, consensus type support, and osakaTime in EL genesis configs. All devnet/testnet/mainnet chain specs and TOML configs updated with placeholder values (devnet: active from genesis, testnet/mainnet: far future). https://claude.ai/code/session_01WL9ZgSDBYTcr1X91AYuPrU
…enesis Devnet now starts at the Fulu fork (FuluForkTime=0), so e2e tests that hardcoded Electra1 as the expected genesis fork version need updating. https://claude.ai/code/session_01WL9ZgSDBYTcr1X91AYuPrU
There was a problem hiding this comment.
Pull request overview
Implements the Fulu fork across the consensus layer, including fork-gated BRIP-0008 hysteresis parameter updates, PoL vNext inflation placeholders, and the required fork plumbing/routing so both CL and EL config paths recognize the new fork.
Changes:
- Add Fulu (0x06000000) fork version support and fork-time plumbing across chain spec, state upgrade handling, and consensus types.
- Gate hysteresis parameters by active fork (timestamp-based) per BRIP-0008, and add Fulu-specific spec fields.
- Extend EL genesis / network config fixtures with osakaTime and add Fulu placeholders to TOML chain specs.
Reviewed changes
Copilot reviewed 28 out of 28 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| testing/simulated/el-genesis-files/eth-genesis.json | Adds osakaTime to simulated EL genesis config. |
| testing/networks/80094/spec.toml | Adds fulu-fork-time and Fulu hysteresis/PoL placeholder fields for network 80094. |
| testing/networks/80094/eth-genesis.json | Adds osakaTime placeholder for network 80094 EL genesis. |
| testing/networks/80069/spec.toml | Adds fulu-fork-time and Fulu hysteresis/PoL placeholder fields for network 80069. |
| testing/networks/80069/eth-genesis.json | Adds osakaTime placeholder for network 80069 EL genesis. |
| testing/files/spec.toml | Adds Fulu fork time and Fulu hysteresis/PoL fields for test fixtures. |
| testing/files/eth-genesis.json | Adds osakaTime to test fixture EL genesis config. |
| state-transition/core/state_processor_forks.go | Adds Fulu fork processing, state upgrade handler, and fork logging. |
| state-transition/core/state_processor.go | Uses fork-gated hysteresis parameters during effective balance updates. |
| primitives/version/versions.go | Introduces Fulu() version constant and removes unused Electra2. |
| primitives/version/supported.go | Adds Fulu to the supported fork version list. |
| primitives/version/name.go | Adds human-readable name mapping for Fulu. |
| execution/client/ethclient/engine_test.go | Updates invalid-version test to use Capella() instead of removed Electra2(). |
| execution/client/ethclient/engine.go | Routes Fulu to the same Engine API variants as Electra1 where applicable. |
| consensus-types/types/signed_beacon_block.go | Allows creating empty signed blocks for Fulu version. |
| consensus-types/types/payload.go | Allows payload header conversion for Fulu version. |
| consensus-types/types/block.go | Allows beacon block creation for Fulu version. |
| config/spec/testnet.go | Adds placeholder FuluForkTime to testnet chain spec data. |
| config/spec/mainnet.go | Adds Fulu fork time + Fulu hysteresis/PoL placeholder constants and wires into mainnet spec data. |
| config/spec/devnet.go | Sets devnet to start with Fulu active and adds Fulu PoL inflation config. |
| cli/commands/genesis/payload.go | Extends supported fork range checks up to Fulu for genesis payload header handling. |
| chain/spec_test.go | Updates fork-order validation tests to include Fulu. |
| chain/spec.go | Adds Fulu fork time, enforces ordering including Fulu, gates hysteresis and PoL fields by active fork. |
| chain/helpers_test.go | Updates helper spec construction to include FuluForkTime. |
| chain/helpers.go | Extends fork-version selection by timestamp to include Fulu. |
| chain/data.go | Adds SpecData fields for Fulu fork time, Fulu hysteresis parameters, and Fulu PoL inflation fields. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 21e8648026
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The simulated test chain spec providers override Electra1ForkTime to far-future values but didn't set FuluForkTime, causing fork ordering violations since testnet's FuluForkTime (9999999999999999) was smaller than the overridden Electra1ForkTime (math.MaxInt64). https://claude.ai/code/session_01WL9ZgSDBYTcr1X91AYuPrU
Expand the comment in processEffectiveBalanceUpdates to explain that the previous block's payload timestamp is used for fork gating because processEpoch runs inside ProcessSlots (before ProcessFork updates the state). This means Fulu hysteresis values take effect one epoch after fork activation at an exact epoch boundary — acceptable since hysteresis only affects capital efficiency, not consensus safety. https://claude.ai/code/session_01WL9ZgSDBYTcr1X91AYuPrU
The testing/simulated/el-genesis-files/eth-genesis.json file is paired with ProvideSimulationChainSpec where Electra, Electra1, and Fulu are all far-future. The file intentionally omits pragueTime to test pre- Pectra behavior. Adding osakaTime=0 created an invalid config (Osaka without Prague), causing Geth containers to fail to start in simulated tests. https://claude.ai/code/session_01WL9ZgSDBYTcr1X91AYuPrU
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3081 +/- ##
==========================================
- Coverage 60.44% 60.41% -0.04%
==========================================
Files 367 367
Lines 18610 18698 +88
==========================================
+ Hits 11249 11296 +47
- Misses 6422 6458 +36
- Partials 939 944 +5
🚀 New features to boost your workflow:
|
| switch fv { | ||
| case version.Deneb1(), version.Electra(), version.Electra1(): | ||
| switch { | ||
| case version.EqualsOrIsAfter(fv, version.Fulu()): |
There was a problem hiding this comment.
Should we not check for exact version here? If we add Fulu1 (or future fork) then we would silently return here instead of panicking which is how the switch was written explicitly before.
| case version.EqualsOrIsAfter(fv, version.Fulu()): | |
| case version.Equals(fv, version.Fulu()): |
There was a problem hiding this comment.
Well I'd argue it's more correct now. For example the value we set in Deneb1 EVMInflationAddressDeneb1 is actually valid from fork Deneb1 and onwards (including Electra and Electra1) until its overriden with a new value. Which is now EVMInflationAddressFulu; this value is valid until overriden again. So for Fulu1 it would also be used by default.
Also adjusted other functions to work like this in 4d88d47
|
|
||
| // HysteresisDownwardMultiplier returns the multiplier used when checking | ||
| // if the effective balance should be decreased. | ||
| HysteresisDownwardMultiplier() math.U64 |
There was a problem hiding this comment.
Looking at the code its unclear why HysteresisUpwardMultiplier takes an argument but HysteresisDownwardMultiplier does not. Since HysteresisDownwardMultiplier does not change in the fork there is no need to, but maybe add an inline comment (or pass a unused timetsamp)
…om:berachain/beacon-kit into claude/implement-brip-0008-pol-vnext-p043C
https://github.com/berachain/BRIPs/blob/main/meta/BRIP-0010.md
Add the Fulu fork (CL component of the Fusaka hardfork) with:
BRIP-0008: Fork-gated hysteresis parameter updates that improve validator capital efficiency by reducing the upward buffer from 125% to ~110% of the effective balance increment (HysteresisQuotient: 4->100, UpwardMultiplier: 5->10, DownwardMultiplier: 1->1 unchanged).
PoL vNext: New EVMInflationAddressFulu and EVMInflationPerBlockFulu fields following the same pattern as the Genesis-to-Deneb1 inflation migration. Values are placeholders pending PoL vNext design finalization.
Fulu fork plumbing: version constant (0x06000000), fork time in chain spec, fork ordering validation, state upgrade handler, Engine API routing, consensus type support, and osakaTime in EL genesis configs.
All devnet/testnet/mainnet chain specs and TOML configs updated with placeholder values (devnet: active from genesis, testnet/mainnet: far future).