Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ interface IOPContractsManagerStandardValidator {
address challenger;
}

error InvalidGameArgsLength();
Comment thread
Inphi marked this conversation as resolved.

function version() external view returns (string memory);
function anchorStateRegistryImpl() external view returns (address);
function challenger() external view returns (address);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@
"type": "string"
}
],
"stateMutability": "pure",
"stateMutability": "view",
"type": "function"
},
{
Expand Down Expand Up @@ -465,5 +465,10 @@
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "InvalidGameArgsLength",
"type": "error"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,22 @@
"name": "IdentityPrecompileCallFailed",
"type": "error"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "devFeature",
"type": "bytes32"
}
],
"name": "InvalidDevFeatureAccess",
Comment thread
Inphi marked this conversation as resolved.
"type": "error"
},
{
"inputs": [],
"name": "InvalidGameArgsLength",
"type": "error"
},
{
"inputs": [],
"name": "NotABlueprint",
Expand Down
8 changes: 4 additions & 4 deletions packages/contracts-bedrock/snapshots/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
"sourceCodeHash": "0xfca613b5d055ffc4c3cbccb0773ddb9030abedc1aa6508c9e2e7727cc0cd617b"
},
"src/L1/OPContractsManager.sol:OPContractsManager": {
"initCodeHash": "0x4025118658a1c56c4fc2d0166081e6d27da980318e749e7811c7178115e4413e",
"sourceCodeHash": "0xdb243ac7475b0214b8f662aa04f696d9ff213dade6b1bdade379e84df419b75a"
"initCodeHash": "0xc6a5146f158bc14297447cda1668f83e8dbfdd74f1b8bc2291d9626933bd23ad",
"sourceCodeHash": "0x01010fcc469ee5b75a446557ed1dd8e202ad5acd2bc23c7ccc8d7117e714d302"
},
"src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": {
"initCodeHash": "0x57d6a6729d887ead009d518e8f17fa0d26bfc97b8efe1494ab4ef8dbb000d109",
"sourceCodeHash": "0x1d58891954cf782d2fe4f112b0c7fd25be991c2b8873f10d8545c653b517cac9"
"initCodeHash": "0x2eaa345ba05582c67b40a1eb7ec9d54823aa08468e697e2d6c04bb74cc574abc",
"sourceCodeHash": "0x30d7e4243a3bab7fea8504be2cd24f2c5ab3335b802d62282a374a458a08feec"
},
"src/L1/OptimismPortal2.sol:OptimismPortal2": {
"initCodeHash": "0x5bf576ea7f566e402a997204988471fc9b971410aa9dff8fe810b10baf6b7456",
Expand Down
276 changes: 233 additions & 43 deletions packages/contracts-bedrock/src/L1/OPContractsManager.sol

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Constants } from "src/libraries/Constants.sol";
import { Hash } from "src/dispute/lib/Types.sol";
import { Features } from "src/libraries/Features.sol";
import { DevFeatures } from "src/libraries/DevFeatures.sol";
import { LibGameArgs } from "src/dispute/lib/LibGameArgs.sol";

// Interfaces
import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol";
Expand All @@ -30,6 +31,7 @@ import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol";
import { IMIPS64 } from "interfaces/cannon/IMIPS64.sol";
import { ISemver } from "interfaces/universal/ISemver.sol";
import { IProxyAdminOwnedBase } from "interfaces/L1/IProxyAdminOwnedBase.sol";
import { IBigStepper } from "interfaces/dispute/IBigStepper.sol";

