Commit cdae7f2b authored by smartcontracts's avatar smartcontracts Committed by GitHub

fix: stack too deep in PermissionedDisputeGame (#13141)

Fixes the stack-too-deep error in the PermissionedDisputeGame by
updating the game to use a struct as the constructor parameter.
parent d1a2198b
...@@ -64,20 +64,6 @@ import { IPreimageOracle } from "src/cannon/interfaces/IPreimageOracle.sol"; ...@@ -64,20 +64,6 @@ import { IPreimageOracle } from "src/cannon/interfaces/IPreimageOracle.sol";
contract Deploy is Deployer { contract Deploy is Deployer {
using stdJson for string; using stdJson for string;
/// @notice FaultDisputeGameParams is a struct that contains the parameters necessary to call
/// the function _setFaultGameImplementation. This struct exists because the EVM needs
/// to finally adopt PUSHN and get rid of stack too deep once and for all.
/// Someday we will look back and laugh about stack too deep, today is not that day.
struct FaultDisputeGameParams {
IAnchorStateRegistry anchorStateRegistry;
IDelayedWETH weth;
GameType gameType;
Claim absolutePrestate;
IBigStepper faultVm;
uint256 maxGameDepth;
Duration maxClockDuration;
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Modifiers // // Modifiers //
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
...@@ -871,14 +857,17 @@ contract Deploy is Deployer { ...@@ -871,14 +857,17 @@ contract Deploy is Deployer {
// Set the Cannon FaultDisputeGame implementation in the factory. // Set the Cannon FaultDisputeGame implementation in the factory.
_setFaultGameImplementation({ _setFaultGameImplementation({
_factory: factory, _factory: factory,
_params: FaultDisputeGameParams({ _params: IFaultDisputeGame.GameConstructorParams({
anchorStateRegistry: IAnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
weth: weth,
gameType: GameTypes.CANNON, gameType: GameTypes.CANNON,
absolutePrestate: loadMipsAbsolutePrestate(), absolutePrestate: loadMipsAbsolutePrestate(),
faultVm: IBigStepper(mustGetAddress("Mips")),
maxGameDepth: cfg.faultGameMaxDepth(), maxGameDepth: cfg.faultGameMaxDepth(),
maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())) splitDepth: cfg.faultGameSplitDepth(),
clockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())),
maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())),
vm: IBigStepper(mustGetAddress("Mips")),
weth: weth,
anchorStateRegistry: IAnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
l2ChainId: cfg.l2ChainID()
}) })
}); });
} }
...@@ -892,15 +881,18 @@ contract Deploy is Deployer { ...@@ -892,15 +881,18 @@ contract Deploy is Deployer {
Claim outputAbsolutePrestate = Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate())); Claim outputAbsolutePrestate = Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate()));
_setFaultGameImplementation({ _setFaultGameImplementation({
_factory: factory, _factory: factory,
_params: FaultDisputeGameParams({ _params: IFaultDisputeGame.GameConstructorParams({
anchorStateRegistry: IAnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
weth: weth,
gameType: GameTypes.ALPHABET, gameType: GameTypes.ALPHABET,
absolutePrestate: outputAbsolutePrestate, absolutePrestate: outputAbsolutePrestate,
faultVm: IBigStepper(new AlphabetVM(outputAbsolutePrestate, IPreimageOracle(mustGetAddress("PreimageOracle")))),
// The max depth for the alphabet trace is always 3. Add 1 because split depth is fully inclusive. // The max depth for the alphabet trace is always 3. Add 1 because split depth is fully inclusive.
maxGameDepth: cfg.faultGameSplitDepth() + 3 + 1, maxGameDepth: cfg.faultGameSplitDepth() + 3 + 1,
maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())) splitDepth: cfg.faultGameSplitDepth(),
clockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())),
maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())),
vm: IBigStepper(new AlphabetVM(outputAbsolutePrestate, IPreimageOracle(mustGetAddress("PreimageOracle")))),
weth: weth,
anchorStateRegistry: IAnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
l2ChainId: cfg.l2ChainID()
}) })
}); });
} }
...@@ -925,23 +917,26 @@ contract Deploy is Deployer { ...@@ -925,23 +917,26 @@ contract Deploy is Deployer {
); );
_setFaultGameImplementation({ _setFaultGameImplementation({
_factory: factory, _factory: factory,
_params: FaultDisputeGameParams({ _params: IFaultDisputeGame.GameConstructorParams({
anchorStateRegistry: IAnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
weth: weth,
gameType: GameTypes.FAST, gameType: GameTypes.FAST,
absolutePrestate: outputAbsolutePrestate, absolutePrestate: outputAbsolutePrestate,
faultVm: IBigStepper(new AlphabetVM(outputAbsolutePrestate, fastOracle)),
// The max depth for the alphabet trace is always 3. Add 1 because split depth is fully inclusive. // The max depth for the alphabet trace is always 3. Add 1 because split depth is fully inclusive.
maxGameDepth: cfg.faultGameSplitDepth() + 3 + 1, maxGameDepth: cfg.faultGameSplitDepth() + 3 + 1,
maxClockDuration: Duration.wrap(0) // Resolvable immediately splitDepth: cfg.faultGameSplitDepth(),
}) clockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())),
maxClockDuration: Duration.wrap(0), // Resolvable immediately
vm: IBigStepper(new AlphabetVM(outputAbsolutePrestate, fastOracle)),
weth: weth,
anchorStateRegistry: IAnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
l2ChainId: cfg.l2ChainID()
})
}); });
} }
/// @notice Sets the implementation for the given fault game type in the `DisputeGameFactory`. /// @notice Sets the implementation for the given fault game type in the `DisputeGameFactory`.
function _setFaultGameImplementation( function _setFaultGameImplementation(
IDisputeGameFactory _factory, IDisputeGameFactory _factory,
FaultDisputeGameParams memory _params IFaultDisputeGame.GameConstructorParams memory _params
) )
internal internal
{ {
...@@ -954,37 +949,19 @@ contract Deploy is Deployer { ...@@ -954,37 +949,19 @@ contract Deploy is Deployer {
} }
uint32 rawGameType = GameType.unwrap(_params.gameType); uint32 rawGameType = GameType.unwrap(_params.gameType);
// Redefine _param variable to avoid stack too deep error during compilation
FaultDisputeGameParams memory _params_ = _params;
require( require(
rawGameType != GameTypes.PERMISSIONED_CANNON.raw(), "Deploy: Permissioned Game should be deployed by OPCM" rawGameType != GameTypes.PERMISSIONED_CANNON.raw(), "Deploy: Permissioned Game should be deployed by OPCM"
); );
_factory.setImplementation( _factory.setImplementation(
_params_.gameType, _params.gameType,
IDisputeGame( IDisputeGame(
DeployUtils.create2AndSave({ DeployUtils.create2AndSave({
_save: this, _save: this,
_salt: _implSalt(), _salt: _implSalt(),
_name: "FaultDisputeGame", _name: "FaultDisputeGame",
_nick: string.concat("FaultDisputeGame_", vm.toString(rawGameType)), _nick: string.concat("FaultDisputeGame_", vm.toString(rawGameType)),
_args: DeployUtils.encodeConstructor( _args: DeployUtils.encodeConstructor(abi.encodeCall(IFaultDisputeGame.__constructor__, (_params)))
abi.encodeCall(
IFaultDisputeGame.__constructor__,
(
_params_.gameType,
_params_.absolutePrestate,
_params_.maxGameDepth,
cfg.faultGameSplitDepth(),
Duration.wrap(uint64(cfg.faultGameClockExtension())),
_params_.maxClockDuration,
_params_.faultVm,
_params_.weth,
IAnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
cfg.l2ChainID()
)
)
)
}) })
) )
); );
......
...@@ -270,19 +270,17 @@ contract DeployDisputeGame is Script { ...@@ -270,19 +270,17 @@ contract DeployDisputeGame is Script {
function deployDisputeGameImpl(DeployDisputeGameInput _dgi, DeployDisputeGameOutput _dgo) internal { function deployDisputeGameImpl(DeployDisputeGameInput _dgi, DeployDisputeGameOutput _dgo) internal {
// Shove the arguments into a struct to avoid stack-too-deep errors. // Shove the arguments into a struct to avoid stack-too-deep errors.
DisputeGameConstructorArgs memory args = DisputeGameConstructorArgs({ IFaultDisputeGame.GameConstructorParams memory args = IFaultDisputeGame.GameConstructorParams({
gameType: GameType.wrap(uint32(_dgi.gameType())), gameType: GameType.wrap(uint32(_dgi.gameType())),
absolutePrestate: Claim.wrap(_dgi.absolutePrestate()), absolutePrestate: Claim.wrap(_dgi.absolutePrestate()),
maxGameDepth: _dgi.maxGameDepth(), maxGameDepth: _dgi.maxGameDepth(),
splitDepth: _dgi.splitDepth(), splitDepth: _dgi.splitDepth(),
clockExtension: Duration.wrap(uint64(_dgi.clockExtension())), clockExtension: Duration.wrap(uint64(_dgi.clockExtension())),
maxClockDuration: Duration.wrap(uint64(_dgi.maxClockDuration())), maxClockDuration: Duration.wrap(uint64(_dgi.maxClockDuration())),
gameVm: IBigStepper(address(_dgi.vmAddress())), vm: IBigStepper(address(_dgi.vmAddress())),
delayedWethProxy: _dgi.delayedWethProxy(), weth: _dgi.delayedWethProxy(),
anchorStateRegistryProxy: _dgi.anchorStateRegistryProxy(), anchorStateRegistry: _dgi.anchorStateRegistryProxy(),
l2ChainId: _dgi.l2ChainId(), l2ChainId: _dgi.l2ChainId()
proposer: _dgi.proposer(),
challenger: _dgi.challenger()
}); });
// PermissionedDisputeGame is used as the type here because it is a superset of // PermissionedDisputeGame is used as the type here because it is a superset of
...@@ -294,23 +292,7 @@ contract DeployDisputeGame is Script { ...@@ -294,23 +292,7 @@ contract DeployDisputeGame is Script {
impl = IPermissionedDisputeGame( impl = IPermissionedDisputeGame(
DeployUtils.create1({ DeployUtils.create1({
_name: "FaultDisputeGame", _name: "FaultDisputeGame",
_args: DeployUtils.encodeConstructor( _args: DeployUtils.encodeConstructor(abi.encodeCall(IFaultDisputeGame.__constructor__, (args)))
abi.encodeCall(
IFaultDisputeGame.__constructor__,
(
args.gameType,
args.absolutePrestate,
args.maxGameDepth,
args.splitDepth,
args.clockExtension,
args.maxClockDuration,
args.gameVm,
args.delayedWethProxy,
args.anchorStateRegistryProxy,
args.l2ChainId
)
)
)
}) })
); );
} else { } else {
...@@ -318,23 +300,7 @@ contract DeployDisputeGame is Script { ...@@ -318,23 +300,7 @@ contract DeployDisputeGame is Script {
DeployUtils.create1({ DeployUtils.create1({
_name: "PermissionedDisputeGame", _name: "PermissionedDisputeGame",
_args: DeployUtils.encodeConstructor( _args: DeployUtils.encodeConstructor(
abi.encodeCall( abi.encodeCall(IPermissionedDisputeGame.__constructor__, (args, _dgi.proposer(), _dgi.challenger()))
IPermissionedDisputeGame.__constructor__,
(
args.gameType,
args.absolutePrestate,
args.maxGameDepth,
args.splitDepth,
args.clockExtension,
args.maxClockDuration,
args.gameVm,
args.delayedWethProxy,
args.anchorStateRegistryProxy,
args.l2ChainId,
args.proposer,
args.challenger
)
)
) )
}) })
); );
......
...@@ -138,16 +138,18 @@ contract DeployUpgrade is Deployer { ...@@ -138,16 +138,18 @@ contract DeployUpgrade is Deployer {
bytes memory constructorInput = abi.encodeCall( bytes memory constructorInput = abi.encodeCall(
IFaultDisputeGame.__constructor__, IFaultDisputeGame.__constructor__,
( (
GameTypes.CANNON, IFaultDisputeGame.GameConstructorParams({
Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate())), gameType: GameTypes.CANNON,
cfg.faultGameMaxDepth(), absolutePrestate: Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate())),
cfg.faultGameSplitDepth(), maxGameDepth: cfg.faultGameMaxDepth(),
Duration.wrap(uint64(cfg.faultGameClockExtension())), splitDepth: cfg.faultGameSplitDepth(),
Duration.wrap(uint64(cfg.faultGameMaxClockDuration())), clockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())),
IBigStepper(mustGetAddress("MIPS")), maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())),
IDelayedWETH(payable(mustGetAddress("DelayedWETHProxyFDG"))), vm: IBigStepper(mustGetAddress("MIPS")),
IAnchorStateRegistry(mustGetAddress("AnchorStateRegistry")), weth: IDelayedWETH(payable(mustGetAddress("DelayedWETHProxyFDG"))),
cfg.l2ChainID() anchorStateRegistry: IAnchorStateRegistry(mustGetAddress("AnchorStateRegistry")),
l2ChainId: cfg.l2ChainID()
})
) )
); );
...@@ -197,16 +199,18 @@ contract DeployUpgrade is Deployer { ...@@ -197,16 +199,18 @@ contract DeployUpgrade is Deployer {
bytes memory constructorInput = abi.encodeCall( bytes memory constructorInput = abi.encodeCall(
IPermissionedDisputeGame.__constructor__, IPermissionedDisputeGame.__constructor__,
( (
GameTypes.PERMISSIONED_CANNON, IFaultDisputeGame.GameConstructorParams({
Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate())), gameType: GameTypes.PERMISSIONED_CANNON,
cfg.faultGameMaxDepth(), absolutePrestate: Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate())),
cfg.faultGameSplitDepth(), maxGameDepth: cfg.faultGameMaxDepth(),
Duration.wrap(uint64(cfg.faultGameClockExtension())), splitDepth: cfg.faultGameSplitDepth(),
Duration.wrap(uint64(cfg.faultGameMaxClockDuration())), clockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())),
IBigStepper(mustGetAddress("MIPS")), maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())),
IDelayedWETH(payable(mustGetAddress("DelayedWETHProxyPDG"))), vm: IBigStepper(mustGetAddress("MIPS")),
IAnchorStateRegistry(mustGetAddress("AnchorStateRegistry")), weth: IDelayedWETH(payable(mustGetAddress("DelayedWETHProxyPDG"))),
cfg.l2ChainID(), anchorStateRegistry: IAnchorStateRegistry(mustGetAddress("AnchorStateRegistry")),
l2ChainId: cfg.l2ChainID()
}),
cfg.l2OutputOracleProposer(), cfg.l2OutputOracleProposer(),
cfg.l2OutputOracleChallenger() cfg.l2OutputOracleChallenger()
) )
......
...@@ -2,54 +2,61 @@ ...@@ -2,54 +2,61 @@
{ {
"inputs": [ "inputs": [
{ {
"internalType": "GameType", "components": [
"name": "_gameType", {
"type": "uint32" "internalType": "GameType",
}, "name": "gameType",
{ "type": "uint32"
"internalType": "Claim", },
"name": "_absolutePrestate", {
"type": "bytes32" "internalType": "Claim",
}, "name": "absolutePrestate",
{ "type": "bytes32"
"internalType": "uint256", },
"name": "_maxGameDepth", {
"type": "uint256" "internalType": "uint256",
}, "name": "maxGameDepth",
{ "type": "uint256"
"internalType": "uint256", },
"name": "_splitDepth", {
"type": "uint256" "internalType": "uint256",
}, "name": "splitDepth",
{ "type": "uint256"
"internalType": "Duration", },
"name": "_clockExtension", {
"type": "uint64" "internalType": "Duration",
}, "name": "clockExtension",
{ "type": "uint64"
"internalType": "Duration", },
"name": "_maxClockDuration", {
"type": "uint64" "internalType": "Duration",
}, "name": "maxClockDuration",
{ "type": "uint64"
"internalType": "contract IBigStepper", },
"name": "_vm", {
"type": "address" "internalType": "contract IBigStepper",
}, "name": "vm",
{ "type": "address"
"internalType": "contract IDelayedWETH", },
"name": "_weth", {
"type": "address" "internalType": "contract IDelayedWETH",
}, "name": "weth",
{ "type": "address"
"internalType": "contract IAnchorStateRegistry", },
"name": "_anchorStateRegistry", {
"type": "address" "internalType": "contract IAnchorStateRegistry",
}, "name": "anchorStateRegistry",
{ "type": "address"
"internalType": "uint256", },
"name": "_l2ChainId", {
"type": "uint256" "internalType": "uint256",
"name": "l2ChainId",
"type": "uint256"
}
],
"internalType": "struct FaultDisputeGame.GameConstructorParams",
"name": "_params",
"type": "tuple"
} }
], ],
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
......
...@@ -2,54 +2,61 @@ ...@@ -2,54 +2,61 @@
{ {
"inputs": [ "inputs": [
{ {
"internalType": "GameType", "components": [
"name": "_gameType", {
"type": "uint32" "internalType": "GameType",
}, "name": "gameType",
{ "type": "uint32"
"internalType": "Claim", },
"name": "_absolutePrestate", {
"type": "bytes32" "internalType": "Claim",
}, "name": "absolutePrestate",
{ "type": "bytes32"
"internalType": "uint256", },
"name": "_maxGameDepth", {
"type": "uint256" "internalType": "uint256",
}, "name": "maxGameDepth",
{ "type": "uint256"
"internalType": "uint256", },
"name": "_splitDepth", {
"type": "uint256" "internalType": "uint256",
}, "name": "splitDepth",
{ "type": "uint256"
"internalType": "Duration", },
"name": "_clockExtension", {
"type": "uint64" "internalType": "Duration",
}, "name": "clockExtension",
{ "type": "uint64"
"internalType": "Duration", },
"name": "_maxClockDuration", {
"type": "uint64" "internalType": "Duration",
}, "name": "maxClockDuration",
{ "type": "uint64"
"internalType": "contract IBigStepper", },
"name": "_vm", {
"type": "address" "internalType": "contract IBigStepper",
}, "name": "vm",
{ "type": "address"
"internalType": "contract IDelayedWETH", },
"name": "_weth", {
"type": "address" "internalType": "contract IDelayedWETH",
}, "name": "weth",
{ "type": "address"
"internalType": "contract IAnchorStateRegistry", },
"name": "_anchorStateRegistry", {
"type": "address" "internalType": "contract IAnchorStateRegistry",
}, "name": "anchorStateRegistry",
{ "type": "address"
"internalType": "uint256", },
"name": "_l2ChainId", {
"type": "uint256" "internalType": "uint256",
"name": "l2ChainId",
"type": "uint256"
}
],
"internalType": "struct FaultDisputeGame.GameConstructorParams",
"name": "_params",
"type": "tuple"
}, },
{ {
"internalType": "address", "internalType": "address",
......
...@@ -164,8 +164,8 @@ ...@@ -164,8 +164,8 @@
"sourceCodeHash": "0x9cb0851b6e471461f2bb369bd72eef4cffe8a0d1345546608a2aa6795540211d" "sourceCodeHash": "0x9cb0851b6e471461f2bb369bd72eef4cffe8a0d1345546608a2aa6795540211d"
}, },
"src/dispute/FaultDisputeGame.sol": { "src/dispute/FaultDisputeGame.sol": {
"initCodeHash": "0xa352179f5055232764aac6b66a3ff5a6b3bfae2101d20c077f714b0ed7e40eef", "initCodeHash": "0x7441e418d3b4229f519c8c027f3fd7a5487206b833110b794cca104a1a2c73fe",
"sourceCodeHash": "0x730eff9147294c115a0a53e7e75771bcc4a517beb48457140ab929a8d1510893" "sourceCodeHash": "0x8f4bf662fe8d56e9aabaa7742033880f0900cd6221c7711c1dbefe985a841104"
}, },
"src/legacy/DeployerWhitelist.sol": { "src/legacy/DeployerWhitelist.sol": {
"initCodeHash": "0xf232863fde5cd65368bcb4a79b41b5a4a09c59ede5070f82fd3f13f681bea7d8", "initCodeHash": "0xf232863fde5cd65368bcb4a79b41b5a4a09c59ede5070f82fd3f13f681bea7d8",
......
...@@ -86,6 +86,21 @@ contract FaultDisputeGame is Clone, ISemver { ...@@ -86,6 +86,21 @@ contract FaultDisputeGame is Clone, ISemver {
address counteredBy; address counteredBy;
} }
/// @notice Parameters for creating a new FaultDisputeGame. We place this into a struct to
/// avoid stack-too-deep errors when compiling without the optimizer enabled.
struct GameConstructorParams {
GameType gameType;
Claim absolutePrestate;
uint256 maxGameDepth;
uint256 splitDepth;
Duration clockExtension;
Duration maxClockDuration;
IBigStepper vm;
IDelayedWETH weth;
IAnchorStateRegistry anchorStateRegistry;
uint256 l2ChainId;
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Events // // Events //
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
...@@ -146,8 +161,8 @@ contract FaultDisputeGame is Clone, ISemver { ...@@ -146,8 +161,8 @@ contract FaultDisputeGame is Clone, ISemver {
uint256 internal constant HEADER_BLOCK_NUMBER_INDEX = 8; uint256 internal constant HEADER_BLOCK_NUMBER_INDEX = 8;
/// @notice Semantic version. /// @notice Semantic version.
/// @custom:semver 1.3.1-beta.7 /// @custom:semver 1.3.1-beta.8
string public constant version = "1.3.1-beta.7"; string public constant version = "1.3.1-beta.8";
/// @notice The starting timestamp of the game /// @notice The starting timestamp of the game
Timestamp public createdAt; Timestamp public createdAt;
...@@ -189,69 +204,52 @@ contract FaultDisputeGame is Clone, ISemver { ...@@ -189,69 +204,52 @@ contract FaultDisputeGame is Clone, ISemver {
/// @notice The latest finalized output root, serving as the anchor for output bisection. /// @notice The latest finalized output root, serving as the anchor for output bisection.
OutputRoot public startingOutputRoot; OutputRoot public startingOutputRoot;
/// @param _gameType The type ID of the game. /// @param _params Parameters for creating a new FaultDisputeGame.
/// @param _absolutePrestate The absolute prestate of the instruction trace. constructor(GameConstructorParams memory _params) {
/// @param _maxGameDepth The maximum depth of bisection.
/// @param _splitDepth The final depth of the output bisection portion of the game.
/// @param _clockExtension The clock extension to perform when the remaining duration is less than the extension.
/// @param _maxClockDuration The maximum amount of time that may accumulate on a team's chess clock.
/// @param _vm An onchain VM that performs single instruction steps on an FPP trace.
/// @param _weth WETH contract for holding ETH.
/// @param _anchorStateRegistry The contract that stores the anchor state for each game type.
/// @param _l2ChainId Chain ID of the L2 network this contract argues about.
constructor(
GameType _gameType,
Claim _absolutePrestate,
uint256 _maxGameDepth,
uint256 _splitDepth,
Duration _clockExtension,
Duration _maxClockDuration,
IBigStepper _vm,
IDelayedWETH _weth,
IAnchorStateRegistry _anchorStateRegistry,
uint256 _l2ChainId
) {
// The max game depth may not be greater than `LibPosition.MAX_POSITION_BITLEN - 1`. // The max game depth may not be greater than `LibPosition.MAX_POSITION_BITLEN - 1`.
if (_maxGameDepth > LibPosition.MAX_POSITION_BITLEN - 1) revert MaxDepthTooLarge(); if (_params.maxGameDepth > LibPosition.MAX_POSITION_BITLEN - 1) revert MaxDepthTooLarge();
// The split depth plus one cannot be greater than or equal to the max game depth. We add // The split depth plus one cannot be greater than or equal to the max game depth. We add
// an additional depth to the split depth to avoid a bug in trace ancestor lookup. We know // an additional depth to the split depth to avoid a bug in trace ancestor lookup. We know
// that the case where the split depth is the max value for uint256 is equivalent to the // that the case where the split depth is the max value for uint256 is equivalent to the
// second check though we do need to check it explicitly to avoid an overflow. // second check though we do need to check it explicitly to avoid an overflow.
if (_splitDepth == type(uint256).max || _splitDepth + 1 >= _maxGameDepth) revert InvalidSplitDepth(); if (_params.splitDepth == type(uint256).max || _params.splitDepth + 1 >= _params.maxGameDepth) {
revert InvalidSplitDepth();
}
// The split depth cannot be 0 or 1 to stay in bounds of clock extension arithmetic. // The split depth cannot be 0 or 1 to stay in bounds of clock extension arithmetic.
if (_splitDepth < 2) revert InvalidSplitDepth(); if (_params.splitDepth < 2) revert InvalidSplitDepth();
// The PreimageOracle challenge period must fit into uint64 so we can safely use it here. // The PreimageOracle challenge period must fit into uint64 so we can safely use it here.
// Runtime check was added instead of changing the ABI since the contract is already // Runtime check was added instead of changing the ABI since the contract is already
// deployed in production. We perform the same check within the PreimageOracle for the // deployed in production. We perform the same check within the PreimageOracle for the
// benefit of developers but also perform this check here defensively. // benefit of developers but also perform this check here defensively.
if (_vm.oracle().challengePeriod() > type(uint64).max) revert InvalidChallengePeriod(); if (_params.vm.oracle().challengePeriod() > type(uint64).max) revert InvalidChallengePeriod();
// Determine the maximum clock extension which is either the split depth extension or the // Determine the maximum clock extension which is either the split depth extension or the
// maximum game depth extension depending on the configuration of these contracts. // maximum game depth extension depending on the configuration of these contracts.
uint256 splitDepthExtension = uint256(_clockExtension.raw()) * 2; uint256 splitDepthExtension = uint256(_params.clockExtension.raw()) * 2;
uint256 maxGameDepthExtension = uint256(_clockExtension.raw()) + uint256(_vm.oracle().challengePeriod()); uint256 maxGameDepthExtension =
uint256(_params.clockExtension.raw()) + uint256(_params.vm.oracle().challengePeriod());
uint256 maxClockExtension = Math.max(splitDepthExtension, maxGameDepthExtension); uint256 maxClockExtension = Math.max(splitDepthExtension, maxGameDepthExtension);
// The maximum clock extension must fit into a uint64. // The maximum clock extension must fit into a uint64.
if (maxClockExtension > type(uint64).max) revert InvalidClockExtension(); if (maxClockExtension > type(uint64).max) revert InvalidClockExtension();
// The maximum clock extension may not be greater than the maximum clock duration. // The maximum clock extension may not be greater than the maximum clock duration.
if (uint64(maxClockExtension) > _maxClockDuration.raw()) revert InvalidClockExtension(); if (uint64(maxClockExtension) > _params.maxClockDuration.raw()) revert InvalidClockExtension();
// Set up initial game state. // Set up initial game state.
GAME_TYPE = _gameType; GAME_TYPE = _params.gameType;
ABSOLUTE_PRESTATE = _absolutePrestate; ABSOLUTE_PRESTATE = _params.absolutePrestate;
MAX_GAME_DEPTH = _maxGameDepth; MAX_GAME_DEPTH = _params.maxGameDepth;
SPLIT_DEPTH = _splitDepth; SPLIT_DEPTH = _params.splitDepth;
CLOCK_EXTENSION = _clockExtension; CLOCK_EXTENSION = _params.clockExtension;
MAX_CLOCK_DURATION = _maxClockDuration; MAX_CLOCK_DURATION = _params.maxClockDuration;
VM = _vm; VM = _params.vm;
WETH = _weth; WETH = _params.weth;
ANCHOR_STATE_REGISTRY = _anchorStateRegistry; ANCHOR_STATE_REGISTRY = _params.anchorStateRegistry;
L2_CHAIN_ID = _l2ChainId; L2_CHAIN_ID = _params.l2ChainId;
} }
/// @notice Initializes the contract. /// @notice Initializes the contract.
......
...@@ -5,14 +5,9 @@ pragma solidity 0.8.15; ...@@ -5,14 +5,9 @@ pragma solidity 0.8.15;
import { FaultDisputeGame } from "src/dispute/FaultDisputeGame.sol"; import { FaultDisputeGame } from "src/dispute/FaultDisputeGame.sol";
// Libraries // Libraries
import { GameType, Claim, Duration } from "src/dispute/lib/Types.sol"; import { Claim } from "src/dispute/lib/Types.sol";
import { BadAuth } from "src/dispute/lib/Errors.sol"; import { BadAuth } from "src/dispute/lib/Errors.sol";
// Interfaces
import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol";
import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol";
import { IBigStepper } from "src/dispute/interfaces/IBigStepper.sol";
/// @title PermissionedDisputeGame /// @title PermissionedDisputeGame
/// @notice PermissionedDisputeGame is a contract that inherits from `FaultDisputeGame`, and contains two roles: /// @notice PermissionedDisputeGame is a contract that inherits from `FaultDisputeGame`, and contains two roles:
/// - The `challenger` role, which is allowed to challenge a dispute. /// - The `challenger` role, which is allowed to challenge a dispute.
...@@ -36,44 +31,15 @@ contract PermissionedDisputeGame is FaultDisputeGame { ...@@ -36,44 +31,15 @@ contract PermissionedDisputeGame is FaultDisputeGame {
_; _;
} }
/// @param _gameType The type ID of the game. /// @param _params Parameters for creating a new FaultDisputeGame.
/// @param _absolutePrestate The absolute prestate of the instruction trace.
/// @param _maxGameDepth The maximum depth of bisection.
/// @param _splitDepth The final depth of the output bisection portion of the game.
/// @param _clockExtension The clock extension to perform when the remaining duration is less than the extension.
/// @param _maxClockDuration The maximum amount of time that may accumulate on a team's chess clock.
/// @param _vm An onchain VM that performs single instruction steps on an FPP trace.
/// @param _weth WETH contract for holding ETH.
/// @param _anchorStateRegistry The contract that stores the anchor state for each game type.
/// @param _l2ChainId Chain ID of the L2 network this contract argues about.
/// @param _proposer Address that is allowed to create instances of this contract. /// @param _proposer Address that is allowed to create instances of this contract.
/// @param _challenger Address that is allowed to challenge instances of this contract. /// @param _challenger Address that is allowed to challenge instances of this contract.
constructor( constructor(
GameType _gameType, GameConstructorParams memory _params,
Claim _absolutePrestate,
uint256 _maxGameDepth,
uint256 _splitDepth,
Duration _clockExtension,
Duration _maxClockDuration,
IBigStepper _vm,
IDelayedWETH _weth,
IAnchorStateRegistry _anchorStateRegistry,
uint256 _l2ChainId,
address _proposer, address _proposer,
address _challenger address _challenger
) )
FaultDisputeGame( FaultDisputeGame(_params)
_gameType,
_absolutePrestate,
_maxGameDepth,
_splitDepth,
_clockExtension,
_maxClockDuration,
_vm,
_weth,
_anchorStateRegistry,
_l2ChainId
)
{ {
PROPOSER = _proposer; PROPOSER = _proposer;
CHALLENGER = _challenger; CHALLENGER = _challenger;
......
...@@ -26,6 +26,19 @@ interface IFaultDisputeGame is IDisputeGame { ...@@ -26,6 +26,19 @@ interface IFaultDisputeGame is IDisputeGame {
address counteredBy; address counteredBy;
} }
struct GameConstructorParams {
GameType gameType;
Claim absolutePrestate;
uint256 maxGameDepth;
uint256 splitDepth;
Duration clockExtension;
Duration maxClockDuration;
IBigStepper vm;
IDelayedWETH weth;
IAnchorStateRegistry anchorStateRegistry;
uint256 l2ChainId;
}
error AlreadyInitialized(); error AlreadyInitialized();
error AnchorRootNotFound(); error AnchorRootNotFound();
error BlockNumberMatches(); error BlockNumberMatches();
...@@ -113,17 +126,5 @@ interface IFaultDisputeGame is IDisputeGame { ...@@ -113,17 +126,5 @@ interface IFaultDisputeGame is IDisputeGame {
function vm() external view returns (IBigStepper vm_); function vm() external view returns (IBigStepper vm_);
function weth() external view returns (IDelayedWETH weth_); function weth() external view returns (IDelayedWETH weth_);
function __constructor__( function __constructor__(GameConstructorParams memory _params) external;
GameType _gameType,
Claim _absolutePrestate,
uint256 _maxGameDepth,
uint256 _splitDepth,
Duration _clockExtension,
Duration _maxClockDuration,
IBigStepper _vm,
IDelayedWETH _weth,
IAnchorStateRegistry _anchorStateRegistry,
uint256 _l2ChainId
)
external;
} }
...@@ -2,12 +2,13 @@ ...@@ -2,12 +2,13 @@
pragma solidity ^0.8.0; pragma solidity ^0.8.0;
import { Types } from "src/libraries/Types.sol"; import { Types } from "src/libraries/Types.sol";
import { GameType, Claim, Position, Clock, Hash, Duration } from "src/dispute/lib/Types.sol"; import { Claim, Position, Clock, Hash, Duration } from "src/dispute/lib/Types.sol";
import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol"; import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol";
import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol"; import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol";
import { IBigStepper } from "src/dispute/interfaces/IBigStepper.sol"; import { IBigStepper } from "src/dispute/interfaces/IBigStepper.sol";
import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol"; import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol";
import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol";
interface IPermissionedDisputeGame is IDisputeGame { interface IPermissionedDisputeGame is IDisputeGame {
struct ClaimData { struct ClaimData {
...@@ -120,16 +121,7 @@ interface IPermissionedDisputeGame is IDisputeGame { ...@@ -120,16 +121,7 @@ interface IPermissionedDisputeGame is IDisputeGame {
function challenger() external view returns (address challenger_); function challenger() external view returns (address challenger_);
function __constructor__( function __constructor__(
GameType _gameType, IFaultDisputeGame.GameConstructorParams memory _params,
Claim _absolutePrestate,
uint256 _maxGameDepth,
uint256 _splitDepth,
Duration _clockExtension,
Duration _maxClockDuration,
IBigStepper _vm,
IDelayedWETH _weth,
IAnchorStateRegistry _anchorStateRegistry,
uint256 _l2ChainId,
address _proposer, address _proposer,
address _challenger address _challenger
) )
......
...@@ -73,16 +73,18 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init { ...@@ -73,16 +73,18 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init {
abi.encodeCall( abi.encodeCall(
IFaultDisputeGame.__constructor__, IFaultDisputeGame.__constructor__,
( (
GAME_TYPE, IFaultDisputeGame.GameConstructorParams({
absolutePrestate, gameType: GAME_TYPE,
2 ** 3, absolutePrestate: absolutePrestate,
2 ** 2, maxGameDepth: 2 ** 3,
Duration.wrap(3 hours), splitDepth: 2 ** 2,
Duration.wrap(3.5 days), clockExtension: Duration.wrap(3 hours),
_vm, maxClockDuration: Duration.wrap(3.5 days),
delayedWeth, vm: _vm,
anchorStateRegistry, weth: delayedWeth,
10 anchorStateRegistry: anchorStateRegistry,
l2ChainId: 10
})
) )
) )
) )
...@@ -154,16 +156,18 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init { ...@@ -154,16 +156,18 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
abi.encodeCall( abi.encodeCall(
IFaultDisputeGame.__constructor__, IFaultDisputeGame.__constructor__,
( (
GAME_TYPE, IFaultDisputeGame.GameConstructorParams({
absolutePrestate, gameType: GAME_TYPE,
_maxGameDepth, absolutePrestate: absolutePrestate,
_maxGameDepth + 1, maxGameDepth: _maxGameDepth,
Duration.wrap(3 hours), splitDepth: _maxGameDepth + 1,
Duration.wrap(3.5 days), clockExtension: Duration.wrap(3 hours),
alphabetVM, maxClockDuration: Duration.wrap(3.5 days),
IDelayedWETH(payable(address(0))), vm: alphabetVM,
IAnchorStateRegistry(address(0)), weth: IDelayedWETH(payable(address(0))),
10 anchorStateRegistry: IAnchorStateRegistry(address(0)),
l2ChainId: 10
})
) )
) )
) )
...@@ -196,16 +200,18 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init { ...@@ -196,16 +200,18 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
abi.encodeCall( abi.encodeCall(
IFaultDisputeGame.__constructor__, IFaultDisputeGame.__constructor__,
( (
GAME_TYPE, IFaultDisputeGame.GameConstructorParams({
absolutePrestate, gameType: GAME_TYPE,
2 ** 3, absolutePrestate: absolutePrestate,
2 ** 2, maxGameDepth: 2 ** 3,
Duration.wrap(3 hours), splitDepth: 2 ** 2,
Duration.wrap(3.5 days), clockExtension: Duration.wrap(3 hours),
alphabetVM, maxClockDuration: Duration.wrap(3.5 days),
IDelayedWETH(payable(address(0))), vm: alphabetVM,
IAnchorStateRegistry(address(0)), weth: IDelayedWETH(payable(address(0))),
10 anchorStateRegistry: IAnchorStateRegistry(address(0)),
l2ChainId: 10
})
) )
) )
) )
...@@ -234,16 +240,18 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init { ...@@ -234,16 +240,18 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
abi.encodeCall( abi.encodeCall(
IFaultDisputeGame.__constructor__, IFaultDisputeGame.__constructor__,
( (
GAME_TYPE, IFaultDisputeGame.GameConstructorParams({
absolutePrestate, gameType: GAME_TYPE,
maxGameDepth, absolutePrestate: absolutePrestate,
_splitDepth, maxGameDepth: maxGameDepth,
Duration.wrap(3 hours), splitDepth: _splitDepth,
Duration.wrap(3.5 days), clockExtension: Duration.wrap(3 hours),
alphabetVM, maxClockDuration: Duration.wrap(3.5 days),
IDelayedWETH(payable(address(0))), vm: alphabetVM,
IAnchorStateRegistry(address(0)), weth: IDelayedWETH(payable(address(0))),
10 anchorStateRegistry: IAnchorStateRegistry(address(0)),
l2ChainId: 10
})
) )
) )
) )
...@@ -272,16 +280,18 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init { ...@@ -272,16 +280,18 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
abi.encodeCall( abi.encodeCall(
IFaultDisputeGame.__constructor__, IFaultDisputeGame.__constructor__,
( (
GAME_TYPE, IFaultDisputeGame.GameConstructorParams({
absolutePrestate, gameType: GAME_TYPE,
2 ** 3, absolutePrestate: absolutePrestate,
_splitDepth, maxGameDepth: 2 ** 3,
Duration.wrap(3 hours), splitDepth: _splitDepth,
Duration.wrap(3.5 days), clockExtension: Duration.wrap(3 hours),
alphabetVM, maxClockDuration: Duration.wrap(3.5 days),
IDelayedWETH(payable(address(0))), vm: alphabetVM,
IAnchorStateRegistry(address(0)), weth: IDelayedWETH(payable(address(0))),
10 anchorStateRegistry: IAnchorStateRegistry(address(0)),
l2ChainId: 10
})
) )
) )
) )
...@@ -318,16 +328,18 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init { ...@@ -318,16 +328,18 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
abi.encodeCall( abi.encodeCall(
IFaultDisputeGame.__constructor__, IFaultDisputeGame.__constructor__,
( (
GAME_TYPE, IFaultDisputeGame.GameConstructorParams({
absolutePrestate, gameType: GAME_TYPE,
16, absolutePrestate: absolutePrestate,
8, maxGameDepth: 16,
Duration.wrap(_clockExtension), splitDepth: 8,
Duration.wrap(_maxClockDuration), clockExtension: Duration.wrap(_clockExtension),
alphabetVM, maxClockDuration: Duration.wrap(_maxClockDuration),
IDelayedWETH(payable(address(0))), vm: alphabetVM,
IAnchorStateRegistry(address(0)), weth: IDelayedWETH(payable(address(0))),
10 anchorStateRegistry: IAnchorStateRegistry(address(0)),
l2ChainId: 10
})
) )
) )
) )
......
...@@ -17,6 +17,7 @@ import "src/dispute/lib/Errors.sol"; ...@@ -17,6 +17,7 @@ import "src/dispute/lib/Errors.sol";
import { IPreimageOracle } from "src/dispute/interfaces/IBigStepper.sol"; import { IPreimageOracle } from "src/dispute/interfaces/IBigStepper.sol";
import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol"; import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol";
import { IPermissionedDisputeGame } from "src/dispute/interfaces/IPermissionedDisputeGame.sol"; import { IPermissionedDisputeGame } from "src/dispute/interfaces/IPermissionedDisputeGame.sol";
import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol";
contract PermissionedDisputeGame_Init is DisputeGameFactory_Init { contract PermissionedDisputeGame_Init is DisputeGameFactory_Init {
/// @dev The type of the game being tested. /// @dev The type of the game being tested.
...@@ -67,16 +68,18 @@ contract PermissionedDisputeGame_Init is DisputeGameFactory_Init { ...@@ -67,16 +68,18 @@ contract PermissionedDisputeGame_Init is DisputeGameFactory_Init {
abi.encodeCall( abi.encodeCall(
IPermissionedDisputeGame.__constructor__, IPermissionedDisputeGame.__constructor__,
( (
GAME_TYPE, IFaultDisputeGame.GameConstructorParams({
absolutePrestate, gameType: GAME_TYPE,
2 ** 3, absolutePrestate: absolutePrestate,
2 ** 2, maxGameDepth: 2 ** 3,
Duration.wrap(3 hours), splitDepth: 2 ** 2,
Duration.wrap(3.5 days), clockExtension: Duration.wrap(3 hours),
_vm, maxClockDuration: Duration.wrap(3.5 days),
_weth, vm: _vm,
anchorStateRegistry, weth: _weth,
10, anchorStateRegistry: anchorStateRegistry,
l2ChainId: 10
}),
PROPOSER, PROPOSER,
CHALLENGER CHALLENGER
) )
......
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