feat(hardfork): implement Epsilon hardfork with 4 contract bytecodes#327
Merged
nekomoto911 merged 2 commits intogravity-testnet-v1.4from Apr 13, 2026
Merged
feat(hardfork): implement Epsilon hardfork with 4 contract bytecodes#327nekomoto911 merged 2 commits intogravity-testnet-v1.4from
nekomoto911 merged 2 commits intogravity-testnet-v1.4from
Conversation
Mirrors the Delta pattern (commit 35f4e02 / 6ad34e3) for the v1.3 → v1.4 contract upgrade landed in gravity_chain_core_contracts PR #71. Replaces 4 contract bytecodes; no storage patches needed (the contract-side fix in PR #71 keeps every storage byte at the same slot across the upgrade). Contracts replaced: - ValidatorManagement (PR #56): D3-2 underbonded eviction (Phase 1) and percentage-based Phase 2 performance threshold, skip-epoch-1 rule - Reconfiguration (PR #63): evictUnderperformingValidators() call site moved out of _applyReconfiguration and into checkAndStartTransition / governanceReconfigure, fixing the DKG synchronization halt - ValidatorConfig (PR #63): new autoEvictThresholdPct uint64 field, declared between autoEvictEnabled and __deprecated_autoEvictThreshold so it packs with autoEvictEnabled in slot 4 — keeps storage layout byte-identical to v1.3 (PendingConfig stays at 6 slots; _initialized stays at slot 12) - GBridgeReceiver (PR #66): _processedNonces mapping replaced with a __deprecated_processedNonces gap; isProcessed() removed. This hardfork is also the first time GBridgeReceiver is upgraded since v1.0, so it adds the trustedSourceId immutable that didn't exist on the originally-deployed receiver. Wiring touchpoints (mirror Delta exactly): - crates/chainspec/src/gravity.rs: add Epsilon variant to GravityHardfork - crates/chainspec/src/spec.rs: parse epsilonBlock from genesis extra_fields - crates/ethereum/evm/src/hardfork/mod.rs: pub mod epsilon - crates/ethereum/evm/src/hardfork/epsilon.rs: HardforkUpgrades impl with 3 system_upgrades and 1 extra_upgrade for GBridgeReceiver. Modeled on delta.rs but with no storage_patches. - crates/ethereum/evm/src/parallel_execute.rs: dispatch alongside Gamma/Delta in the post-balance-increment block Bytecodes embedded via include_bytes! from bytecodes/epsilon/{ValidatorManagement,Reconfiguration,ValidatorConfig, GBridgeReceiver}.bin. Generated by the new scripts/build_epsilon_bytecodes.sh in the contracts repo, which extracts deployedBytecode from forge artifacts and patches the GBridgeReceiver immutables with the testnet values: trustedBridge = 0x79226649b3A20231e6b468a9E1AbBD23d3DFbbC6 trustedSourceId = 11155111 (Sepolia) Both values were obtained by reading the live testnet at 34.186.189.129:8545 (trustedBridge() getter on the existing receiver; getLatestNonce(0,11155111) on NativeOracle to confirm the relayer source). The AST id ordering of the patch script is verified by EpsilonGBridgeReceiverPatchSanity in the contracts repo. Test wiring: - crates/pipe-exec-layer-ext-v2/execute/gravity_hardfork.json: add epsilonBlock=30 - crates/pipe-exec-layer-ext-v2/execute/tests/gravity_hardfork_test.rs: add EPSILON_BLOCK constant and the same 2-assertion transitions_at_block pattern Delta uses. Also drops a stale unused `use reth_ethereum_forks::Hardforks;` import that was preventing the test from even compiling on the v1.4 branch (the trait method is reached via the inherent ChainHardforks impl). Verification: - cargo build -p reth-chainspec -p reth-evm-ethereum: clean - cargo test -p reth-pipe-exec-layer-ext-v2 --test gravity_hardfork_test: test_gamma_hardfork passes; the test pushes blocks past EPSILON_BLOCK so apply_hardfork_upgrades(&EpsilonHardfork, state) runs end-to-end without panicking. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- epsilon.rs / parallel_execute.rs: apply fmt diffs from CI (line wrapping) - epsilon.rs / alpha.rs / beta.rs / gamma.rs: add backticks to bare type names in doc comments (clippy::doc-markdown). Pre-existing on alpha/beta/ gamma but only surfaced now because v1.4 is the first branch to push a PR that triggers full clippy. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ByteYue
added a commit
that referenced
this pull request
Apr 23, 2026
…327) * feat(hardfork): implement Epsilon hardfork with 4 contract bytecodes Mirrors the Delta pattern (commit 35f4e02 / 6ad34e3) for the v1.3 → v1.4 contract upgrade landed in gravity_chain_core_contracts PR #71. Replaces 4 contract bytecodes; no storage patches needed (the contract-side fix in PR #71 keeps every storage byte at the same slot across the upgrade). Contracts replaced: - ValidatorManagement (PR #56): D3-2 underbonded eviction (Phase 1) and percentage-based Phase 2 performance threshold, skip-epoch-1 rule - Reconfiguration (PR #63): evictUnderperformingValidators() call site moved out of _applyReconfiguration and into checkAndStartTransition / governanceReconfigure, fixing the DKG synchronization halt - ValidatorConfig (PR #63): new autoEvictThresholdPct uint64 field, declared between autoEvictEnabled and __deprecated_autoEvictThreshold so it packs with autoEvictEnabled in slot 4 — keeps storage layout byte-identical to v1.3 (PendingConfig stays at 6 slots; _initialized stays at slot 12) - GBridgeReceiver (PR #66): _processedNonces mapping replaced with a __deprecated_processedNonces gap; isProcessed() removed. This hardfork is also the first time GBridgeReceiver is upgraded since v1.0, so it adds the trustedSourceId immutable that didn't exist on the originally-deployed receiver. Wiring touchpoints (mirror Delta exactly): - crates/chainspec/src/gravity.rs: add Epsilon variant to GravityHardfork - crates/chainspec/src/spec.rs: parse epsilonBlock from genesis extra_fields - crates/ethereum/evm/src/hardfork/mod.rs: pub mod epsilon - crates/ethereum/evm/src/hardfork/epsilon.rs: HardforkUpgrades impl with 3 system_upgrades and 1 extra_upgrade for GBridgeReceiver. Modeled on delta.rs but with no storage_patches. - crates/ethereum/evm/src/parallel_execute.rs: dispatch alongside Gamma/Delta in the post-balance-increment block Bytecodes embedded via include_bytes! from bytecodes/epsilon/{ValidatorManagement,Reconfiguration,ValidatorConfig, GBridgeReceiver}.bin. Generated by the new scripts/build_epsilon_bytecodes.sh in the contracts repo, which extracts deployedBytecode from forge artifacts and patches the GBridgeReceiver immutables with the testnet values: trustedBridge = 0x79226649b3A20231e6b468a9E1AbBD23d3DFbbC6 trustedSourceId = 11155111 (Sepolia) Both values were obtained by reading the live testnet at 34.186.189.129:8545 (trustedBridge() getter on the existing receiver; getLatestNonce(0,11155111) on NativeOracle to confirm the relayer source). The AST id ordering of the patch script is verified by EpsilonGBridgeReceiverPatchSanity in the contracts repo. Test wiring: - crates/pipe-exec-layer-ext-v2/execute/gravity_hardfork.json: add epsilonBlock=30 - crates/pipe-exec-layer-ext-v2/execute/tests/gravity_hardfork_test.rs: add EPSILON_BLOCK constant and the same 2-assertion transitions_at_block pattern Delta uses. Also drops a stale unused `use reth_ethereum_forks::Hardforks;` import that was preventing the test from even compiling on the v1.4 branch (the trait method is reached via the inherent ChainHardforks impl). Verification: - cargo build -p reth-chainspec -p reth-evm-ethereum: clean - cargo test -p reth-pipe-exec-layer-ext-v2 --test gravity_hardfork_test: test_gamma_hardfork passes; the test pushes blocks past EPSILON_BLOCK so apply_hardfork_upgrades(&EpsilonHardfork, state) runs end-to-end without panicking. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style(hardfork): apply cargo fmt + clippy doc-markdown fixes from CI - epsilon.rs / parallel_execute.rs: apply fmt diffs from CI (line wrapping) - epsilon.rs / alpha.rs / beta.rs / gamma.rs: add backticks to bare type names in doc comments (clippy::doc-markdown). Pre-existing on alpha/beta/ gamma but only surfaced now because v1.4 is the first branch to push a PR that triggers full clippy. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> (cherry picked from commit 15e07d9)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Mirrors the Delta pattern (commit
35f4e02/6ad34e3f8) for the v1.3 → v1.4 contract upgrade landed ingravity_chain_core_contractsPR #71. Replaces 4 contract bytecodes; no storage patches are needed — the contract-side fix in PR #71 keeps every storage byte at the same slot across the upgrade, so Epsilon is a pure bytecode-replacement hardfork.Contracts replaced
ValidatorManagement0x...2001Reconfiguration0x...2003evictUnderperformingValidators()call site moved out of_applyReconfigurationand intocheckAndStartTransition/governanceReconfigure(fixes DKG sync halt)ValidatorConfig0x...1002autoEvictThresholdPct uint64, declared betweenautoEvictEnabledand__deprecated_autoEvictThresholdso it packs withautoEvictEnabledin slot 4 — keeps storage layout byte-identical to v1.3GBridgeReceiver0x595475934ed7d9faa7fca28341c2ce583904a44e(testnet)_processedNoncesmapping →__deprecated_processedNoncesgap,isProcessed()removed. Also adds thetrustedSourceIdimmutable that did not exist on the originally-deployed v1.0 receiverGBridgeReceiver — first upgrade since v1.0
The on-chain
GBridgeReceiverat0x595475934ed7d9faa7fca28341c2ce583904a44ewas deployed byGenesis.solat testnet bring-up using the v1.0 source — neither Gamma nor Delta touched it. v1.0 only had one immutable (trustedBridge) and did not validatesourceId. v1.4 adds a second immutable (trustedSourceId) and enforces it in_handlePortalMessage.The on-chain values were obtained by reading the live testnet at
34.186.189.129:8545:So the relayer source is Sepolia (
11155111). Thebytecodes/epsilon/GBridgeReceiver.binshipped here has both immutables pre-patched with these testnet values viascripts/build_epsilon_bytecodes.shin the contracts repo. For non-testnet environments, regenerate the.binwith the matching values.The AST id ordering used by the patch script (lower id =
trustedBridge, higher id =trustedSourceId) is verified byEpsilonGBridgeReceiverPatchSanity.t.solin the contracts repo, which deploys a fresh receiver and asserts the offsets match.Wiring
Mirrors Delta exactly:
crates/chainspec/src/gravity.rs— addEpsilonvariant toGravityHardforkcrates/chainspec/src/spec.rs— parseepsilonBlockfromgenesis.config.extra_fieldscrates/ethereum/evm/src/hardfork/mod.rs—pub mod epsiloncrates/ethereum/evm/src/hardfork/epsilon.rs—HardforkUpgradesimpl with 3system_upgradesand 1extra_upgradesforGBridgeReceiver. Nostorage_patches(uses trait default).crates/ethereum/evm/src/parallel_execute.rs— dispatch alongside Gamma/Delta in the post-balance-increment blockcrates/ethereum/evm/src/hardfork/bytecodes/epsilon/{ValidatorManagement,Reconfiguration,ValidatorConfig,GBridgeReceiver}.bin— embedded viainclude_bytes!Test wiring
crates/pipe-exec-layer-ext-v2/execute/gravity_hardfork.json—"epsilonBlock": 30crates/pipe-exec-layer-ext-v2/execute/tests/gravity_hardfork_test.rs—EPSILON_BLOCK = 30constant + the same 2-assertiontransitions_at_blockpattern Delta uses.Also drops a stale
use reth_ethereum_forks::Hardforks;import that was preventing the test from even compiling on the v1.4 branch (reth-ethereum-forksis not a direct dependency of the test crate). The trait method is reached via the inherentChainHardforksimpl, so theuseline is unnecessary.Test plan
cargo build -p reth-chainspec -p reth-evm-ethereum— cleancargo test -p reth-pipe-exec-layer-ext-v2 --test gravity_hardfork_test—test_gamma_hardforkpasses. The test pushes blocks pastEPSILON_BLOCK=30(target =GAMMA_BLOCK + 30 = 50), soapply_hardfork_upgrades(&EpsilonHardfork, state)runs end-to-end without panicking.epsilonBlockin the testnet genesis to a target activation block, restart nodes, then runbash scripts/verify_hardfork/verify.sh epsilon http://34.186.189.129:8545from the contracts repo. Phase 1 (codehash check on the 3 system contracts) and Phase 2 (smoke tests forautoEvictThresholdPctexists,autoEvictThresholdreverts,isProcessedreverts) should all pass.sourceId=11155111, which now must match the newtrustedSourceIdimmutable baked into the receiver bytecode).Risks
bytecodes/epsilon/GBridgeReceiver.binwith its ownTRUSTED_BRIDGE/TRUSTED_SOURCE_IDvalues viascripts/build_epsilon_bytecodes.shin the contracts repo. The hardcoded testnet address constant inepsilon.rswould also need updating..binfiles were built withsolc 0.8.30(pinned in the contracts repo'sfoundry.toml). Any node running a different Solidity version locally will produce a different on-chain codehash post-hardfork than whatcargo-built nodes apply —cargo-built node bytecode is the source of truth.sourceId == trustedSourceId. If the relayer is reconfigured to a different chain id (e.g., mainnet1) without rebuilding the receiver.binfirst, every bridge transfer will revert withInvalidSourceChain.🤖 Generated with Claude Code