Commit 3f4d94a4 authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

ctb: Implement addGameType method on OPCM (#13653)

parent 3d3deab1
......@@ -9,8 +9,6 @@ import { IResourceMetering } from "interfaces/L1/IResourceMetering.sol";
import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol";
import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";
import { Bytes } from "src/libraries/Bytes.sol";
import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol";
import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol";
import { IMIPS } from "interfaces/cannon/IMIPS.sol";
......@@ -493,14 +491,22 @@ contract DeployImplementations is Script {
bytes32 salt = _dii.salt();
OPContractsManager.Blueprints memory blueprints;
address checkAddress;
vm.startBroadcast(msg.sender);
blueprints.addressManager = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("AddressManager")), salt);
blueprints.proxy = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("Proxy")), salt);
blueprints.proxyAdmin = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("ProxyAdmin")), salt);
blueprints.l1ChugSplashProxy = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("L1ChugSplashProxy")), salt);
blueprints.resolvedDelegateProxy = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("ResolvedDelegateProxy")), salt);
blueprints.anchorStateRegistry = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("AnchorStateRegistry")), salt);
(blueprints.permissionedDisputeGame1, blueprints.permissionedDisputeGame2) = deployBigBytecode(vm.getCode("PermissionedDisputeGame"), salt);
(blueprints.addressManager, checkAddress) = Blueprint.create(vm.getCode("AddressManager"), salt);
require(checkAddress == address(0), "OPCM-10");
(blueprints.proxy, checkAddress) = Blueprint.create(vm.getCode("Proxy"), salt);
require(checkAddress == address(0), "OPCM-20");
(blueprints.proxyAdmin, checkAddress) = Blueprint.create(vm.getCode("ProxyAdmin"), salt);
require(checkAddress == address(0), "OPCM-30");
(blueprints.l1ChugSplashProxy, checkAddress) = Blueprint.create(vm.getCode("L1ChugSplashProxy"), salt);
require(checkAddress == address(0), "OPCM-40");
(blueprints.resolvedDelegateProxy, checkAddress) = Blueprint.create(vm.getCode("ResolvedDelegateProxy"), salt);
require(checkAddress == address(0), "OPCM-50");
(blueprints.anchorStateRegistry, checkAddress) = Blueprint.create(vm.getCode("AnchorStateRegistry"), salt);
require(checkAddress == address(0), "OPCM-60");
(blueprints.permissionedDisputeGame1, blueprints.permissionedDisputeGame2) = Blueprint.create(vm.getCode("PermissionedDisputeGame"), salt);
(blueprints.permissionlessDisputeGame1, blueprints.permissionlessDisputeGame2) = Blueprint.create(vm.getCode("FaultDisputeGame"), salt);
vm.stopBroadcast();
// forgefmt: disable-end
......@@ -862,33 +868,6 @@ contract DeployImplementations is Script {
dio_ = DeployImplementationsOutput(DeployUtils.toIOAddress(msg.sender, "optimism.DeployImplementationsOutput"));
}
function deployBytecode(bytes memory _bytecode, bytes32 _salt) public returns (address newContract_) {
assembly ("memory-safe") {
newContract_ := create2(0, add(_bytecode, 0x20), mload(_bytecode), _salt)
}
require(newContract_ != address(0), "DeployImplementations: create2 failed");
}
function deployBigBytecode(
bytes memory _bytecode,
bytes32 _salt
)
public
returns (address newContract1_, address newContract2_)
{
// Preamble needs 3 bytes.
uint256 maxInitCodeSize = 24576 - 3;
require(_bytecode.length > maxInitCodeSize, "DeployImplementations: Use deployBytecode instead");
bytes memory part1Slice = Bytes.slice(_bytecode, 0, maxInitCodeSize);
bytes memory part1 = Blueprint.blueprintDeployerBytecode(part1Slice);
bytes memory part2Slice = Bytes.slice(_bytecode, maxInitCodeSize, _bytecode.length - maxInitCodeSize);
bytes memory part2 = Blueprint.blueprintDeployerBytecode(part2Slice);
newContract1_ = deployBytecode(part1, _salt);
newContract2_ = deployBytecode(part2, _salt);
}
// Zero address is returned if the address is not found in '_standardVersionsToml'.
function getReleaseAddress(
string memory _version,
......
......@@ -198,7 +198,9 @@ contract DeployOPCM is Script {
resolvedDelegateProxy: _doi.resolvedDelegateProxyBlueprint(),
anchorStateRegistry: _doi.anchorStateRegistryBlueprint(),
permissionedDisputeGame1: _doi.permissionedDisputeGame1Blueprint(),
permissionedDisputeGame2: _doi.permissionedDisputeGame2Blueprint()
permissionedDisputeGame2: _doi.permissionedDisputeGame2Blueprint(),
permissionlessDisputeGame1: address(0),
permissionlessDisputeGame2: address(0)
});
OPContractsManager.Implementations memory implementations = OPContractsManager.Implementations({
l1ERC721BridgeImpl: address(_doi.l1ERC721BridgeImpl()),
......
......@@ -57,6 +57,16 @@
"internalType": "address",
"name": "permissionedDisputeGame2",
"type": "address"
},
{
"internalType": "address",
"name": "permissionlessDisputeGame1",
"type": "address"
},
{
"internalType": "address",
"name": "permissionlessDisputeGame2",
"type": "address"
}
],
"internalType": "struct OPContractsManager.Blueprints",
......@@ -132,6 +142,104 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "string",
"name": "saltMixer",
"type": "string"
},
{
"internalType": "contract ISystemConfig",
"name": "systemConfig",
"type": "address"
},
{
"internalType": "contract IProxyAdmin",
"name": "proxyAdmin",
"type": "address"
},
{
"internalType": "contract IDelayedWETH",
"name": "delayedWETH",
"type": "address"
},
{
"internalType": "GameType",
"name": "disputeGameType",
"type": "uint32"
},
{
"internalType": "Claim",
"name": "disputeAbsolutePrestate",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "disputeMaxGameDepth",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "disputeSplitDepth",
"type": "uint256"
},
{
"internalType": "Duration",
"name": "disputeClockExtension",
"type": "uint64"
},
{
"internalType": "Duration",
"name": "disputeMaxClockDuration",
"type": "uint64"
},
{
"internalType": "uint256",
"name": "initialBond",
"type": "uint256"
},
{
"internalType": "contract IBigStepper",
"name": "vm",
"type": "address"
},
{
"internalType": "bool",
"name": "permissioned",
"type": "bool"
}
],
"internalType": "struct OPContractsManager.AddGameInput[]",
"name": "_gameConfigs",
"type": "tuple[]"
}
],
"name": "addGameType",
"outputs": [
{
"components": [
{
"internalType": "contract IDelayedWETH",
"name": "delayedWETH",
"type": "address"
},
{
"internalType": "contract IFaultDisputeGame",
"name": "faultDisputeGame",
"type": "address"
}
],
"internalType": "struct OPContractsManager.AddGameOutput[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "blueprints",
......@@ -177,6 +285,16 @@
"internalType": "address",
"name": "permissionedDisputeGame2",
"type": "address"
},
{
"internalType": "address",
"name": "permissionlessDisputeGame1",
"type": "address"
},
{
"internalType": "address",
"name": "permissionlessDisputeGame2",
"type": "address"
}
],
"internalType": "struct OPContractsManager.Blueprints",
......@@ -596,6 +714,11 @@
"name": "InvalidChainId",
"type": "error"
},
{
"inputs": [],
"name": "InvalidGameConfigs",
"type": "error"
},
{
"inputs": [
{
......@@ -622,6 +745,11 @@
"name": "NotABlueprint",
"type": "error"
},
{
"inputs": [],
"name": "OnlyDelegatecall",
"type": "error"
},
{
"inputs": [],
"name": "ReservedBitsSet",
......
......@@ -57,6 +57,16 @@
"internalType": "address",
"name": "permissionedDisputeGame2",
"type": "address"
},
{
"internalType": "address",
"name": "permissionlessDisputeGame1",
"type": "address"
},
{
"internalType": "address",
"name": "permissionlessDisputeGame2",
"type": "address"
}
],
"internalType": "struct OPContractsManager.Blueprints",
......@@ -132,6 +142,104 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "string",
"name": "saltMixer",
"type": "string"
},
{
"internalType": "contract ISystemConfig",
"name": "systemConfig",
"type": "address"
},
{
"internalType": "contract IProxyAdmin",
"name": "proxyAdmin",
"type": "address"
},
{
"internalType": "contract IDelayedWETH",
"name": "delayedWETH",
"type": "address"
},
{
"internalType": "GameType",
"name": "disputeGameType",
"type": "uint32"
},
{
"internalType": "Claim",
"name": "disputeAbsolutePrestate",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "disputeMaxGameDepth",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "disputeSplitDepth",
"type": "uint256"
},
{
"internalType": "Duration",
"name": "disputeClockExtension",
"type": "uint64"
},
{
"internalType": "Duration",
"name": "disputeMaxClockDuration",
"type": "uint64"
},
{
"internalType": "uint256",
"name": "initialBond",
"type": "uint256"
},
{
"internalType": "contract IBigStepper",
"name": "vm",
"type": "address"
},
{
"internalType": "bool",
"name": "permissioned",
"type": "bool"
}
],
"internalType": "struct OPContractsManager.AddGameInput[]",
"name": "_gameConfigs",
"type": "tuple[]"
}
],
"name": "addGameType",
"outputs": [
{
"components": [
{
"internalType": "contract IDelayedWETH",
"name": "delayedWETH",
"type": "address"
},
{
"internalType": "contract IFaultDisputeGame",
"name": "faultDisputeGame",
"type": "address"
}
],
"internalType": "struct OPContractsManager.AddGameOutput[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "blueprints",
......@@ -177,6 +285,16 @@
"internalType": "address",
"name": "permissionedDisputeGame2",
"type": "address"
},
{
"internalType": "address",
"name": "permissionlessDisputeGame1",
"type": "address"
},
{
"internalType": "address",
"name": "permissionlessDisputeGame2",
"type": "address"
}
],
"internalType": "struct OPContractsManager.Blueprints",
......@@ -596,6 +714,11 @@
"name": "InvalidChainId",
"type": "error"
},
{
"inputs": [],
"name": "InvalidGameConfigs",
"type": "error"
},
{
"inputs": [
{
......@@ -622,6 +745,11 @@
"name": "NotABlueprint",
"type": "error"
},
{
"inputs": [],
"name": "OnlyDelegatecall",
"type": "error"
},
{
"inputs": [],
"name": "ReservedBitsSet",
......
......@@ -16,8 +16,8 @@
"sourceCodeHash": "0xa91b445bdc666a02ba18e3b91ba94b6d54bbe65da714002fc734814201319d57"
},
"src/L1/OPContractsManager.sol": {
"initCodeHash": "0x4b413cbe79bd10d41d8f3e9f0408e773dd49ced823d457b9f9aa92f446828105",
"sourceCodeHash": "0xe5179a20ae40d4e4773c52df98bac67e73e04044bec9e8750073b4e2f14fe81b"
"initCodeHash": "0xe0c14a8fee7ad4c4e28a3ff6ca4e726721a6c3fea0a74ab7eac7ef07fe4da0ae",
"sourceCodeHash": "0xe0f5413e0a0a335016d773f02ef6bd25551416635981e83b7a4da601b9b65bc4"
},
"src/L1/OptimismPortal2.sol": {
"initCodeHash": "0x7e533474310583593c2d57d30fcd1ec11e1568dbaaf37a2dd28c5cc574068bac",
......
......@@ -7,7 +7,7 @@
"type": "string"
},
{
"bytes": "256",
"bytes": "320",
"label": "blueprint",
"offset": 0,
"slot": "1",
......@@ -17,7 +17,7 @@
"bytes": "288",
"label": "implementation",
"offset": 0,
"slot": "9",
"slot": "11",
"type": "struct OPContractsManager.Implementations"
}
]
\ No newline at end of file
......@@ -7,7 +7,7 @@
"type": "string"
},
{
"bytes": "256",
"bytes": "320",
"label": "blueprint",
"offset": 0,
"slot": "1",
......@@ -17,7 +17,7 @@
"bytes": "288",
"label": "implementation",
"offset": 0,
"slot": "9",
"slot": "11",
"type": "struct OPContractsManager.Implementations"
}
]
\ No newline at end of file
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Bytes } from "src/libraries/Bytes.sol";
/// @notice Methods for working with ERC-5202 blueprint contracts.
/// https://eips.ethereum.org/EIPS/eip-5202
library Blueprint {
......@@ -157,6 +159,50 @@ library Blueprint {
if (newContract_ == address(0)) revert DeploymentFailed();
}
/// @notice Deploys a blueprint contract with the given `_rawBytecode` and `_salt`. If the blueprint is too large to
/// fit in a single deployment, it is split across two addresses. It is the responsibility of the caller to handle
/// large contracts by checking if the second return value is not address(0).
function create(
bytes memory _rawBytecode,
bytes32 _salt
)
internal
returns (address newContract1_, address newContract2_)
{
if (_rawBytecode.length <= maxInitCodeSize()) {
newContract1_ = deploySmallBytecode(blueprintDeployerBytecode(_rawBytecode), _salt);
return (newContract1_, address(0));
}
(newContract1_, newContract2_) = deployBigBytecode(_rawBytecode, _salt);
}
/// @notice Deploys a blueprint contract that can fit in a single address.
function deploySmallBytecode(bytes memory _bytecode, bytes32 _salt) internal returns (address newContract_) {
assembly ("memory-safe") {
newContract_ := create2(0, add(_bytecode, 0x20), mload(_bytecode), _salt)
}
require(newContract_ != address(0), "Blueprint: create2 failed");
}
/// @notice Deploys a two blueprint contracts, splitting the bytecode across both of them.
function deployBigBytecode(
bytes memory _bytecode,
bytes32 _salt
)
internal
returns (address newContract1_, address newContract2_)
{
uint32 maxSize = maxInitCodeSize();
bytes memory part1Slice = Bytes.slice(_bytecode, 0, maxSize);
bytes memory part1 = blueprintDeployerBytecode(part1Slice);
bytes memory part2Slice = Bytes.slice(_bytecode, maxSize, _bytecode.length - maxSize);
bytes memory part2 = blueprintDeployerBytecode(part2Slice);
newContract1_ = deploySmallBytecode(part1, _salt);
newContract2_ = deploySmallBytecode(part2, _salt);
}
/// @notice Convert a bytes array to a uint256.
function bytesToUint(bytes memory _b) internal pure returns (uint256) {
if (_b.length > 32) revert BytesArrayTooLong();
......@@ -166,4 +212,9 @@ library Blueprint {
}
return number;
}
/// @notice Returns the maximum init code size for each blueprint. The preamble needs 3 bytes.
function maxInitCodeSize() internal pure returns (uint32) {
return 24576 - 3;
}
}
......@@ -8,6 +8,8 @@ import { FaultDisputeGame_Init, _changeClaimStatus } from "test/dispute/FaultDis
import "src/dispute/lib/Types.sol";
import "src/dispute/lib/Errors.sol";
import { Hash } from "src/dispute/lib/Types.sol";
contract AnchorStateRegistry_Init is FaultDisputeGame_Init {
function setUp() public virtual override {
// Duplicating the initialization/setup logic of FaultDisputeGame_Test.
......
......@@ -781,6 +781,7 @@ contract Specification_Test is CommonTest {
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.blueprints.selector });
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.chainIdToBatchInboxAddress.selector });
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.implementations.selector });
_addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.addGameType.selector });
// OPContractsManagerInterop
_addSpec({ _name: "OPContractsManagerInterop", _sel: _getSel("version()") });
......@@ -792,6 +793,7 @@ contract Specification_Test is CommonTest {
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.blueprints.selector });
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.chainIdToBatchInboxAddress.selector });
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.implementations.selector });
_addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.addGameType.selector });
// DeputyGuardianModule
_addSpec({
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment