Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[OP] - Aligning OpStackParentHashesFetcher with the latest Optimism stack #50

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@
pragma solidity ^0.8.19;

import {IParentHashFetcher} from "../interfaces/IParentHashFetcher.sol";
import {IL2OutputOracle} from "./interfaces/IL2OutputOracle.sol";
import {IDisputeGameFactory} from "./interfaces/IDisputeGameFactory.sol";
import {DisputeGameStatus} from "../../lib/Types.sol";
import {GameType} from "../../lib/Types.sol";

/// @title OpStackParentHashesFetcher
/// @notice Fetches parent hashes for the an OP stack based chain, settling to the chain where this contract is deployed
/// @notice for example if deployed on Ethereum, it will fetch parent hashes for Optimism/Base
contract OpStackParentHashesFetcher is IParentHashFetcher {
IL2OutputOracle public immutable l2OutputOracle;
IDisputeGameFactory public immutable disputeGameFactory;
uint256 public immutable chainId;
GameType public immutable respectedGameType;

constructor(IL2OutputOracle _l2OutputOracle, uint256 _chainId) {
l2OutputOracle = _l2OutputOracle;
constructor(IDisputeGameFactory _disputeGameFactory, uint256 _chainId, GameType _respectedGameType) {
disputeGameFactory = _disputeGameFactory;
chainId = _chainId;
respectedGameType = _respectedGameType;
}

function fetchParentHash(bytes memory ctx)
Expand All @@ -22,20 +26,31 @@ contract OpStackParentHashesFetcher is IParentHashFetcher {
override
returns (uint256 fetchedForBlock, bytes32 parentHash)
{
(uint256 l2OutputIndex, bytes memory outputRootPreimage) = abi.decode(ctx, (uint256, bytes));
IL2OutputOracle.OutputProposal memory outputProposal = l2OutputOracle.getL2Output(l2OutputIndex);
(uint256 startSearchGameIndex, bytes memory outputRootPreimage) = abi.decode(ctx, (uint256, bytes));

// Fetch the latest dispute game
IDisputeGameFactory.GameSearchResult memory game = disputeGameFactory.findLatestGames(
respectedGameType,
startSearchGameIndex,
1
)[0];

require(game.metadata != bytes32(0), "ERR_GAME_NOT_FOUND");
require(game.status == DisputeGameStatus.DEFENDER_WINS, "ERR_GAME_NOT_RESOLVED");

// To see the preimage structure and why it is valid, see:
// https://github.com/ethereum-optimism/optimism/blob/c24298e798f40003f752d12710aa1cad63ad66d1/packages/contracts-bedrock/src/libraries/Hashing.sol#L114
// https://github.com/ethereum-optimism/optimism/blob/c24298e798f40003f752d12710aa1cad63ad66d1/packages/contracts-bedrock/src/libraries/Types.sol#L25

// Ensure that the passed preimage matches the output proposal root
require(outputProposal.outputRoot == keccak256(outputRootPreimage), "ERR_INVALID_OUTPUT_PROPOSAL");
require(game.rootClaim == keccak256(outputRootPreimage), "ERR_INVALID_OUTPUT_PROPOSAL");


// Decode the values from the preimage
(,,, bytes32 latestBlockhash) = abi.decode(outputRootPreimage, (bytes32, bytes32, bytes32, bytes32));

fetchedForBlock = outputProposal.l2BlockNumber + 1;

// The block number is encoded in the game metadata
fetchedForBlock = uint256(uint160(bytes20(game.metadata))) + 1;
parentHash = latestBlockhash;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;

import {GameType} from "../../../lib/Types.sol";
import {DisputeGameStatus} from "../../../lib/Types.sol";

interface IDisputeGameFactory {
struct GameSearchResult {
uint256 index;
bytes32 metadata;
uint64 timestamp;
bytes32 rootClaim;
bytes extraData;
DisputeGameStatus status;
}

function findLatestGames(
GameType gameType,
uint256 start,
uint256 n
) external view returns (GameSearchResult[] memory games);
}
8 changes: 8 additions & 0 deletions src/lib/Types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,12 @@ library Types {
STORAGE_ROOT,
CODE_HASH
}

enum DisputeGameStatus {
IN_PROGRESS,
CHALLENGER_WINS,
DEFENDER_WINS
}

type GameType is uint32;
}