Skip to content

fix: enable automatic upgrades on the server side (#1981)#1983

Open
kelemeno wants to merge 22 commits intodraft-v31from
kl/automatic-upgrades
Open

fix: enable automatic upgrades on the server side (#1981)#1983
kelemeno wants to merge 22 commits intodraft-v31from
kl/automatic-upgrades

Conversation

@kelemeno
Copy link
Contributor

@kelemeno kelemeno commented Jan 21, 2026

What ❔

enable automatic upgrades on the server side

Why ❔

Checklist

  • PR title corresponds to the body of PR (we generate changelog
    entries from PRs).
  • Tests for the changes have been added / updated.
  • Documentation comments have been added / updated.

What ❔

Why ❔

Checklist

  • PR title corresponds to the body of PR (we generate changelog entries from PRs).
  • Tests for the changes have been added / updated.
  • Documentation comments have been added / updated.

# What ❔

<!-- What are the changes this PR brings about? -->
<!-- Example: This PR adds a PR template to the repo. -->
<!-- (For bigger PRs adding more context is appreciated) -->

## Why ❔

<!-- Why are these changes done? What goal do they contribute to? What
are the principles behind them? -->
<!-- Example: PR templates ensure PR reviewers, observers, and future
iterators are in context about the evolution of repos. -->

## Checklist

<!-- Check your PR fulfills the following items. -->
<!-- For draft PRs check the boxes as you complete them. -->

- [ ] PR title corresponds to the body of PR (we generate changelog
entries from PRs).
- [ ] Tests for the changes have been added / updated.
- [ ] Documentation comments have been added / updated.

# What ❔

<!-- What are the changes this PR brings about? -->
<!-- Example: This PR adds a PR template to the repo. -->
<!-- (For bigger PRs adding more context is appreciated) -->

## Why ❔

<!-- Why are these changes done? What goal do they contribute to? What are the principles behind them? -->
<!-- Example: PR templates ensure PR reviewers, observers, and future iterators are in context about the evolution of repos. -->

## Checklist

<!-- Check your PR fulfills the following items. -->
<!-- For draft PRs check the boxes as you complete them. -->

- [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs).
- [ ] Tests for the changes have been added / updated.
- [ ] Documentation comments have been added / updated.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 96116eaa79

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines 121 to 123
function _onlyAdminOrChainTypeManagerOrUpgradeExecutor() internal view {
if (msg.sender != s.admin && msg.sender != s.chainTypeManager && !s.validators[msg.sender] && false) { // kl todo
revert Unauthorized(msg.sender);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restore access control in upgrade executor check

The new onlyAdminOrChainTypeManagerOrUpgradeExecutor guard is effectively a no‑op because the condition includes && false, which makes the if unreachable. That means any address can pass the modifier, and since upgradeChainFromVersion now uses it, any caller can execute a pending upgrade as soon as the cut hash matches, bypassing the intended admin/chain-type-manager/upgrade-executor restriction and any timing controls. This allows unauthorized or premature upgrades whenever upgradeCutHash is set.

Useful? React with 👍 / 👎.

@kelemeno kelemeno force-pushed the kl/automatic-upgrades branch from e527e38 to 0262c7a Compare February 6, 2026 13:40
@kelemeno kelemeno changed the title fix: foundry fixes (#1981) fix: enable automatic upgrades on the server side (#1981) Feb 9, 2026
Copy link
Collaborator

@StanislavBreadless StanislavBreadless left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, we should add a test for upgrading via the validator timelock, etc

@@ -140,4 +148,10 @@ interface IValidatorTimelock is IExecutor {
uint256 _processBatchTo,
bytes calldata _batchData
) external;
/// @dev Make a call to the zkChain diamond contract to upgrade from a specific protocol version.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: should be a newline before new function declaration

/// @param _cutData The diamond cut parameters that is executed in the upgrade
function upgradeChainFromVersion(uint256 _protocolVersion, Diamond.DiamondCutData calldata _cutData) external;
function upgradeChainFromVersion(
address _chainAddress,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that you have not yet worked on this change on the server side, but this is a breaking change for zkstack cli etc

rotateCommitterRole: false,
rotateReverterRole: true,
rotateProverRole: true,
rotateExecutorRole: true
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we never in this script set that the upgrader role is true, I am not sure it is usable for the platform team

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tomasz tried it and he said it worked somehow

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most likely because he uses ValidatorTimelock.addValidator which sets all the roles

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to rotate it here somehow

@@ -140,4 +148,10 @@ interface IValidatorTimelock is IExecutor {
uint256 _processBatchTo,
bytes calldata _batchData
) external;
/// @dev Make a call to the zkChain diamond contract to upgrade from a specific protocol version.
function upgradeChainFromVersion(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another small note:

  • the interface is defined inside IAdmin.sol, but ValidatorTimelock does not inherit it.
  • this introduces a risk that we may accidentally change the function signature and not notice it. the tests help, but whenever we have an opportunity to use compile time checks, we should do so

I think the best solutions are either:

  • move this function to executor
  • create a new small upgrade-only interface that will be inherited by both IAdmin and IValidatorTimelock


/// @notice Checks that the message sender is an active admin
modifier onlyAdmin() {
_onlyAdmin();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did we introduce so many changes in this file?

@github-actions
Copy link
Contributor

Coverage after merging kl/automatic-upgrades into draft-v31 will be

90.86%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
contracts/bridge
   BridgeHelper.sol100%100%100%100%
   BridgedStandardERC20.sol96.25%100%92.31%97.01%231–232
   L1ERC20Bridge.sol97.78%100%100%97.30%261
   L1Nullifier.sol96.12%100%100%95.40%432–433, 436, 462, 715, 718, 720, 736
   UpgradeableBeaconDeployer.sol100%100%100%100%
contracts/bridge/asset-router
   AssetRouterBase.sol98.53%100%100%98.21%128
   L1AssetRouter.sol91.62%100%86.67%92.70%104, 319, 330, 412–413, 432, 590, 601, 615, 620
contracts/bridge/asset-tracker
   AssetTrackerBase.sol93.55%100%88.89%95.45%84
   GWAssetTracker.sol89.46%100%92.86%88.93%114, 164–166, 168–170, 175–176, 311–313, 329, 468, 516, 518–524, 531–532, 748–749, 767, 91–93
   L1AssetTracker.sol98.61%100%100%98.37%397, 61
   LegacySharedBridgeAddresses.sol83.33%100%100%81.82%39, 41
contracts/bridge/interfaces
   AssetHandlerModifiers.sol75%100%100%66.67%13
contracts/bridge/ntv
   L1NativeTokenVault.sol98.17%100%100%97.70%184, 186
   NativeTokenVaultBase.sol98.95%100%100%98.75%147, 153
contracts/common
   MessageVerification.sol88.24%100%87.50%88.46%34, 41–42
   ReentrancyGuard.sol100%100%100%100%
contracts/common/l2-helpers
   L2ContractHelper.sol98.11%100%100%97.78%102
   SystemContractsCaller.sol52.50%100%60%51.43%42–43, 45, 47, 49, 51, 64, 67, 70, 73, 76, 81, 87, 89, 91, 94, 96
contracts/common/libraries
   DataEncoding.sol95.61%100%95.65%95.60%183, 273, 291, 297
   DynamicIncrementalMerkle.sol100%100%100%100%
   DynamicIncrementalMerkleMemory.sol98.96%100%100%98.84%196
   FullMerkle.sol98.28%100%100%98.11%109
   FullMerkleMemory.sol93.81%100%100%93.33%114, 131, 149, 163, 194, 90
   Merkle.sol100%100%100%100%
   MessageHashing.sol98.67%100%100%98.46%154
   SemVer.sol100%100%100%100%
   UncheckedMath.sol100%100%100%100%
   UnsafeBytes.sol100%100%100%100%
   ZKSyncOSBytecodeInfo.sol100%100%100%100%
contracts/common/libraries/TransientPrimitives
   TransientPrimitives.sol100%100%100%100%
contracts/core/bridgehub
   BridgehubBase.sol96.86%100%100%96.23%136, 285, 301, 561, 565, 568
   L1Bridgehub.sol92.78%100%100%91.86%202, 277, 281–282, 285, 295, 85
   L2Bridgehub.sol66.67%100%60%68.57%103–104, 112, 114–115, 124, 129–130, 132–133, 76
contracts/core/chain-asset-handler
   ChainAssetHandlerBase.sol85.86%100%92.31%84.88%104–105, 123–125, 174, 177, 186–187, 323, 327, 349, 97
   L1ChainAssetHandler.sol88.54%100%87.50%88.75%230, 232–234, 273, 71–72, 76–77
   L2ChainAssetHandler.sol84.21%100%80%85.71%120, 124, 69, 93
contracts/core/chain-registration
   ChainRegistrationSender.sol90.91%100%100%88.89%41, 88, 92, 98
contracts/core/ctm-deployment
   CTMDeploymentTracker.sol100%100%100%100%
contracts/core/message-root
   L1MessageRoot.sol95%100%90.91%95.92%154–155
   L2MessageRoot.sol62.22%100%45.45%67.65%105, 112, 116–117, 38–39, 48–49, 53, 60, 76
   MessageRootBase.sol92.78%100%100%91.36%119, 123, 200, 271, 290, 334, 99
contracts/governance
   AccessControlRestriction.sol100%100%100%100%
   ChainAdmin.sol97.87%100%100%97.30%39
   ChainAdminOwnable.sol100%100%100%100%
   Governance.sol100%100%100%100%
   L2ProxyAdminDeployer.sol100%100%100%100%
   PermanentRestriction.sol100%100%100%100%
   ServerNotifier.sol100%100%100%100%
   TransitionaryOwner.sol100%100%100%100%
contracts/governance/restriction
   Restriction.sol100%100%100%100%
   RestrictionValidator.sol100%100%100%100%
contracts/interop
   AttributesDecoder.sol100%100%100%100%
   InteropCenter.sol95.56%100%88.46%96.48%103, 147–148, 546, 630, 91–92
   InteropDataEncoding.sol100%100%100%100%
   InteropHandler.sol96.72%100%100%96.36%35, 386, 408, 413
   L2InteropRootStorage.sol0%100%0%0%20–22, 41, 46, 52–53, 58, 60–62, 71, 73–74, 76–77, 81–82, 86, 88
   L2MessageVerification.sol100%100%100%100%
contracts/l2-system/zksync-os
   L1MessageGasLib.sol100%100%100%100%
   L1Messenger.sol94.12%100%100%92.86%29
   SystemContext.sol100%100%100%100%
   ZKOSContractDeployer.sol0%100%0%0%12–14, 20, 26, 30–31
contracts/l2-upgrades
   L2ComplexUpgrader.sol0%100%0%0%23–25, 39, 44, 46, 56, 62–63, 70, 79–81, 84, 86–87
   L2GenesisForceDeploymentsHelper.sol93.71%100%100%93.15%125, 171, 173, 177, 179–180, 210, 216, 429, 92
   L2GenesisUpgrade.sol0%100%0%0%30, 37, 39–40, 43, 47–50, 53, 55, 63
   L2V30TestnetSystemProxiesUpgrade.sol0%100%0%0%22, 27–28, 30, 41, 47, 52, 56, 61, 66, 71, 76, 81, 86, 93, 99
   L2V31Upgrade.sol0%100%0%0%14–15
   SystemContractProxy.sol88%100%66.67%90.91%16–17
   SystemContractProxyAdmin.sol60%100%66.67%57.14%12, 18–19
   V31AcrossRecovery.sol0%100%0%0%43–45, 64–65, 67–68, 72, 77–78, 93
contracts/state-transition
   AccessControlEnumerablePerChainAddressUpgradeable.sol98.25%100%100%97.83%179
   ChainTypeManagerBase.sol96.20%100%100%95.31%194, 197, 371, 429, 434, 577, 640, 678, 754
   EraChainTypeManager.sol94.12%100%100%92.86%34
   ZKsyncOSChainTypeManager.sol80%100%66.67%83.33%22–23
contracts/state-transition/chain-deps
   DiamondInit.sol94.12%100%100%93.88%58, 62, 66
   DiamondProxy.sol100%100%100%100%
   StoredBatchHashing.sol100%100%100%100%
contracts/state-transition/chain-deps/facets
   Admin.sol90.50%100%93.75%89.95%160, 164, 168, 238, 263–264, 348, 387, 431–433, 57–59, 61–62, 73–75
   Committer.sol90.80%100%100%90%146, 171, 178, 224, 227–228, 232–233, 342, 378–379, 388, 399, 460, 487, 494–496, 523, 598,

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