Skip to content

Commit

Permalink
OPSM: Deploy Permissioned Game (ethereum-optimism#12064)
Browse files Browse the repository at this point in the history
* chore: fix semver lock

* fix: no permissionless root, remove hash from 0xdead

* fix: use 0xdead root properly

* feat: add remaining fault proof support

* chore: Update semver-lock

* fix: Remove extra anchor root definition and restore aritfactsFs argument

* feat: Add wip big blueprint code

* Don't wrap input to deployBigBytecode with preamble

* fix: off by one in deployBigBytecode

* feat: more gas efficient blueprint deployment for permissioned game

* Get the big deployments working

* perf: more efficient preamble parsing

* chore: snapshots + fix revert

* test: skip FaultDisputeGameAddress since we don't deploy it yet

* chore: cleanup

---------

Co-authored-by: Matt Solomon <[email protected]>
Co-authored-by: Matthew Slipper <[email protected]>
  • Loading branch information
3 people authored Sep 24, 2024
1 parent ec3f634 commit 308ce74
Show file tree
Hide file tree
Showing 11 changed files with 309 additions and 70 deletions.
9 changes: 8 additions & 1 deletion op-chain-ops/deployer/integration_test/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import (
const TestParams = `
participants:
- el_type: geth
el_extra_params:
- "--gcmode=archive"
cl_type: lighthouse
network_params:
prefunded_accounts: '{ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266": { "balance": "1000000ETH" } }'
Expand All @@ -41,6 +43,7 @@ network_params:
}'
network_id: "77799777"
seconds_per_slot: 3
genesis_delay: 0
`

type deployerKey struct{}
Expand All @@ -56,7 +59,7 @@ func (d *deployerKey) String() string {
func TestEndToEndApply(t *testing.T) {
kurtosisutil.Test(t)

lgr := testlog.Logger(t, slog.LevelInfo)
lgr := testlog.Logger(t, slog.LevelDebug)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()
Expand Down Expand Up @@ -189,6 +192,10 @@ func TestEndToEndApply(t *testing.T) {
{"DelayedWETHPermissionlessGameProxyAddress", chainState.DelayedWETHPermissionlessGameProxyAddress},
}
for _, addr := range chainAddrs {
// TODO Delete this `if`` block once FaultDisputeGameAddress is deployed.
if addr.name == "FaultDisputeGameAddress" {
continue
}
t.Run(fmt.Sprintf("chain %s - %s", chainState.ID, addr.name), func(t *testing.T) {
code, err := l1Client.CodeAt(ctx, addr.addr, nil)
require.NoError(t, err)
Expand Down
52 changes: 42 additions & 10 deletions packages/contracts-bedrock/scripts/DeployImplementations.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol";

import { Constants } from "src/libraries/Constants.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";
import { Bytes } from "src/libraries/Bytes.sol";

import { ProxyAdmin } from "src/universal/ProxyAdmin.sol";
import { Proxy } from "src/universal/Proxy.sol";
Expand All @@ -23,6 +24,7 @@ import { IPreimageOracle } from "src/cannon/interfaces/IPreimageOracle.sol";
import { MIPS } from "src/cannon/MIPS.sol";
import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { AnchorStateRegistry } from "src/dispute/AnchorStateRegistry.sol";
import { PermissionedDisputeGame } from "src/dispute/PermissionedDisputeGame.sol";

import { SuperchainConfig } from "src/L1/SuperchainConfig.sol";
import { ProtocolVersions } from "src/L1/ProtocolVersions.sol";
Expand Down Expand Up @@ -514,10 +516,11 @@ contract DeployImplementations is Script {
blueprints.l1ChugSplashProxy = deployBytecode(Blueprint.blueprintDeployerBytecode(type(L1ChugSplashProxy).creationCode), salt);
blueprints.resolvedDelegateProxy = deployBytecode(Blueprint.blueprintDeployerBytecode(type(ResolvedDelegateProxy).creationCode), salt);
blueprints.anchorStateRegistry = deployBytecode(Blueprint.blueprintDeployerBytecode(type(AnchorStateRegistry).creationCode), salt);
(blueprints.permissionedDisputeGame1, blueprints.permissionedDisputeGame2) = deployBigBytecode(type(PermissionedDisputeGame).creationCode, salt);
vm.stopBroadcast();
// forgefmt: disable-end

OPStackManager.ImplementationSetter[] memory setters = new OPStackManager.ImplementationSetter[](7);
OPStackManager.ImplementationSetter[] memory setters = new OPStackManager.ImplementationSetter[](9);
setters[0] = OPStackManager.ImplementationSetter({
name: "L1ERC721Bridge",
info: OPStackManager.Implementation(address(_dio.l1ERC721BridgeImpl()), L1ERC721Bridge.initialize.selector)
Expand All @@ -543,13 +546,22 @@ contract DeployImplementations is Script {
name: "L1StandardBridge",
info: OPStackManager.Implementation(address(_dio.l1StandardBridgeImpl()), L1StandardBridge.initialize.selector)
});

setters[6] = OPStackManager.ImplementationSetter({
name: "DisputeGameFactory",
info: OPStackManager.Implementation(
address(_dio.disputeGameFactoryImpl()), DisputeGameFactory.initialize.selector
)
});
setters[7] = OPStackManager.ImplementationSetter({
name: "DelayedWETH",
info: OPStackManager.Implementation(address(_dio.delayedWETHImpl()), DelayedWETH.initialize.selector)
});
setters[8] = OPStackManager.ImplementationSetter({
name: "MIPS",
// MIPS is a singleton for all chains, so it doesn't need to be initialized, so the
// selector is just `bytes4(0)`.
info: OPStackManager.Implementation(address(_dio.mipsSingleton()), bytes4(0))
});

// This call contains a broadcast to deploy OPSM which is proxied.
OPStackManager opsmProxy = createOPSMContract(_dii, _dio, blueprints, release, setters);
Expand Down Expand Up @@ -617,14 +629,14 @@ contract DeployImplementations is Script {
// The fault proofs contracts are configured as follows:
// | Contract | Proxied | Deployment | MCP Ready |
// |-------------------------|---------|-----------------------------------|------------|
// | DisputeGameFactory | Yes | Bespoke | Yes | X
// | AnchorStateRegistry | Yes | Bespoke | No | X
// | FaultDisputeGame | No | Bespoke | No | Todo
// | PermissionedDisputeGame | No | Bespoke | No | Todo
// | DelayedWETH | Yes | Two bespoke (one per DisputeGame) | No | Todo: Proxies.
// | PreimageOracle | No | Shared | N/A | X
// | MIPS | No | Shared | N/A | X
// | OptimismPortal2 | Yes | Shared | No | X
// | DisputeGameFactory | Yes | Bespoke | Yes |
// | AnchorStateRegistry | Yes | Bespoke | No |
// | FaultDisputeGame | No | Bespoke | No | Not yet supported by OPCM
// | PermissionedDisputeGame | No | Bespoke | No |
// | DelayedWETH | Yes | Two bespoke (one per DisputeGame) | No |
// | PreimageOracle | No | Shared | N/A |
// | MIPS | No | Shared | N/A |
// | OptimismPortal2 | Yes | Shared | No |
//
// This script only deploys the shared contracts. The bespoke contracts are deployed by
// `DeployOPChain.s.sol`. When the shared contracts are proxied, the contracts deployed here are
Expand Down Expand Up @@ -731,6 +743,26 @@ contract DeployImplementations is Script {
}
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);
}
}

// Similar to how DeploySuperchain.s.sol contains a lot of comments to thoroughly document the script
Expand Down
38 changes: 30 additions & 8 deletions packages/contracts-bedrock/scripts/DeployOPChain.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { BaseDeployIO } from "scripts/utils/BaseDeployIO.sol";

import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol";
import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol";
import { IBigStepper } from "src/dispute/interfaces/IBigStepper.sol";
import { Constants } from "src/libraries/Constants.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";

Expand All @@ -23,7 +24,7 @@ import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { AnchorStateRegistry } from "src/dispute/AnchorStateRegistry.sol";
import { FaultDisputeGame } from "src/dispute/FaultDisputeGame.sol";
import { PermissionedDisputeGame } from "src/dispute/PermissionedDisputeGame.sol";
import { GameType, GameTypes, Hash, OutputRoot } from "src/dispute/lib/Types.sol";
import { Claim, GameType, GameTypes, Hash, OutputRoot } from "src/dispute/lib/Types.sol";

import { OPStackManager } from "src/L1/OPStackManager.sol";
import { OptimismPortal2 } from "src/L1/OptimismPortal2.sol";
Expand Down Expand Up @@ -201,7 +202,7 @@ contract DeployOPChainOutput is BaseDeployIO {
address(_disputeGameFactoryProxy),
address(_anchorStateRegistryProxy),
address(_anchorStateRegistryImpl),
address(_faultDisputeGame),
// address(_faultDisputeGame),
address(_permissionedDisputeGame),
address(_delayedWETHPermissionedGameProxy),
address(_delayedWETHPermissionlessGameProxy)
Expand Down Expand Up @@ -289,18 +290,32 @@ contract DeployOPChainOutput is BaseDeployIO {
// -------- Deployment Assertions --------

function assertValidDeploy(DeployOPChainInput _doi) internal {
assertValidAnchorStateRegistryProxy(_doi);
assertValidAnchorStateRegistryImpl(_doi);
assertValidAnchorStateRegistryProxy(_doi);
assertValidDelayedWETHs(_doi);
assertValidDisputeGameFactory(_doi);
assertValidL1CrossDomainMessenger(_doi);
assertValidL1ERC721Bridge(_doi);
assertValidL1StandardBridge(_doi);
assertValidOptimismMintableERC20Factory(_doi);
assertValidOptimismPortal(_doi);
assertValidPermissionedDisputeGame(_doi);
assertValidSystemConfig(_doi);
// TODO Other FP assertions like the dispute games, anchor state registry, etc.
// TODO add initialization assertions
}

function assertValidPermissionedDisputeGame(DeployOPChainInput _doi) internal view {
PermissionedDisputeGame game = permissionedDisputeGame();

require(GameType.unwrap(game.gameType()) == GameType.unwrap(GameTypes.PERMISSIONED_CANNON), "DPG-10");
require(Claim.unwrap(game.absolutePrestate()) == bytes32(hex"dead"), "DPG-20");

OPStackManager opsm = _doi.opsmProxy();
(address mips,) = opsm.implementations(opsm.latestRelease(), "MIPS");
require(game.vm() == IBigStepper(mips), "DPG-30");

require(address(game.weth()) == address(delayedWETHPermissionedGameProxy()), "DPG-40");
require(address(game.anchorStateRegistry()) == address(anchorStateRegistryProxy()), "DPG-50");
require(game.l2ChainId() == _doi.l2ChainId(), "DPG-60");
}

function assertValidAnchorStateRegistryProxy(DeployOPChainInput) internal {
Expand Down Expand Up @@ -436,7 +451,14 @@ contract DeployOPChainOutput is BaseDeployIO {
}

function assertValidDisputeGameFactory(DeployOPChainInput) internal view {
// TODO add in once FP support is added.
DisputeGameFactory factory = disputeGameFactoryProxy();

DeployUtils.assertInitialized({ _contractAddress: address(factory), _slot: 0, _offset: 0 });

require(
address(factory.gameImpls(GameTypes.PERMISSIONED_CANNON)) == address(permissionedDisputeGame()), "DF-10"
);
require(factory.owner() == address(opChainProxyAdmin()), "DF-20");
}

function assertValidDelayedWETHs(DeployOPChainInput) internal view {
Expand Down Expand Up @@ -480,7 +502,7 @@ contract DeployOPChain is Script {
vm.label(address(deployOutput.disputeGameFactoryProxy), "disputeGameFactoryProxy");
vm.label(address(deployOutput.anchorStateRegistryProxy), "anchorStateRegistryProxy");
vm.label(address(deployOutput.anchorStateRegistryImpl), "anchorStateRegistryImpl");
vm.label(address(deployOutput.faultDisputeGame), "faultDisputeGame");
// vm.label(address(deployOutput.faultDisputeGame), "faultDisputeGame");
vm.label(address(deployOutput.permissionedDisputeGame), "permissionedDisputeGame");
vm.label(address(deployOutput.delayedWETHPermissionedGameProxy), "delayedWETHPermissionedGameProxy");
vm.label(address(deployOutput.delayedWETHPermissionlessGameProxy), "delayedWETHPermissionlessGameProxy");
Expand All @@ -498,7 +520,7 @@ contract DeployOPChain is Script {
_doo.set(_doo.disputeGameFactoryProxy.selector, address(deployOutput.disputeGameFactoryProxy));
_doo.set(_doo.anchorStateRegistryProxy.selector, address(deployOutput.anchorStateRegistryProxy));
_doo.set(_doo.anchorStateRegistryImpl.selector, address(deployOutput.anchorStateRegistryImpl));
_doo.set(_doo.faultDisputeGame.selector, address(deployOutput.faultDisputeGame));
// _doo.set(_doo.faultDisputeGame.selector, address(deployOutput.faultDisputeGame));
_doo.set(_doo.permissionedDisputeGame.selector, address(deployOutput.permissionedDisputeGame));
_doo.set(_doo.delayedWETHPermissionedGameProxy.selector, address(deployOutput.delayedWETHPermissionedGameProxy));
_doo.set(
Expand Down
4 changes: 2 additions & 2 deletions packages/contracts-bedrock/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"sourceCodeHash": "0xde4df0f9633dc0cdb1c9f634003ea5b0f7c5c1aebc407bc1b2f44c0ecf938649"
},
"src/L1/OPStackManager.sol": {
"initCodeHash": "0x4bffecbd95e63f9bd04ab8e3c6a804cc25e0cd151ebeb7f8d6b9330332e6eb20",
"sourceCodeHash": "0x850f1eacc77f1a5c680625196618bc4b4332cb68924d9eddd57c749bedcd7c94"
"initCodeHash": "0x5b451782192b8429f6822c88270c4f0dbd10342518c5695ecf4dff7b5ebfb4e4",
"sourceCodeHash": "0x4a9c242ce96471437ec97662d2365a7bda376db765c630a41cbe238811f1df51"
},
"src/L1/OptimismPortal.sol": {
"initCodeHash": "0xbe2c0c81b3459014f287d8c89cdc0d27dde5d1f44e5d024fa1e4773ddc47c190",
Expand Down
25 changes: 25 additions & 0 deletions packages/contracts-bedrock/snapshots/abi/OPStackManager.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@
"internalType": "address",
"name": "anchorStateRegistry",
"type": "address"
},
{
"internalType": "address",
"name": "permissionedDisputeGame1",
"type": "address"
},
{
"internalType": "address",
"name": "permissionedDisputeGame2",
"type": "address"
}
],
"internalType": "struct OPStackManager.Blueprints",
Expand Down Expand Up @@ -298,6 +308,16 @@
"internalType": "address",
"name": "anchorStateRegistry",
"type": "address"
},
{
"internalType": "address",
"name": "permissionedDisputeGame1",
"type": "address"
},
{
"internalType": "address",
"name": "permissionedDisputeGame2",
"type": "address"
}
],
"internalType": "struct OPStackManager.Blueprints",
Expand Down Expand Up @@ -499,6 +519,11 @@
"name": "EmptyInitcode",
"type": "error"
},
{
"inputs": [],
"name": "IdentityPrecompileCallFailed",
"type": "error"
},
{
"inputs": [],
"name": "InvalidChainId",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@
"internalType": "address",
"name": "anchorStateRegistry",
"type": "address"
},
{
"internalType": "address",
"name": "permissionedDisputeGame1",
"type": "address"
},
{
"internalType": "address",
"name": "permissionedDisputeGame2",
"type": "address"
}
],
"internalType": "struct OPStackManager.Blueprints",
Expand Down Expand Up @@ -298,6 +308,16 @@
"internalType": "address",
"name": "anchorStateRegistry",
"type": "address"
},
{
"internalType": "address",
"name": "permissionedDisputeGame1",
"type": "address"
},
{
"internalType": "address",
"name": "permissionedDisputeGame2",
"type": "address"
}
],
"internalType": "struct OPStackManager.Blueprints",
Expand Down Expand Up @@ -499,6 +519,11 @@
"name": "EmptyInitcode",
"type": "error"
},
{
"inputs": [],
"name": "IdentityPrecompileCallFailed",
"type": "error"
},
{
"inputs": [],
"name": "InvalidChainId",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,39 @@
"slot": "0",
"type": "bool"
},
{
"bytes": "192",
"label": "blueprint",
"offset": 0,
"slot": "1",
"type": "struct OPStackManager.Blueprints"
},
{
"bytes": "32",
"label": "latestRelease",
"offset": 0,
"slot": "7",
"slot": "1",
"type": "string"
},
{
"bytes": "32",
"label": "implementations",
"offset": 0,
"slot": "8",
"slot": "2",
"type": "mapping(string => mapping(string => struct OPStackManager.Implementation))"
},
{
"bytes": "32",
"label": "systemConfigs",
"offset": 0,
"slot": "9",
"slot": "3",
"type": "mapping(uint256 => contract SystemConfig)"
},
{
"bytes": "256",
"label": "blueprint",
"offset": 0,
"slot": "4",
"type": "struct OPStackManager.Blueprints"
},
{
"bytes": "1600",
"label": "__gap",
"offset": 0,
"slot": "12",
"type": "uint256[50]"
}
]
Loading

0 comments on commit 308ce74

Please sign in to comment.