Skip to content

feat: add zombie permanently-off upgrade gate#3898

Merged
0x00101010 merged 5 commits into
mainfrom
francis/subsecond-pseudo-fork
Jul 9, 2026
Merged

feat: add zombie permanently-off upgrade gate#3898
0x00101010 merged 5 commits into
mainfrom
francis/subsecond-pseudo-fork

Conversation

@0x00101010

@0x00101010 0x00101010 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Adds a Zombie Base upgrade that keeps a full gate identity (enum variant, name(), and is_zombie_active* query helpers) but can never be activated by any path (config, genesis, runtime override, contract signal, or chainspec schedule), so it always resolves to ForkCondition::Never. Use it like any other is_xxx_activated_at_timestamp gate to guard not-yet-ready features until Zombie is replaced by a real named fork. Zombie tracks the latest precompile set so it evolves with new hard forks.

@cb-heimdall

cb-heimdall commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

✅ Heimdall Review Status

Requirement Status More Info
Reviews 1/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1

Comment thread crates/common/genesis/src/rollup.rs
Enforce the 'Zombie is never stored as active' invariant at the source
by dropping Zombie writes in UpgradeActivationOverrides::set_activation,
which also covers the RuntimeUpgradeRegistry paths. Previously the raw
override map would store a dead Zombie->Timestamp entry that consumers
had to keep short-circuiting.
Comment thread crates/common/genesis/src/chain/upgrade.rs
Comment thread crates/common/genesis/src/chain/upgrade.rs
…_fork_name

contract_id emits "zombie" but the reverse lookup deliberately drops it
so the L1 upgrade signal can never address the permanently-off gate.
@0x00101010
0x00101010 marked this pull request as ready for review July 9, 2026 21:44
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Summary

The implementation is well-structured with defense-in-depth at multiple layers. The Zombie gate is correctly excluded from EXECUTION_VARIANTS, CONTRACT_VARIANTS, from_contract_fork_name, and all write paths (set_activation, UpgradeActivationSink impls, UpgradeConfig timestamp setters). The deny_unknown_fields addition to UpgradeInfo is a good hardening measure to prevent Zombie (or any unknown key) from being smuggled through genesis JSON.

I reviewed all UpgradeActivationSink implementations:

  • RollupConfig — has explicit Zombie guard, returns Ok(false)
  • RuntimeRegistrySink — has explicit Zombie guard, returns Ok(false)
  • BaseChainSpec — no explicit guard, but is_execution() returns false and execution_hardfork() returns None for Zombie, so set_hardfork_activation_condition_for correctly returns falseOk(false)

The >= comparisons in BasePrecompiles::install_with_observer (e.g., >= BaseUpgrade::Beryl, >= BaseUpgrade::Cobalt) will match Zombie since it's the last enum variant, but this is intentional per the PR design — "Zombie tracks the latest precompile set so it evolves with new hard forks." The zkvm test at crates/proof/succinct/utils/client/src/precompiles/mod.rs:464 explicitly validates this with (BaseUpgrade::Zombie, true).

Maintenance concern

Zombie's position as the last enum variant is load-bearing: it ensures >= Cobalt comparisons in the precompile provider include Zombie, and the wildcard _ => arms in upgrade_activation / into_eth_spec / from_contract_fork_name catch it correctly. When a new real upgrade is added after Cobalt (e.g., Diamond), it must be inserted before Zombie in the enum declaration, otherwise the EXECUTION_VARIANTS ordering, execution_idx mapping, and >= comparisons will break. The existing documentation hints at this but doesn't make the constraint explicit. Consider adding a compile-time assertion or a doc comment on the Zombie variant stating it must always be the last variant in the enum.

No blocking issues found.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

✅ base-std fork tests: all 616 passed

base/base is fully in sync with the base-std spec.

Dependency Ref Commit
base-std main 4658f1b7
base-anvil 0092692587d8d064dd2c6923ce26a682c58f3694 00926925

@0x00101010
0x00101010 added this pull request to the merge queue Jul 9, 2026
Merged via the queue into main with commit 0608d4b Jul 9, 2026
24 of 25 checks passed
@0x00101010
0x00101010 deleted the francis/subsecond-pseudo-fork branch July 9, 2026 22:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants