Commit 399cf71f authored by clabby's avatar clabby Committed by GitHub

feat(ctb): Respected game type updated timestamp (#9465)

* init

* Add check for respected type updated timestamp
parent 0783222c
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -32,8 +32,8 @@
"sourceCodeHash": "0xdc27421279afb6c3b26fc8c589c5d213695f666c74d2c2c41cb7df719d172f37"
},
"src/L1/OptimismPortal2.sol": {
"initCodeHash": "0x3c081d9769220a8b4a7538830905be3ebb058d0c01312bdbd9feae7f707a2866",
"sourceCodeHash": "0xc853bb1763d0b6b2008ebfa14148cd0840691f412873fed4ac7d203b7c69e7a7"
"initCodeHash": "0xcb81890a6a3caa9f759be0fa97cd7ea7243564c31a3ebafe9528878eb02670bc",
"sourceCodeHash": "0x9a700ba456d9f8cc338fc755ae99c46ef264a95cf63915d185ba6890c81b4b59"
},
"src/L1/ProtocolVersions.sol": {
"initCodeHash": "0x72cd467e8bcf019c02675d72ab762e088bcc9cc0f1a4e9f587fa4589f7fdd1b8",
......
......@@ -474,6 +474,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "respectedGameTypeUpdatedAt",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
......
......@@ -103,5 +103,12 @@
"offset": 0,
"slot": "59",
"type": "GameType"
},
{
"bytes": "8",
"label": "respectedGameTypeUpdatedAt",
"offset": 4,
"slot": "59",
"type": "uint64"
}
]
\ No newline at end of file
......@@ -87,6 +87,9 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ISemver {
/// @notice The game type that the OptimismPortal consults for output proposals.
GameType public respectedGameType;
/// @notice The timestamp at which the respected game type was last updated.
uint64 public respectedGameTypeUpdatedAt;
/// @notice Emitted when a transaction is deposited from L1 to L2.
/// The parameters of this event are read by the rollup node and used to derive deposit
/// transactions on L2.
......@@ -114,8 +117,8 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ISemver {
}
/// @notice Semantic version.
/// @custom:semver 3.0.0
string public constant version = "3.0.0";
/// @custom:semver 3.1.0
string public constant version = "3.1.0";
/// @notice Constructs the OptimismPortal contract.
constructor(
......@@ -428,6 +431,7 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ISemver {
function setRespectedGameType(GameType _gameType) external {
require(msg.sender == guardian(), "OptimismPortal: only the guardian can set the respected game type");
respectedGameType = _gameType;
respectedGameTypeUpdatedAt = uint64(block.timestamp);
}
/// @notice Checks if a withdrawal can be finalized. This function will revert if the withdrawal cannot be
......@@ -445,11 +449,13 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ISemver {
// a timestamp of zero.
require(provenWithdrawal.timestamp != 0, "OptimismPortal: withdrawal has not been proven yet");
uint64 createdAt = disputeGameProxy.createdAt().raw();
// As a sanity check, we make sure that the proven withdrawal's timestamp is greater than
// starting timestamp inside the Dispute Game. Not strictly necessary but extra layer of
// safety against weird bugs in the proving step.
require(
provenWithdrawal.timestamp > disputeGameProxy.createdAt().raw(),
provenWithdrawal.timestamp > createdAt,
"OptimismPortal: withdrawal timestamp less than dispute game creation timestamp"
);
......@@ -472,6 +478,13 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ISemver {
// the withdrawal was proven.
require(disputeGameProxy.gameType().raw() == respectedGameType.raw(), "OptimismPortal: invalid game type");
// The game must have been created after `respectedGameTypeUpdatedAt`. This is to prevent users from creating
// invalid disputes against a deployed game type while the off-chain challenge agents are not watching.
require(
createdAt >= respectedGameTypeUpdatedAt,
"OptimismPortal: dispute game created before respected game type was updated"
);
// Before a withdrawal can be finalized, the dispute game it was proven against must have been
// resolved for at least `DISPUTE_GAME_FINALITY_DELAY_SECONDS`. This is to allow for manual
// intervention in the event that a dispute game is resolved incorrectly.
......
......@@ -1029,6 +1029,36 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
optimismPortal2.finalizeWithdrawalTransaction(_defaultTx);
}
/// @dev Tests that `finalizeWithdrawalTransaction` reverts if the respected game type was updated after the
/// dispute game was created.
function test_finalizeWithdrawalTransaction_gameOlderThanRespectedGameTypeUpdate_reverts() external {
vm.expectEmit(true, true, true, true);
emit WithdrawalProven(_withdrawalHash, alice, bob);
optimismPortal2.proveWithdrawalTransaction({
_tx: _defaultTx,
_disputeGameIndex: _proposedGameIndex,
_outputRootProof: _outputRootProof,
_withdrawalProof: _withdrawalProof
});
// Warp past the finalization period.
vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1);
// Resolve the dispute game.
game.resolveClaim(0);
game.resolve();
// Change the respected game type in the portal.
vm.prank(optimismPortal2.guardian());
optimismPortal2.setRespectedGameType(GameType.wrap(0xFF));
// Mock the game's type so that we pass the correct game type check.
vm.mockCall(address(game), abi.encodeCall(game.gameType, ()), abi.encode(GameType.wrap(0xFF)));
vm.expectRevert("OptimismPortal: dispute game created before respected game type was updated");
optimismPortal2.finalizeWithdrawalTransaction(_defaultTx);
}
/// @dev Tests an e2e prove -> finalize path, checking the edges of each delay for correctness.
function test_finalizeWithdrawalTransaction_delayEdges_succeeds() external {
// Prove the withdrawal transaction.
......
......@@ -254,6 +254,7 @@ contract Specification_Test is CommonTest {
_addSpec({ _name: "OptimismPortal2", _sel: _getSel("checkWithdrawal(bytes32)") });
_addSpec({ _name: "OptimismPortal2", _sel: _getSel("proofMaturityDelaySeconds()") });
_addSpec({ _name: "OptimismPortal2", _sel: _getSel("disputeGameFinalityDelaySeconds()") });
_addSpec({ _name: "OptimismPortal2", _sel: _getSel("respectedGameTypeUpdatedAt()") });
// ProtocolVersions
_addSpec({ _name: "ProtocolVersions", _sel: _getSel("RECOMMENDED_SLOT()") });
......
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