/// @title OPContractsManagerStandardValidator
/// @notice This contract is used to validate the configuration of the L1 contracts of an OP Stack chain.
Expand All @@ -38,8 +40,8 @@ import { IProxyAdminOwnedBase } from "interfaces/L1/IProxyAdminOwnedBase.sol";
/// before and after an upgrade.
contract OPContractsManagerStandardValidator is ISemver {
/// @notice The semantic version of the OPContractsManagerStandardValidator contract.
/// @custom:semver 1.18.0
string public constant version = "1.18.0";
/// @custom:semver 1.19.0
string public constant version = "1.19.0";

/// @notice The SuperchainConfig contract.
ISuperchainConfig public superchainConfig;
Expand Down Expand Up @@ -124,6 +126,25 @@ contract OPContractsManagerStandardValidator is ISemver {
address challenger;
}

/// @notice Struct containing the unified game args for a dispute game implementation.
struct DisputeGameImplementation {
address gameAddress;
uint256 maxGameDepth;
uint256 splitDepth;
Duration maxClockDuration;
Duration clockExtension;
GameType gameType;
// extra args
uint256 l2SequenceNumber;
// dispute-game v2 game args
Claim absolutePrestate;
IBigStepper vm;
IAnchorStateRegistry asr;
IDelayedWETH weth;
uint256 l2ChainId;
address challenger;
}

/// @notice Constructor for the OPContractsManagerStandardValidator contract.
constructor(
Implementations memory _implementations,
Expand Down Expand Up @@ -187,8 +208,12 @@ contract OPContractsManagerStandardValidator is ISemver {
}

/// @notice Returns the expected PermissionedDisputeGame version.
function permissionedDisputeGameVersion() public pure returns (string memory) {
return "1.8.0";
function permissionedDisputeGameVersion() public view returns (string memory) {
if (DevFeatures.isDevFeatureEnabled(devFeatureBitmap, DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) {
return "2.1.0";
} else {
return "1.8.0";
}
}

/// @notice Returns the expected PreimageOracle version.
Expand Down Expand Up @@ -495,10 +520,19 @@ contract OPContractsManagerStandardValidator is ISemver {
return _errors;
}

bytes memory _gameArgs = _factory.gameArgs(GameTypes.PERMISSIONED_CANNON);
bool lenCheckFailed;
(_errors, lenCheckFailed) = assertGameArgsLength(_errors, _gameArgs, true, "PDDG");
if (lenCheckFailed) {
// bail out immediately to avoid trying to validate an invalid dispute game
return _errors;
}

DisputeGameImplementation memory _gameImpl = _decodeDisputeGameImpl(_game, _gameArgs, true);
_errors = assertValidDisputeGame(
_errors,
_sysCfg,
_game,
_gameImpl,
_factory,
_absolutePrestate,
_l2ChainID,
Expand All @@ -510,7 +544,7 @@ contract OPContractsManagerStandardValidator is ISemver {

// Challenger is specific to the PermissionedDisputeGame contract.
address _challenger = expectedChallenger(_overrides);
_errors = internalRequire(_game.challenger() == _challenger, "PDDG-130", _errors);
_errors = internalRequire(_gameImpl.challenger == _challenger, "PDDG-130", _errors);

return _errors;
}
Expand Down Expand Up @@ -538,10 +572,19 @@ contract OPContractsManagerStandardValidator is ISemver {
return _errors;
}

bytes memory _gameArgs = _factory.gameArgs(GameTypes.CANNON);
bool lenCheckFailed;
(_errors, lenCheckFailed) = assertGameArgsLength(_errors, _gameArgs, false, "PLDG");
if (lenCheckFailed) {
// bail out immediately to avoid trying to validate an invalid dispute game
return _errors;
}

DisputeGameImplementation memory _gameImpl = _decodeDisputeGameImpl(_game, _gameArgs, false);
_errors = assertValidDisputeGame(
_errors,
_sysCfg,
_game,
_gameImpl,
_factory,
_absolutePrestate,
_l2ChainID,
Expand All @@ -558,7 +601,7 @@ contract OPContractsManagerStandardValidator is ISemver {
function assertValidDisputeGame(
string memory _errors,
ISystemConfig _sysCfg,
IPermissionedDisputeGame _game,
DisputeGameImplementation memory _game,
IDisputeGameFactory _factory,
bytes32 _absolutePrestate,
uint256 _l2ChainID,
Expand All @@ -571,41 +614,40 @@ contract OPContractsManagerStandardValidator is ISemver {
view
returns (string memory)
{
IAnchorStateRegistry _asr = _game.anchorStateRegistry();
(Hash anchorRoot,) = _asr.getAnchorRoot();
(Hash anchorRoot,) = _game.asr.getAnchorRoot();

_errors = internalRequire(
LibString.eq(getVersion(address(_game)), permissionedDisputeGameVersion()),
LibString.eq(getVersion(_game.gameAddress), permissionedDisputeGameVersion()),
string.concat(_errorPrefix, "-20"),
_errors
);

_errors = internalRequire(
GameType.unwrap(_game.gameType()) == GameType.unwrap(_gameType), string.concat(_errorPrefix, "-30"), _errors
);
_errors = internalRequire(
Claim.unwrap(_game.absolutePrestate()) == _absolutePrestate, string.concat(_errorPrefix, "-40"), _errors
GameType.unwrap(_game.gameType) == GameType.unwrap(_gameType), string.concat(_errorPrefix, "-30"), _errors
);
_errors = internalRequire(_game.l2ChainId() == _l2ChainID, string.concat(_errorPrefix, "-60"), _errors);
_errors = internalRequire(_game.l2SequenceNumber() == 0, string.concat(_errorPrefix, "-70"), _errors);
_errors = internalRequire(
Duration.unwrap(_game.clockExtension()) == 10800, string.concat(_errorPrefix, "-80"), _errors
Claim.unwrap(_game.absolutePrestate) == _absolutePrestate, string.concat(_errorPrefix, "-40"), _errors
);
_errors = internalRequire(_game.splitDepth() == 30, string.concat(_errorPrefix, "-90"), _errors);
_errors = internalRequire(_game.maxGameDepth() == 73, string.concat(_errorPrefix, "-100"), _errors);
_errors = internalRequire(_game.l2ChainId == _l2ChainID, string.concat(_errorPrefix, "-60"), _errors);
_errors = internalRequire(_game.l2SequenceNumber == 0, string.concat(_errorPrefix, "-70"), _errors);
_errors =
internalRequire(Duration.unwrap(_game.clockExtension) == 10800, string.concat(_errorPrefix, "-80"), _errors);
_errors = internalRequire(_game.splitDepth == 30, string.concat(_errorPrefix, "-90"), _errors);
_errors = internalRequire(_game.maxGameDepth == 73, string.concat(_errorPrefix, "-100"), _errors);
_errors = internalRequire(
Duration.unwrap(_game.maxClockDuration()) == 302400, string.concat(_errorPrefix, "-110"), _errors
Duration.unwrap(_game.maxClockDuration) == 302400, string.concat(_errorPrefix, "-110"), _errors
);
_errors = internalRequire(Hash.unwrap(anchorRoot) != bytes32(0), string.concat(_errorPrefix, "-120"), _errors);

_errors = assertValidDelayedWETH(_errors, _sysCfg, _game.weth(), _admin, _overrides, _errorPrefix);
_errors = assertValidAnchorStateRegistry(_errors, _sysCfg, _factory, _asr, _admin, _errorPrefix);
_errors = assertValidDelayedWETH(_errors, _sysCfg, _game.weth, _admin, _overrides, _errorPrefix);
_errors = assertValidAnchorStateRegistry(_errors, _sysCfg, _factory, _game.asr, _admin, _errorPrefix);

_errors = assertValidMipsVm(_errors, IMIPS64(address(_game.vm())), _errorPrefix);
_errors = assertValidMipsVm(_errors, IMIPS64(address(_game.vm)), _errorPrefix);

// Only assert valid preimage oracle if the game VM is valid, since otherwise
// the contract is likely to revert.
if (address(_game.vm()) == mipsImpl) {
_errors = assertValidPreimageOracle(_errors, _game.vm().oracle(), _errorPrefix);
if (address(_game.vm) == mipsImpl) {
_errors = assertValidPreimageOracle(_errors, _game.vm.oracle(), _errorPrefix);
}

return _errors;
Expand Down Expand Up @@ -798,4 +840,74 @@ contract OPContractsManagerStandardValidator is ISemver {

return finalErrors;
}

function assertGameArgsLength(
string memory _errors,
bytes memory _gameArgsBytes,
bool _isPermissioned,
string memory _errorPrefix
)
internal
view
returns (string memory errors_, bool failed_)
{
_errorPrefix = string.concat(_errorPrefix, "-GARGS");
if (DevFeatures.isDevFeatureEnabled(devFeatureBitmap, DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) {
if (_isPermissioned) {
bool ok = LibGameArgs.isValidPermissionedArgs(_gameArgsBytes);
_errors = internalRequire(ok, string.concat(_errorPrefix, "-10"), _errors);
return (_errors, !ok);
} else {
bool ok = LibGameArgs.isValidPermissionlessArgs(_gameArgsBytes);
_errors = internalRequire(ok, string.concat(_errorPrefix, "-10"), _errors);
return (_errors, !ok);
}
} else {
bool ok = _gameArgsBytes.length == 0;
_errors = internalRequire(ok, string.concat(_errorPrefix, "-10"), _errors);
return (_errors, !ok);
}
}

// @notice Internal function to read all information from a dispute game while supporting both v1 and v2 dispute
/// games.
function _decodeDisputeGameImpl(
IPermissionedDisputeGame _game,
bytes memory _gameArgsBytes,
bool _isPermissioned
)
internal
view
returns (DisputeGameImplementation memory gameImpl_)
{
LibGameArgs.GameArgs memory gameArgs;
if (DevFeatures.isDevFeatureEnabled(devFeatureBitmap, DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) {
gameArgs = LibGameArgs.decode(_gameArgsBytes);
} else {
gameArgs.absolutePrestate = Claim.unwrap(_game.absolutePrestate());
gameArgs.vm = address(_game.vm());
gameArgs.anchorStateRegistry = address(_game.anchorStateRegistry());
gameArgs.weth = address(_game.weth());
gameArgs.l2ChainId = _game.l2ChainId();
if (_isPermissioned) {
gameArgs.challenger = _game.challenger();
}
}

gameImpl_ = DisputeGameImplementation({
gameAddress: address(_game),
maxGameDepth: _game.maxGameDepth(),
splitDepth: _game.splitDepth(),
maxClockDuration: _game.maxClockDuration(),
clockExtension: _game.clockExtension(),
gameType: _game.gameType(),
l2SequenceNumber: _game.l2SequenceNumber(),
absolutePrestate: Claim.wrap(gameArgs.absolutePrestate),
vm: IBigStepper(gameArgs.vm),
asr: IAnchorStateRegistry(gameArgs.anchorStateRegistry),
weth: IDelayedWETH(payable(gameArgs.weth)),
l2ChainId: gameArgs.l2ChainId,
challenger: gameArgs.challenger
});
}
}
7 changes: 7 additions & 0 deletions packages/contracts-bedrock/src/dispute/lib/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,10 @@ error BadAuth();

/// @notice Thrown when trying to close a game while the system is paused.
error GamePaused();

////////////////////////////////////////////////////////////////
// `LibGameArgs` Errors //
////////////////////////////////////////////////////////////////

/// @notice Thrown when the length of the game arguments is invalid.
error InvalidGameArgsLength();
Loading