Skip to content

Commit 3b0bfac

Browse files
authored
opcm: Support v2 games for updatePrestate (#17956)
* test: Check game args after opcm.updatePrestate for v2 games * remove skips for super DG tests * use adrian's change
1 parent 56f5a97 commit 3b0bfac

File tree

3 files changed

+140
-95
lines changed

3 files changed

+140
-95
lines changed

packages/contracts-bedrock/snapshots/semver-lock.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
"sourceCodeHash": "0xfca613b5d055ffc4c3cbccb0773ddb9030abedc1aa6508c9e2e7727cc0cd617b"
2121
},
2222
"src/L1/OPContractsManager.sol:OPContractsManager": {
23-
"initCodeHash": "0x02af0627bee699be308b7d83ceb41655c38ae6856ed3842246917ae696475d64",
24-
"sourceCodeHash": "0x76f8991025c5346053444d50c4c0b63faa1739deebdbad99360fe37ca068ed15"
23+
"initCodeHash": "0x1a1de93a1e15a32fd621b572211bd1ceccf82d5d2b936e0aa337ea7593c1ce19",
24+
"sourceCodeHash": "0xbe7ceb48b39fc1d6c311b9d6dd9095ee72fa5cf82f72d27ec4511c97c01b02aa"
2525
},
2626
"src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": {
2727
"initCodeHash": "0x2eaa345ba05582c67b40a1eb7ec9d54823aa08468e697e2d6c04bb74cc574abc",

packages/contracts-bedrock/src/L1/OPContractsManager.sol

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,24 @@ abstract contract OPContractsManagerBase {
462462
}
463463
}
464464

