Commit ff136e1f authored by smartcontracts's avatar smartcontracts Committed by Adrian Sutton

fix: correct clock extension for step (#258)

When the FDG is about to execute a step, we must add an additional
clock extension equal to the PreimageOracle challenge period. This
gives the PreimageOracle time to elapse.
parent b945bcf0
......@@ -148,8 +148,8 @@
"sourceCodeHash": "0x115bd6a4c4d77ed210dfd468675b409fdae9f79b932063c138f0765ba9063462"
},
"src/cannon/PreimageOracle.sol": {
"initCodeHash": "0x3b89440c73c7da079257f38a9da237fef199755c0e31578889ebd55e3f963aef",
"sourceCodeHash": "0x6889891526f82ec0c68561ac0803da0ee995f737844ad2b7acfdac0b41ff789e"
"initCodeHash": "0x967d730bb1b10a36ee625179734cccd6b6826ce480bad0419272663c460603bd",
"sourceCodeHash": "0xb1f0d6f26c2e6a2c3b635eaf8f327e91a8d22ef7479b1ebb93427b88f73ed163"
},
"src/dispute/AnchorStateRegistry.sol": {
"initCodeHash": "0x0305c21e50829b9e07d43358d8c2c82f1449534c90d4391400d46e76d0503a49",
......@@ -160,8 +160,8 @@
"sourceCodeHash": "0x918c395ac5d77357f2551616aad0613e68893862edd14e554623eb16ee6ba148"
},
"src/dispute/FaultDisputeGame.sol": {
"initCodeHash": "0x8a5b0a63aa89d54bfdfee0520c7d93d148dcf1bfaefd0649d070492cf1b40327",
"sourceCodeHash": "0x8412814c752106251edf5d96881c8e00b1962b406ef2920837e9b4a1209a408b"
"initCodeHash": "0xe0b6dae6078d1e7237240ab3c589055190ff4a4bb16280dcbf3919e062ad8f84",
"sourceCodeHash": "0xea69f63d4df701e9dfb73b85692c9a62b8a5819b3f473889c9da3734131b9738"
},
"src/dispute/weth/DelayedWETH.sol": {
"initCodeHash": "0x8f9a5b50374331ad2fabe03a7ce28a0012bfaca5fa48ee917339c3eec39a319f",
......
......@@ -963,6 +963,11 @@
"name": "IncorrectBondAmount",
"type": "error"
},
{
"inputs": [],
"name": "InvalidChallengePeriod",
"type": "error"
},
{
"inputs": [],
"name": "InvalidClockExtension",
......
......@@ -1004,6 +1004,11 @@
"name": "IncorrectBondAmount",
"type": "error"
},
{
"inputs": [],
"name": "InvalidChallengePeriod",
"type": "error"
},
{
"inputs": [],
"name": "InvalidClockExtension",
......
......@@ -92,6 +92,11 @@ contract PreimageOracle is IPreimageOracle, ISemver {
MIN_LPP_SIZE_BYTES = _minProposalSize;
CHALLENGE_PERIOD = _challengePeriod;
// Make sure challenge period fits within uint64 so that it can safely be used within the
// FaultDisputeGame contract to compute clock extensions. Adding this check is simpler than
// changing the existing contract ABI.
require(_challengePeriod <= type(uint64).max, "challenge period too large");
// Compute hashes in empty sparse Merkle tree. The first hash is not set, and kept as zero as the identity.
for (uint256 height = 0; height < KECCAK_TREE_DEPTH - 1; height++) {
zeroHashes[height + 1] = keccak256(abi.encodePacked(zeroHashes[height], zeroHashes[height]));
......
......@@ -4,6 +4,10 @@ pragma solidity 0.8.15;
/// @title IPreimageOracle
/// @notice Interface for a preimage oracle.
interface IPreimageOracle {
/// @notice Returns the length of the large preimage proposal challenge period.
/// @return challengePeriod_ The length of the challenge period in seconds.
function challengePeriod() external view returns (uint256 challengePeriod_);
/// @notice Reads a preimage from the oracle.
/// @param _key The key of the preimage to read.
/// @param _offset The offset of the preimage to read.
......
......@@ -2,6 +2,7 @@
pragma solidity 0.8.15;
import { FixedPointMathLib } from "@solady/utils/FixedPointMathLib.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol";
import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol";
......@@ -146,11 +147,23 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
// The split depth cannot be 0 or 1 to stay in bounds of clock extension arithmetic.
if (_splitDepth < 2) revert InvalidSplitDepth();
// The clock extension may not be greater than the max clock duration.
if (_clockExtension.raw() > _maxClockDuration.raw()) revert InvalidClockExtension();
// 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
// deployed in production. We perform the same check within the PreimageOracle for the
// benefit of developers but also perform this check here defensively.
if (_vm.oracle().challengePeriod() > type(uint64).max) revert InvalidChallengePeriod();
// The worst-case clock extension may not be greater than the max clock duration.
if (_clockExtension.raw() * 2 > _maxClockDuration.raw()) revert InvalidClockExtension();
// 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.
uint256 splitDepthExtension = uint256(_clockExtension.raw()) * 2;
uint256 maxGameDepthExtension = uint256(_clockExtension.raw()) + uint256(_vm.oracle().challengePeriod());
uint256 maxClockExtension = Math.max(splitDepthExtension, maxGameDepthExtension);
// The maximum clock extension must fit into a uint64.
if (maxClockExtension > type(uint64).max) revert InvalidClockExtension();
// The maximum clock extension may not be greater than the maximum clock duration.
if (uint64(maxClockExtension) > _maxClockDuration.raw()) revert InvalidClockExtension();
// Set up initial game state.
GAME_TYPE = _gameType;
......@@ -380,17 +393,29 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
// seconds of time.
if (nextDuration.raw() == MAX_CLOCK_DURATION.raw()) revert ClockTimeExceeded();
// If the remaining clock time has less than `CLOCK_EXTENSION` seconds remaining, grant the potential
// grandchild's clock `CLOCK_EXTENSION` seconds. This is to ensure that, even if a player has to inherit another
// team's clock to counter a freeloader claim, they will always have enough time to respond. This extension
// is bounded by the depth of the tree. If the potential grandchild is an execution trace bisection root, the
// clock extension is doubled. This is to allow for extra time for the off-chain challenge agent to generate
// the initial instruction trace on the native FPVM.
if (nextDuration.raw() > MAX_CLOCK_DURATION.raw() - CLOCK_EXTENSION.raw()) {
// If the potential grandchild is an execution trace bisection root, double the clock extension.
uint64 extensionPeriod =
nextPositionDepth == SPLIT_DEPTH - 1 ? CLOCK_EXTENSION.raw() * 2 : CLOCK_EXTENSION.raw();
nextDuration = Duration.wrap(MAX_CLOCK_DURATION.raw() - extensionPeriod);
// Clock extension is a mechanism that automatically extends the clock for a potential
// grandchild claim when there would be less than the clock extension time left if a player
// is forced to inherit another team's clock when countering a freeloader claim. Exact
// amount of clock extension time depends exactly where we are within the game.
uint64 actualExtension;
if (nextPositionDepth == MAX_GAME_DEPTH - 1) {
// If the next position is `MAX_GAME_DEPTH - 1` then we're about to execute a step. Our
// clock extension must therefore account for the LPP challenge period in addition to
// the standard clock extension.
actualExtension = CLOCK_EXTENSION.raw() + uint64(VM.oracle().challengePeriod());
} else if (nextPositionDepth == SPLIT_DEPTH - 1) {
// If the next position is `SPLIT_DEPTH - 1` then we're about to begin an execution
// trace bisection and we need to give extra time for the off-chain challenge agent to
// be able to generate the initial instruction trace on the native FPVM.
actualExtension = CLOCK_EXTENSION.raw() * 2;
} else {
// Otherwise, we just use the standard clock extension.
actualExtension = CLOCK_EXTENSION.raw();
}
// Check if we need to apply the clock extension.
if (nextDuration.raw() > MAX_CLOCK_DURATION.raw() - actualExtension) {
nextDuration = Duration.wrap(MAX_CLOCK_DURATION.raw() - actualExtension);
}
// Construct the next clock with the new duration and the current block timestamp.
......
......@@ -94,6 +94,9 @@ error InvalidSplitDepth();
/// @notice Thrown on deployment if the max clock duration is less than or equal to the clock extension.
error InvalidClockExtension();
/// @notice Thrown on deployment if the PreimageOracle challenge period is too high.
error InvalidChallengePeriod();
/// @notice Thrown on deployment if the max depth is greater than `LibPosition.`
error MaxDepthTooLarge();
......
......@@ -20,6 +20,14 @@ contract PreimageOracle_Test is Test {
vm.label(address(oracle), "PreimageOracle");
}
/// @notice Tests that the challenge period cannot be made too large.
/// @param _challengePeriod The challenge period to test.
function testFuzz_constructor_challengePeriodTooLarge_reverts(uint256 _challengePeriod) public {
_challengePeriod = bound(_challengePeriod, uint256(type(uint64).max) + 1, type(uint256).max);
vm.expectRevert("challenge period too large");
new PreimageOracle(0, _challengePeriod);
}
/// @notice Test the pre-image key computation with a known pre-image.
function test_keccak256PreimageKey_succeeds() public pure {
bytes memory preimage = hex"deadbeef";
......
......@@ -27,13 +27,13 @@ contract DeploymentSummary is DeploymentSummaryCode {
address internal constant l1StandardBridgeProxyAddress = 0x20A42a5a785622c6Ba2576B2D6e924aA82BFA11D;
address internal constant l2OutputOracleAddress = 0x19652082F846171168Daf378C4fD3ee85a0D4A60;
address internal constant l2OutputOracleProxyAddress = 0x39Af23E00F1e662025aA01b0cEdA19542B78DF99;
address internal constant mipsAddress = 0x96A4FAe2Ef523cecC7E4a202Cdc1D5FD25f76484;
address internal constant mipsAddress = 0xcFf3d2300Bf09462BBA3D23EF284a5C60Ef7c187;
address internal constant optimismMintableERC20FactoryAddress = 0x39Aea2Dd53f2d01c15877aCc2791af6BDD7aD567;
address internal constant optimismMintableERC20FactoryProxyAddress = 0xc7B87b2b892EA5C3CfF47168881FE168C00377FB;
address internal constant optimismPortalAddress = 0xbdD90485FCbcac869D5b5752179815a3103d8131;
address internal constant optimismPortal2Address = 0xae5DadFc48928543f706a9E6Ce25c682aaD2b63b;
address internal constant optimismPortalProxyAddress = 0x1c23A6d89F95ef3148BCDA8E242cAb145bf9c0E4;
address internal constant preimageOracleAddress = 0xC8B5749cEFfbC5F70E7C48f9a464883289574D99;
address internal constant preimageOracleAddress = 0x5A996D7C1b5De7C21121F06D99ADFa088d4b779e;
address internal constant protocolVersionsAddress = 0xfbfD64a6C0257F613feFCe050Aa30ecC3E3d7C3F;
address internal constant protocolVersionsProxyAddress = 0x4C52a6277b1B84121b3072C0c92b6Be0b7CC10F1;
address internal constant proxyAdminAddress = 0x62c20Aa1e0272312BC100b4e23B4DC1Ed96dD7D1;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -27,13 +27,13 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode {
address internal constant l1StandardBridgeProxyAddress = 0x20A42a5a785622c6Ba2576B2D6e924aA82BFA11D;
address internal constant l2OutputOracleAddress = 0x19652082F846171168Daf378C4fD3ee85a0D4A60;
address internal constant l2OutputOracleProxyAddress = 0x39Af23E00F1e662025aA01b0cEdA19542B78DF99;
address internal constant mipsAddress = 0x96A4FAe2Ef523cecC7E4a202Cdc1D5FD25f76484;
address internal constant mipsAddress = 0xcFf3d2300Bf09462BBA3D23EF284a5C60Ef7c187;
address internal constant optimismMintableERC20FactoryAddress = 0x39Aea2Dd53f2d01c15877aCc2791af6BDD7aD567;
address internal constant optimismMintableERC20FactoryProxyAddress = 0xc7B87b2b892EA5C3CfF47168881FE168C00377FB;
address internal constant optimismPortalAddress = 0xbdD90485FCbcac869D5b5752179815a3103d8131;
address internal constant optimismPortal2Address = 0xae5DadFc48928543f706a9E6Ce25c682aaD2b63b;
address internal constant optimismPortalProxyAddress = 0x1c23A6d89F95ef3148BCDA8E242cAb145bf9c0E4;
address internal constant preimageOracleAddress = 0xC8B5749cEFfbC5F70E7C48f9a464883289574D99;
address internal constant preimageOracleAddress = 0x5A996D7C1b5De7C21121F06D99ADFa088d4b779e;
address internal constant protocolVersionsAddress = 0xfbfD64a6C0257F613feFCe050Aa30ecC3E3d7C3F;
address internal constant protocolVersionsProxyAddress = 0x4C52a6277b1B84121b3072C0c92b6Be0b7CC10F1;
address internal constant proxyAdminAddress = 0x62c20Aa1e0272312BC100b4e23B4DC1Ed96dD7D1;
......
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