From 9d04777f887c5f737256a5c2f223497c6c9fc5fb Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Tue, 11 Feb 2025 07:36:52 +1000 Subject: [PATCH] op-sepolia: Add task to switch back to singlethreaded cannon. (#544) * op-sepolia: Add task to switch back to singlethreaded cannon. Updates the set-game-implementation task to handle recent breaking changes in superchain-registry and the monorepo. * Add game verification instructions. * Switch to new verification framework. * Review feedback * Remove comment. --- tasks/sep/030-revert-mt-cannon/.env | 7 + .../NestedSignFromJson.s.sol | 57 ++++++++ tasks/sep/030-revert-mt-cannon/README.md | 22 +++ tasks/sep/030-revert-mt-cannon/VALIDATION.md | 130 ++++++++++++++++++ tasks/sep/030-revert-mt-cannon/input.json | 66 +++++++++ .../005-set-game-implementation/justfile | 2 +- .../templates/NestedSignFromJson.s.sol | 1 - 7 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 tasks/sep/030-revert-mt-cannon/.env create mode 100644 tasks/sep/030-revert-mt-cannon/NestedSignFromJson.s.sol create mode 100644 tasks/sep/030-revert-mt-cannon/README.md create mode 100644 tasks/sep/030-revert-mt-cannon/VALIDATION.md create mode 100644 tasks/sep/030-revert-mt-cannon/input.json diff --git a/tasks/sep/030-revert-mt-cannon/.env b/tasks/sep/030-revert-mt-cannon/.env new file mode 100644 index 000000000..a03e5bcb6 --- /dev/null +++ b/tasks/sep/030-revert-mt-cannon/.env @@ -0,0 +1,7 @@ +ETH_RPC_URL="https://ethereum-sepolia.publicnode.com" +COUNCIL_SAFE=0xf64bc17485f0B4Ea5F06A96514182FC4cB561977 +FOUNDATION_SAFE=0xDEe57160aAfCF04c34C887B5962D0a69676d3C8B +SAFE_NONCE="" +L1_CHAIN_NAME="sepolia" +L2_CHAIN_NAME="op" +OWNER_SAFE="0x1Eb2fFc903729a0F03966B917003800b145F56E2" diff --git a/tasks/sep/030-revert-mt-cannon/NestedSignFromJson.s.sol b/tasks/sep/030-revert-mt-cannon/NestedSignFromJson.s.sol new file mode 100644 index 000000000..d62a82b44 --- /dev/null +++ b/tasks/sep/030-revert-mt-cannon/NestedSignFromJson.s.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +import {console2 as console} from "forge-std/console2.sol"; +import {Vm} from "forge-std/Vm.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {Simulation} from "@base-contracts/script/universal/Simulation.sol"; +import {NestedSignFromJson as OriginalNestedSignFromJson} from "script/NestedSignFromJson.s.sol"; +import {DisputeGameUpgrade} from "script/verification/DisputeGameUpgrade.s.sol"; +import {CouncilFoundationNestedSign} from "script/verification/CouncilFoundationNestedSign.s.sol"; +import {SuperchainRegistry} from "script/verification/Verification.s.sol"; + +contract NestedSignFromJson is OriginalNestedSignFromJson, CouncilFoundationNestedSign, DisputeGameUpgrade { + constructor() + SuperchainRegistry("sepolia", "op", "v1.8.0-rc.4") + DisputeGameUpgrade( + 0x03f89406817db1ed7fd8b31e13300444652cdb0b9c509a674de43483b2f83568, // absolutePrestate + 0xF3CcF0C4b51D42cFe6073F0278c19A8D1900e856, // faultDisputeGame + 0xbbDBdfe37C02439764dE0e41C906e4396B5B3914 // permissionedDisputeGame + ) + {} + + function setUp() public view { + checkInput(); + } + + function checkInput() public view { + string memory inputJson; + string memory path = "/tasks/sep/030-revert-mt-cannon/input.json"; + try vm.readFile(string.concat(vm.projectRoot(), path)) returns (string memory data) { + inputJson = data; + } catch { + revert(string.concat("Failed to read ", path)); + } + + address inputPermissionedDisputeGame = + stdJson.readAddress(inputJson, "$.transactions[1].contractInputsValues._impl"); + address inputFaultDisputeGame = stdJson.readAddress(inputJson, "$.transactions[0].contractInputsValues._impl"); + require(expPermissionedDisputeGame == inputPermissionedDisputeGame, "input-pdg"); + require(expFaultDisputeGame == inputFaultDisputeGame, "input-fdg"); + } + + function _postCheck(Vm.AccountAccess[] memory accesses, Simulation.Payload memory) internal view override { + console.log("Running post-deploy assertions"); + checkStateDiff(accesses); + checkDisputeGameUpgrade(); + console.log("All assertions passed!"); + } + + function getAllowedStorageAccess() internal view override returns (address[] memory) { + return allowedStorageAccess; + } + + function getCodeExceptions() internal view override returns (address[] memory) { + return codeExceptions; + } +} diff --git a/tasks/sep/030-revert-mt-cannon/README.md b/tasks/sep/030-revert-mt-cannon/README.md new file mode 100644 index 000000000..d71c0edfc --- /dev/null +++ b/tasks/sep/030-revert-mt-cannon/README.md @@ -0,0 +1,22 @@ +# ProxyAdminOwner - Set Dispute Game Implementation + +Status: READY TO SIGN + +## Objective + +This task updates the fault dispute system for op-sepolia: + +* Set implementation for game type 0 to 0xF3CcF0C4b51D42cFe6073F0278c19A8D1900e856 in `DisputeGameFactory` 0x05F9613aDB30026FFd634f38e5C4dFd30a197Fa1: `setImplementation(0, 0xF3CcF0C4b51D42cFe6073F0278c19A8D1900e856)` +* Set implementation for game type 1 to 0xbbDBdfe37C02439764dE0e41C906e4396B5B3914 in `DisputeGameFactory` 0x05F9613aDB30026FFd634f38e5C4dFd30a197Fa1: `setImplementation(1, 0xbbDBdfe37C02439764dE0e41C906e4396B5B3914)` + +This switches sepolia back to singlethreaded cannon, undoing the upgrade to cannon-mt (025-mt-cannon task) + +### State Validations + +Please see the instructions for [validation](./VALIDATION.md). + +## Simulation + +Please see the "Simulating and Verifying the Transaction" instructions in [NESTED.md](../../../NESTED.md). +When simulating, ensure the logs say `Using script /your/path/to/superchain-ops/tasks/sep/030-revert-mt-cannon/NestedSignFromJson.s.sol`. +This ensures all safety checks are run. If the default `NestedSignFromJson.s.sol` script is shown (without the full path), something is wrong and the safety checks will not run. diff --git a/tasks/sep/030-revert-mt-cannon/VALIDATION.md b/tasks/sep/030-revert-mt-cannon/VALIDATION.md new file mode 100644 index 000000000..a7d874d8d --- /dev/null +++ b/tasks/sep/030-revert-mt-cannon/VALIDATION.md @@ -0,0 +1,130 @@ +# Validation + +This document can be used to validate the state diff resulting from the execution of the upgrade transaction. + +For each contract listed in the state diff, please verify that no contracts or state changes shown in the Tenderly diff +are missing from this document. Additionally, please verify that for each contract: + +- The following state changes (and none others) are made to that contract. This validates that no unexpected state + changes occur. +- All addresses (in section headers and storage values) match the provided name, using the Etherscan and Superchain + Registry links provided. This validates the bytecode deployed at the addresses contains the correct logic. +- All key values match the semantic meaning provided, which can be validated using the storage layout links provided. + +## Nested Safe State Overrides and Changes + +This task is executed by the nested 2/2 `ProxyAdminOwner` Safe. Refer to the +[generic nested Safe execution validation document](../../../NESTED-VALIDATION.md) +for the expected state overrides and changes. + +The `approvedHashes` mapping **key** of the `ProxyAdminOwner` that should change during the simulation is +- Council simulation: `0xe8f8aa2e65c85624906005cf8077cbc632900bd87fdfb6023df637b4fddfffe3` +- Foundation simulation: `0x0d550ba923712ad13c224c6566f757fbc09207dd05fec85aebd7a66e56e27bd5` + +calculated as explained in the nested validation doc. + +Additionally, the nonces [will increment by one](../../../NESTED-VALIDATION.md#nonce-increments). + +## State Changes + +Note: The changes listed below do not include safe nonce updates or liveness guard related changes. Refer to the +[generic nested Safe execution validation document](../../../NESTED-VALIDATION.md) + +### `0x05F9613aDB30026FFd634f38e5C4dFd30a197Fa1` (`DisputeGameFactoryProxy`) + +- **Key**: `0xffdfc1249c027f9191656349feb0761381bb32c9f557e01f419fd08754bf5a1b`
+ **Before**: `0x000000000000000000000000833a817ef459f4ecdb83fc5a4bf04d09a4e83f3f`
+ **After**: `0x000000000000000000000000F3CcF0C4b51D42cFe6073F0278c19A8D1900e856`
+ **Meaning**: Updates the implementation for game type 0. Verify that the new implementation is set using + `cast call 0x05F9613aDB30026FFd634f38e5C4dFd30a197Fa1 "gameImpls(uint32)(address)" 0`. + +- **Key**: `0x4d5a9bd2e41301728d41c8e705190becb4e74abe869f75bdb405b63716a35f9e`
+ **Before**: `0x000000000000000000000000bbd576128f71186a0f9ae2f2aab4afb4af2dae17`
+ **After**: `0x000000000000000000000000bbDBdfe37C02439764dE0e41C906e4396B5B3914`
+ **Meaning**: Updates the implementation for game type 1. Verify that the new implementation is set using + `cast call 0x05F9613aDB30026FFd634f38e5C4dFd30a197Fa1 "gameImpls(uint32)(address)" 1`. + +## Verifying Dispute Games + +The old and new dispute game contracts can be compared with https://gist.github.com/ajsutton/28be852a36d9d19af16f7c870b267873 + +The previous dispute game implementation can be loaded from the `DisputeGameFactory.gameImpl` function. ie: +``` +cast call 0x05F9613aDB30026FFd634f38e5C4dFd30a197Fa1 "gameImpls(uint32)(address)" 0 +cast call 0x05F9613aDB30026FFd634f38e5C4dFd30a197Fa1 "gameImpls(uint32)(address)" 1 +``` + +The second argument is the new deployment which should match the state diff above. + +FaultDisputeGame: +``` +./temp/compareGames.sh 0x833a817eF459f4eCdB83Fc5A4Bf04d09A4e83f3F 0xF3CcF0C4b51D42cFe6073F0278c19A8D1900e856 + +Matches version()(string) = "1.3.1" + +Mismatch absolutePrestate()(bytes32) +Was: 0x03b7eaa4e3cbce90381921a4b48008f4769871d64f93d113fcadca08ecee503b +Now: 0x03f89406817db1ed7fd8b31e13300444652cdb0b9c509a674de43483b2f83568 + +Matches maxGameDepth()(uint256) = 73 + +Matches splitDepth()(uint256) = 30 + +Matches maxClockDuration()(uint256) = 302400 [3.024e5] + +Matches gameType()(uint32) = 0 + +Matches l2ChainId()(uint256) = 11155420 [1.115e7] + +Matches clockExtension()(uint64) = 10800 [1.08e4] + +Matches anchorStateRegistry()(address) = 0x218CD9489199F321E1177b56385d333c5B598629 +Matches weth()(address) +Comparing vm + +Mismatch version()(string) +Was: "1.0.0-beta.7" +Now: "1.2.1" +``` + +PermissionedDisputeGame: +``` +./temp/compareGames.sh 0xbBD576128f71186A0f9ae2F2AAb4afb4aF2dae17 0xbbDBdfe37C02439764dE0e41C906e4396B5B3914 + +Matches version()(string) = "1.3.1" + +Mismatch absolutePrestate()(bytes32) +Was: 0x03b7eaa4e3cbce90381921a4b48008f4769871d64f93d113fcadca08ecee503b +Now: 0x03f89406817db1ed7fd8b31e13300444652cdb0b9c509a674de43483b2f83568 + +Matches maxGameDepth()(uint256) = 73 + +Matches splitDepth()(uint256) = 30 + +Matches maxClockDuration()(uint256) = 302400 [3.024e5] + +Matches gameType()(uint32) = 1 + +Matches l2ChainId()(uint256) = 11155420 [1.115e7] + +Matches clockExtension()(uint64) = 10800 [1.08e4] + +Matches anchorStateRegistry()(address) = 0x218CD9489199F321E1177b56385d333c5B598629 + +Matches proposer()(address) = 0x49277EE36A024120Ee218127354c4a3591dc90A9 + +Matches challenger()(address) = 0xfd1D2e729aE8eEe2E146c033bf4400fE75284301 +Matches weth()(address) +Comparing vm + +Mismatch version()(string) +Was: "1.0.0-beta.7" +Now: "1.2.1" +``` + +In both, there are two changes: + +* absolutePrestate() changes from `0x03b7eaa4e3cbce90381921a4b48008f4769871d64f93d113fcadca08ecee503b` to `0x03f89406817db1ed7fd8b31e13300444652cdb0b9c509a674de43483b2f83568`. + These can be verified by comparing to the values in [releases.json](https://github.com/ethereum-optimism/optimism/blob/develop/op-program/prestates/releases.json). + The old absolute prestate is the cannon64 variant of the 1.4.0 release, the new one is the governance approved, single-threaded cannon version from the same 1.4.0 release. +* vm - the MIPS.sol version. This reverts from the MIPS64.sol beta version back to the governance approved version 1.2.1 from the contracts/1.8.0 (Holocene) release. diff --git a/tasks/sep/030-revert-mt-cannon/input.json b/tasks/sep/030-revert-mt-cannon/input.json new file mode 100644 index 000000000..181a7e436 --- /dev/null +++ b/tasks/sep/030-revert-mt-cannon/input.json @@ -0,0 +1,66 @@ +{ + "metadata": { + "name": "ProxyAdminOwner - Set Dispute Game Implementation", + "description": "Sets the implementation for game type 0 to 0xF3CcF0C4b51D42cFe6073F0278c19A8D1900e856 in the `DisputeGameFactory`. Sets the implementation for game type 1 to 0xbbDBdfe37C02439764dE0e41C906e4396B5B3914 in the `DisputeGameFactory`. " + }, + "transactions": [ + { + "metadata": { + "name": "Set implementation for game type", + "description": "Sets the implementation for game type 0 to 0xF3CcF0C4b51D42cFe6073F0278c19A8D1900e856 in the `DisputeGameFactory`." + }, + "to": "0x05F9613aDB30026FFd634f38e5C4dFd30a197Fa1", + "value": "0x0", + "data": "0x14f6b1a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f3ccf0c4b51d42cfe6073f0278c19a8d1900e856", + "contractMethod": { + "type": "function", + "name": "setImplementation", + "inputs": [ + { + "name": "_gameType", + "type": "uint32" + }, + { + "name": "_impl", + "type": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + "contractInputsValues": { + "_gameType": "0", + "_impl": "0xF3CcF0C4b51D42cFe6073F0278c19A8D1900e856" + } + }, + { + "metadata": { + "name": "Set implementation for game type", + "description": "Sets the implementation for game type 1 to 0xbbDBdfe37C02439764dE0e41C906e4396B5B3914 in the `DisputeGameFactory`." + }, + "to": "0x05F9613aDB30026FFd634f38e5C4dFd30a197Fa1", + "value": "0x0", + "data": "0x14f6b1a30000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bbdbdfe37c02439764de0e41c906e4396b5b3914", + "contractMethod": { + "type": "function", + "name": "setImplementation", + "inputs": [ + { + "name": "_gameType", + "type": "uint32" + }, + { + "name": "_impl", + "type": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + "contractInputsValues": { + "_gameType": "1", + "_impl": "0xbbDBdfe37C02439764dE0e41C906e4396B5B3914" + } + } + ] +} diff --git a/tasks/sep/fp-recovery/005-set-game-implementation/justfile b/tasks/sep/fp-recovery/005-set-game-implementation/justfile index cfe20d433..fe68c3a03 100644 --- a/tasks/sep/fp-recovery/005-set-game-implementation/justfile +++ b/tasks/sep/fp-recovery/005-set-game-implementation/justfile @@ -36,7 +36,7 @@ prep l1='' l2='': CONFIG_URL="https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/refs/heads/main/superchain/configs/{{l1}}/{{l2}}.toml" CONFIG_TOML=$(curl -s --show-error --fail "${CONFIG_URL}") SYSTEM_CONFIG=$(echo "${CONFIG_TOML}" | yq -p toml .addresses.SystemConfigProxy) - OWNER_SAFE=$(echo "${CONFIG_TOML}" | yq -p toml .addresses.ProxyAdminOwner) + OWNER_SAFE=$(echo "${CONFIG_TOML}" | yq -p toml .roles.ProxyAdminOwner) PROXY_ADMIN=$(echo "${CONFIG_TOML}" | yq -p toml .addresses.ProxyAdmin) cat >> out/.env << EOF diff --git a/tasks/sep/fp-recovery/005-set-game-implementation/templates/NestedSignFromJson.s.sol b/tasks/sep/fp-recovery/005-set-game-implementation/templates/NestedSignFromJson.s.sol index 1dbd8f81c..1353b0629 100644 --- a/tasks/sep/fp-recovery/005-set-game-implementation/templates/NestedSignFromJson.s.sol +++ b/tasks/sep/fp-recovery/005-set-game-implementation/templates/NestedSignFromJson.s.sol @@ -9,7 +9,6 @@ import {stdToml} from "forge-std/StdToml.sol"; import {Vm, VmSafe} from "forge-std/Vm.sol"; import {GnosisSafe} from "safe-contracts/GnosisSafe.sol"; import {LibString} from "solady/utils/LibString.sol"; -import {Types} from "@eth-optimism-bedrock/scripts/Types.sol"; import "@eth-optimism-bedrock/src/dispute/lib/Types.sol"; import {DisputeGameFactory} from "@eth-optimism-bedrock/src/dispute/DisputeGameFactory.sol"; import {FaultDisputeGame} from "@eth-optimism-bedrock/src/dispute/FaultDisputeGame.sol";