465+
/// @notice Retrieves the BigStepper VM for a given v1 or v2 game
466+
function getVM(
467+
IDisputeGameFactory _disputeGameFactory,
468+
IDisputeGame _disputeGame,
469+
GameType _gameType
470+
)
471+
internal
472+
view
473+
returns (IBigStepper)
474+
{
475+
bytes memory gameArgsBytes = _disputeGameFactory.gameArgs(_gameType);
476+
if (gameArgsBytes.length == 0) {
477+
return IFaultDisputeGame(address(_disputeGame)).vm();
478+
} else {
479+
return IBigStepper(LibGameArgs.decode(gameArgsBytes).vm);
480+
}
481+
}
482+
465483
/// @notice Sets a game implementation on the dispute game factory
466484
/// @param _dgf The dispute game factory
467485
/// @param _gameType The game type
@@ -688,8 +706,8 @@ contract OPContractsManagerGameTypeAdder is OPContractsManagerBase {
688706
getAnchorStateRegistry(gameConfig.systemConfig),
689707
gameL2ChainId
690708
),
691-
getProposerV1(IPermissionedDisputeGame(address(existingGame))),
692-
getChallengerV1(IPermissionedDisputeGame(address(existingGame)))
709+
getProposer(dgf, IPermissionedDisputeGame(address(existingGame)), gameConfig.disputeGameType),
710+
getChallenger(dgf, IPermissionedDisputeGame(address(existingGame)), gameConfig.disputeGameType)
693711
);
694712
} else {
695713
constructorData = encodePermissionlessFDGConstructor(
@@ -804,23 +822,20 @@ contract OPContractsManagerGameTypeAdder is OPContractsManagerBase {
804822
revert OPContractsManager.PrestateRequired();
805823
}
806824

807-
// Grab the existing game constructor params and init bond.
808-
IFaultDisputeGame.GameConstructorParams memory gameParams = getGameConstructorParams(existingGame);
809-
810825
// Create a new game input with the updated prestate.
811826
OPContractsManager.AddGameInput memory input = OPContractsManager.AddGameInput({
812827
disputeAbsolutePrestate: prestate,
813828
saltMixer: reusableSaltMixer(_prestateUpdateInputs[i].systemConfigProxy),
814829
systemConfig: _prestateUpdateInputs[i].systemConfigProxy,
815830
proxyAdmin: _prestateUpdateInputs[i].systemConfigProxy.proxyAdmin(),
816-
delayedWETH: IDelayedWETH(payable(address(gameParams.weth))),
817-
disputeGameType: gameParams.gameType,
818-
disputeMaxGameDepth: gameParams.maxGameDepth,
819-
disputeSplitDepth: gameParams.splitDepth,
820-
disputeClockExtension: gameParams.clockExtension,
821-
disputeMaxClockDuration: gameParams.maxClockDuration,
831+
delayedWETH: getWETH(dgf, existingGame, gameType),
832+
disputeGameType: gameType,
833+
disputeMaxGameDepth: existingGame.maxGameDepth(),
834+
disputeSplitDepth: existingGame.splitDepth(),
835+
disputeClockExtension: existingGame.clockExtension(),
836+
disputeMaxClockDuration: existingGame.maxClockDuration(),
822837
initialBond: dgf.initBonds(gameType),
823-
vm: gameParams.vm,
838+
vm: getVM(dgf, existingGame, gameType),
824839
permissioned: gameType.raw() == GameTypes.PERMISSIONED_CANNON.raw()
825840
|| gameType.raw() == GameTypes.SUPER_PERMISSIONED_CANNON.raw()
826841
});
@@ -993,7 +1008,7 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase {
9931008
if (!isDevFeatureEnabled(DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) {
9941009
// Update the PermissionedDisputeGame.
9951010
// We're reusing the same DelayedWETH and ASR contracts.
996-
deployAndSetNewGameImpl({
1011+
deployAndSetNewGameImplV1({
9971012
_l2ChainId: _l2ChainId,
9981013
_disputeGame: permissionedDisputeGame,
9991014
_newDelayedWeth: getWETHV1(IFaultDisputeGame(address(permissionedDisputeGame))),
@@ -1008,7 +1023,7 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase {
10081023
// If it exists, replace its implementation.
10091024
// We're reusing the same DelayedWETH and ASR contracts.
10101025
if (address(permissionlessDisputeGame) != address(0)) {
1011-
deployAndSetNewGameImpl({
1026+
deployAndSetNewGameImplV1({
10121027
_l2ChainId: _l2ChainId,
10131028
_disputeGame: permissionlessDisputeGame,
10141029
_newDelayedWeth: getWETHV1(IFaultDisputeGame(address(permissionlessDisputeGame))),
@@ -1087,14 +1102,14 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase {
10871102
assertValidContractAddress(address(_config.proxyAdmin));
10881103
}
10891104

1090-
/// @notice Deploys and sets a new dispute game implementation
1105+
/// @notice Deploys and sets a new v1 dispute game implementation
10911106
/// @param _l2ChainId The L2 chain ID
10921107
/// @param _disputeGame The current dispute game implementation
10931108
/// @param _newDelayedWeth The new delayed WETH implementation
10941109
/// @param _newAnchorStateRegistryProxy The new anchor state registry proxy
10951110
/// @param _gameType The type of game to deploy
10961111
/// @param _opChainConfig The OP chain configuration
1097-
function deployAndSetNewGameImpl(
1112+
function deployAndSetNewGameImplV1(
10981113
uint256 _l2ChainId,
10991114
IDisputeGame _disputeGame,
11001115
IDelayedWETH _newDelayedWeth,
@@ -2138,9 +2153,9 @@ contract OPContractsManager is ISemver {
21382153

21392154
// -------- Constants and Variables --------
21402155

2141-
/// @custom:semver 4.5.0
2156+
/// @custom:semver 4.6.0
21422157
function version() public pure virtual returns (string memory) {
2143-
return "4.5.0";
2158+
return "4.6.0";
21442159
}
21452160

21462161
OPContractsManagerGameTypeAdder public immutable opcmGameTypeAdder;

packages/contracts-bedrock/test/L1/OPContractsManager.t.sol

Lines changed: 105 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -948,12 +948,6 @@ contract OPContractsManager_UpdatePrestate_Test is OPContractsManager_TestInit {
948948

949949
function setUp() public virtual override {
950950
super.setUp();
951-
952-
// Skip UpdatePrestate tests when V2 dispute games enabled
953-
// UpdatePrestate feature not yet implemented for V2
954-
// TODO(#17261): Remove skip when V2 dispute game support for updatePrestate implemented
955-
skipIfDevFeatureEnabled(DevFeatures.DEPLOY_V2_DISPUTE_GAMES);
956-
957951
prestateUpdater = opcm;
958952
}
959953

@@ -963,6 +957,55 @@ contract OPContractsManager_UpdatePrestate_Test is OPContractsManager_TestInit {
963957
_runUpdatePrestateAndChecks(_input, bytes(""));
964958
}
965959

960+
/// @notice Returns the game args of a v1 or v2 game.
961+
function _getGameArgs(
962+
IDisputeGameFactory _dgf,
963+
GameType _gameType
964+
)
965+
internal
966+
view
967+
returns (LibGameArgs.GameArgs memory gameArgs_)
968+
{
969+
bytes memory args = _dgf.gameArgs(_gameType);
970+
if (args.length == 0) {
971+
IPermissionedDisputeGame game = IPermissionedDisputeGame(address(_dgf.gameImpls(_gameType)));
972+
gameArgs_.absolutePrestate = game.absolutePrestate().raw();
973+
gameArgs_.vm = address(game.vm());
974+
gameArgs_.anchorStateRegistry = address(game.anchorStateRegistry());
975+
gameArgs_.weth = address(game.weth());
976+
gameArgs_.l2ChainId = game.l2ChainId();
977+
if (
978+
game.gameType().raw() == GameTypes.PERMISSIONED_CANNON.raw()
979+
|| game.gameType().raw() == GameTypes.SUPER_PERMISSIONED_CANNON.raw()
980+
) {
981+
gameArgs_.proposer = game.proposer();
982+
gameArgs_.challenger = game.challenger();
983+
}
984+
return gameArgs_;
985+
} else {
986+
return LibGameArgs.decode(args);
987+
}
988+
}
989+
990+
function _assertGameArgsEqual(
991+
LibGameArgs.GameArgs memory a,
992+
LibGameArgs.GameArgs memory b,
993+
bool _skipPrestateCheck
994+
)
995+
internal
996+
pure
997+
{
998+
if (!_skipPrestateCheck) {
999+
assertEq(a.absolutePrestate, b.absolutePrestate, "absolutePrestate mismatch");
1000+
}
1001+
assertEq(a.vm, b.vm, "vm mismatch");
1002+
assertEq(a.anchorStateRegistry, b.anchorStateRegistry, "anchorStateRegistry mismatch");
1003+
assertEq(a.weth, b.weth, "weth mismatch");
1004+
assertEq(a.l2ChainId, b.l2ChainId, "l2ChainId mismatch");
1005+
assertEq(a.proposer, b.proposer, "proposer mismatch");
1006+
assertEq(a.challenger, b.challenger, "challenger mismatch");
1007+
}
1008+
9661009
/// @notice Runs the OPCM updatePrestate function and checks the results.
9671010
/// @param _input The input to the OPCM updatePrestate function.
9681011
/// @param _revertBytes The bytes of the revert to expect, if any.
@@ -981,6 +1024,18 @@ contract OPContractsManager_UpdatePrestate_Test is OPContractsManager_TestInit {
9811024
)
9821025
) != address(0);
9831026

1027+
// Retrieve current game args before updatePrestate
1028+
IDisputeGameFactory dgf = IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory());
1029+
LibGameArgs.GameArgs memory pdgArgsBefore = _getGameArgs(dgf, GameTypes.PERMISSIONED_CANNON);
1030+
LibGameArgs.GameArgs memory cannonArgsBefore;
1031+
LibGameArgs.GameArgs memory cannonKonaArgsBefore;
1032+
if (expectCannonUpdated) {
1033+
cannonArgsBefore = _getGameArgs(dgf, GameTypes.CANNON);
1034+
}
1035+
if (expectCannonKonaUpdated) {
1036+
cannonKonaArgsBefore = _getGameArgs(dgf, GameTypes.CANNON_KONA);
1037+
}
1038+
9841039
// Turn the ProxyAdmin owner into a DelegateCaller.
9851040
address proxyAdminOwner = chainDeployOutput1.opChainProxyAdmin.owner();
9861041
vm.etch(address(proxyAdminOwner), vm.getDeployedCode("test/mocks/Callers.sol:DelegateCaller"));
@@ -1002,65 +1057,62 @@ contract OPContractsManager_UpdatePrestate_Test is OPContractsManager_TestInit {
10021057
return;
10031058
}
10041059

1005-
// Grab the PermissionedDisputeGame.
1006-
IPermissionedDisputeGame pdg = IPermissionedDisputeGame(
1007-
address(
1008-
IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()).gameImpls(
1009-
GameTypes.PERMISSIONED_CANNON
1010-
)
1011-
)
1012-
);
1013-
assertEq(pdg.absolutePrestate().raw(), _input.cannonPrestate.raw(), "permissioned game prestate mismatch");
1060+
LibGameArgs.GameArgs memory pdgArgsAfter = _getGameArgs(dgf, GameTypes.PERMISSIONED_CANNON);
1061+
_assertGameArgsEqual(pdgArgsBefore, pdgArgsAfter, true);
1062+
assertEq(pdgArgsAfter.absolutePrestate, _input.cannonPrestate.raw(), "permissioned game prestate mismatch");
10141063
// Ensure that the WETH contracts are not reverting
1015-
pdg.weth().balanceOf(address(0));
1064+
IDelayedWETH(payable(pdgArgsAfter.weth)).balanceOf(address(0));
10161065

10171066
if (expectCannonUpdated) {
1018-
IPermissionedDisputeGame game = IPermissionedDisputeGame(
1019-
address(
1020-
IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()).gameImpls(
1021-
GameTypes.CANNON
1022-
)
1023-
)
1024-
);
1025-
assertEq(game.absolutePrestate().raw(), _input.cannonPrestate.raw(), "cannon game prestate mismatch");
1067+
LibGameArgs.GameArgs memory cannonArgsAfter = _getGameArgs(dgf, GameTypes.CANNON);
1068+
_assertGameArgsEqual(cannonArgsBefore, cannonArgsAfter, true);
1069+
assertEq(cannonArgsAfter.absolutePrestate, _input.cannonPrestate.raw(), "cannon game prestate mismatch");
10261070
// Ensure that the WETH contracts are not reverting
1027-
game.weth().balanceOf(address(0));
1071+
IDelayedWETH(payable(cannonArgsAfter.weth)).balanceOf(address(0));
10281072
} else {
1029-
assertEq(
1030-
address(
1031-
IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()).gameImpls(
1032-
GameTypes.CANNON
1033-
)
1034-
),
1035-
(address(0)),
1036-
"cannon game should not exist"
1037-
);
1073+
assertEq(address(dgf.gameImpls(GameTypes.CANNON)), (address(0)), "cannon game should not exist");
10381074
}
10391075

10401076
if (expectCannonKonaUpdated) {
1041-
IPermissionedDisputeGame game = IPermissionedDisputeGame(
1042-
address(
1043-
IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()).gameImpls(
1044-
GameTypes.CANNON_KONA
1045-
)
1046-
)
1077+
LibGameArgs.GameArgs memory cannonKonaArgsAfter = _getGameArgs(dgf, GameTypes.CANNON_KONA);
1078+
_assertGameArgsEqual(cannonKonaArgsBefore, cannonKonaArgsAfter, true);
1079+
assertEq(
1080+
cannonKonaArgsAfter.absolutePrestate,
1081+
_input.cannonKonaPrestate.raw(),
1082+
"cannon-kona game prestate mismatch"
10471083
);
1048-
assertEq(game.absolutePrestate().raw(), _input.cannonKonaPrestate.raw(), "cannon game prestate mismatch");
10491084
// Ensure that the WETH contracts are not reverting
1050-
game.weth().balanceOf(address(0));
1085+
IDelayedWETH(payable(cannonKonaArgsAfter.weth)).balanceOf(address(0));
10511086
} else {
1052-
assertEq(
1053-
address(
1054-
IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()).gameImpls(
1055-
GameTypes.CANNON_KONA
1056-
)
1057-
),
1058-
(address(0)),
1059-
"cannon_kona game should not exist"
1060-
);
1087+
assertEq(address(dgf.gameImpls(GameTypes.CANNON_KONA)), (address(0)), "cannon_kona game should not exist");
10611088
}
10621089
}
10631090

1091+
/// @notice Mocks the existence of a previous SuperPermissionedDisputeGame so we can add a real
1092+
/// SuperPermissionedDisputeGame implementation by calling opcm.updatePrestate.
1093+
function _mockSuperPermissionedGame() internal {
1094+
vm.mockCall(
1095+
address(chainDeployOutput1.disputeGameFactoryProxy),
1096+
abi.encodeCall(IDisputeGameFactory.gameImpls, (GameTypes.SUPER_PERMISSIONED_CANNON)),
1097+
abi.encode(chainDeployOutput1.permissionedDisputeGame)
1098+
);
1099+
vm.mockCall(
1100+
address(chainDeployOutput1.permissionedDisputeGame),
1101+
abi.encodeCall(IDisputeGame.gameType, ()),
1102+
abi.encode(GameTypes.SUPER_PERMISSIONED_CANNON)
1103+
);
1104+
vm.mockCall(
1105+
address(chainDeployOutput1.permissionedDisputeGame),
1106+
abi.encodeCall(IPermissionedDisputeGame.proposer, ()),
1107+
abi.encode(proposer)
1108+
);
1109+
vm.mockCall(
1110+
address(chainDeployOutput1.permissionedDisputeGame),
1111+
abi.encodeCall(IPermissionedDisputeGame.challenger, ()),
1112+
abi.encode(challenger)
1113+
);
1114+
}
1115+
10641116
/// @notice Tests that we can update the prestate when only the PermissionedDisputeGame exists.
10651117
function test_updatePrestate_pdgOnlyWithValidInput_succeeds() public {
10661118
Claim prestate = Claim.wrap(bytes32(hex"ABBA"));
@@ -1093,18 +1145,7 @@ contract OPContractsManager_UpdatePrestate_Test is OPContractsManager_TestInit {
10931145
/// shouldn't matter because the function is independent of other game types that
10941146
/// exist.
10951147
function test_updatePrestate_withSuperGame_succeeds() public {
1096-
// Mock out the existence of a previous SuperPermissionedDisputeGame so we can add a real
1097-
// SuperPermissionedDisputeGame implementation.
1098-
vm.mockCall(
1099-
address(chainDeployOutput1.disputeGameFactoryProxy),
1100-
abi.encodeCall(IDisputeGameFactory.gameImpls, (GameTypes.SUPER_PERMISSIONED_CANNON)),
1101-
abi.encode(chainDeployOutput1.permissionedDisputeGame)
1102-
);
1103-
vm.mockCall(
1104-
address(chainDeployOutput1.permissionedDisputeGame),
1105-
abi.encodeCall(IDisputeGame.gameType, ()),
1106-
abi.encode(GameTypes.SUPER_PERMISSIONED_CANNON)
1107-
);
1148+
_mockSuperPermissionedGame();
11081149

11091150
// Add a SuperPermissionedDisputeGame implementation via addGameType.
11101151
IOPContractsManager.AddGameInput memory input1 = newGameInputFactory(GameTypes.SUPER_PERMISSIONED_CANNON);
@@ -1233,19 +1274,8 @@ contract OPContractsManager_UpdatePrestate_Test is OPContractsManager_TestInit {
12331274

12341275
function test_updatePrestate_cannonKonaWithSuperGame_succeeds() public {
12351276
skipIfDevFeatureDisabled(DevFeatures.CANNON_KONA);
1236-
// Mock out the existence of a previous SuperPermissionedDisputeGame so we can add a real
1237-
// SuperPermissionedDisputeGame implementation.
1238-
vm.mockCall(
1239-
address(chainDeployOutput1.disputeGameFactoryProxy),
1240-
abi.encodeCall(IDisputeGameFactory.gameImpls, (GameTypes.SUPER_PERMISSIONED_CANNON)),
1241-
abi.encode(chainDeployOutput1.permissionedDisputeGame)
1242-
);
1243-
vm.mockCall(
1244-
address(chainDeployOutput1.permissionedDisputeGame),
1245-
abi.encodeCall(IDisputeGame.gameType, ()),
1246-
abi.encode(GameTypes.SUPER_PERMISSIONED_CANNON)
1247-
);
12481277

1278+
_mockSuperPermissionedGame();
12491279
// Add a SuperPermissionedDisputeGame implementation via addGameType.
12501280
IOPContractsManager.AddGameInput memory input1 = newGameInputFactory(GameTypes.SUPER_PERMISSIONED_CANNON);
12511281
addGameType(input1);

0 commit comments

Comments
 (0)