Skip to content

Commit 77b9823

Browse files
committed
working and tested
1 parent c44b585 commit 77b9823

File tree

6 files changed

+82
-14
lines changed

6 files changed

+82
-14
lines changed

solidity/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,5 @@ node_modules
4343
ignition/deployments/chain-31337
4444

4545
ignition/deployments
46+
47+
.venv

solidity/bun.lockb

347 Bytes
Binary file not shown.

solidity/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"bun-types": "latest",
5050
"chai": "^5.2.0",
5151
"ethers": "^6.4.0",
52+
"forge-std": "^1.1.2",
5253
"only-allow": "^1.2.1",
5354
"prettier": "^3.4.2",
5455
"prettier-plugin-solidity": "^1.4.1",

solidity/src/interfaces/modules/parent-hash-fetching/IOptimismParentHashFetcherModule.sol

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ interface IFaultDisputeGame {
1919
function gameCreator() external view returns (address);
2020
}
2121

22+
struct OptimismParentHashFetcherModuleStorage {
23+
// Chain ID of blocks being fetched
24+
uint256 chainId;
25+
// Dispute game factory
26+
IDisputeGameFactory disputeGameFactory;
27+
// Dispute game
28+
address trustedGameProposer;
29+
}
30+
2231
/// @notice Module that fetches the parent hash of blocks from Arbitrum
2332
/// @dev It needs to be deployed on the chain that Arbitrum settles on (L1)
2433
interface IOptimismParentHashFetcherModule {
25-
struct OptimismParentHashFetcherModuleStorage {
26-
// Chain ID of blocks being fetched
27-
uint256 chainId;
28-
// Dispute game factory
29-
IDisputeGameFactory disputeGameFactory;
30-
// Dispute game
31-
address trustedGameProposer;
32-
}
33-
3434
function initOptimismParentHashFetcherModule(uint256 chainId, address disputeGameFactory, address trustedGameProposer) external;
3535

3636
function optimismFetchParentHash(uint256 gameIndex, bytes32 versionByte, bytes32 stateRoot, bytes32 withdrawalStorageRoot, bytes memory blockHeader) external;

solidity/src/modules/parent-hash-fetching/OptimismParentHashFetcherModule.sol

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
pragma solidity ^0.8.27;
33

44
import {ISatellite} from "../../interfaces/ISatellite.sol";
5-
import {IOptimismParentHashFetcherModule, IDisputeGameFactory, IFaultDisputeGame} from "../../interfaces/modules/parent-hash-fetching/IOptimismParentHashFetcherModule.sol";
5+
import {IOptimismParentHashFetcherModule, OptimismParentHashFetcherModuleStorage, IDisputeGameFactory, IFaultDisputeGame} from "../../interfaces/modules/parent-hash-fetching/IOptimismParentHashFetcherModule.sol";
66
import {AccessController} from "../../libraries/AccessController.sol";
77
import {Lib_RLPReader as RLPReader} from "../../libraries/external/optimism/rlp/Lib_RLPReader.sol";
88

@@ -36,11 +36,10 @@ contract OptimismParentHashFetcherModule is IOptimismParentHashFetcherModule, Ac
3636
ms.trustedGameProposer = trustedGameProposer;
3737
}
3838

39-
/// @param rootHash Root hash that is key of the mapping `roots` of `ERC20Outbox` contract
4039
function optimismFetchParentHash(uint256 gameIndex, bytes32 versionByte, bytes32 stateRoot, bytes32 withdrawalStorageRoot, bytes memory blockHeader) external {
4140
OptimismParentHashFetcherModuleStorage storage ms = moduleStorage();
4241

43-
(uint32 gameType, uint64 timestamp, address proxy) = ms.disputeGameFactory.gameAtIndex(gameIndex);
42+
(, , address proxy) = ms.disputeGameFactory.gameAtIndex(gameIndex);
4443
require(proxy != address(0), "ERR_GAME_NOT_FOUND");
4544

4645
IFaultDisputeGame game = IFaultDisputeGame(proxy);
@@ -57,8 +56,8 @@ contract OptimismParentHashFetcherModule is IOptimismParentHashFetcherModule, Ac
5756
bytes32 rootClaim = game.rootClaim();
5857

5958
bytes32 blockHash = keccak256(blockHeader);
60-
bytes32 payload = abi.encodePacked(stateRoot, withdrawalStorageRoot, blockHash);
61-
bytes32 fullInput = abi.encodePacked(versionByte, payload);
59+
bytes memory payload = abi.encode(stateRoot, withdrawalStorageRoot, blockHash);
60+
bytes memory fullInput = bytes.concat(bytes32(versionByte), payload);
6261
bytes32 calculatedRoot = keccak256(fullInput);
6362

6463
require(rootClaim == calculatedRoot, "ERR_ROOT_CLAIM_MISMATCH");
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
pragma solidity ^0.8.27;
3+
4+
import {Test} from "forge-std/Test.sol";
5+
import {console} from "forge-std/console.sol";
6+
import {IFaultDisputeGame, IDisputeGameFactory} from "../src/interfaces/modules/parent-hash-fetching/IOptimismParentHashFetcherModule.sol";
7+
import {Lib_RLPReader} from "../src/libraries/external/optimism/rlp/Lib_RLPReader.sol";
8+
9+
contract OptimismParentHashFetcherModuleTest is Test {
10+
function test_OptimismFetchParentHash_Success() public view {
11+
uint256 gameIndex = 177;
12+
IDisputeGameFactory disputeGameFactory = IDisputeGameFactory(address(0xe5965Ab5962eDc7477C8520243A95517CD252fA9));
13+
address trustedGameProposer = 0x473300df21D047806A082244b417f96b32f13A33;
14+
bytes
15+
memory blockHeader = hex"f90245a040e73048087fca25ae73f38e37bb77aef9dc5d622ab3fed7c02f8d0e8eda3771a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a08cd5c86564142d3020554cffa6b3591a6a8d2f7b8ec2d263863f29e0ab6de222a0947d56916131017aa9b0b825c5df87eb1dba7abe2e64af928af19aefe19d15f9a0c7ab6c66f4cd77d512ee6f05293bee8d5ca8373b1f4c3f78ef93a0d2e5a25e11b901009009a20811241081800105868000c040818122180240000a000401006060400005881000200600010040001420002800048110c00102340280200040006c2b4122a00020021010083030090800823c0101822c00004400200000001080a04000100440454214000060011a0004004800003c10471000060011000336810a041180011040280400010128030030020100021050009020002020020002420a40020300200450802c041001000000c02080060870900000820008410100844801006202500b00000402974000360021140008a0000406a88608040024060a102a040030400b0221000080086048000001028580840009e3098000600800000d24088084073e52508401c9c380833a194f8466707e5980a0b082f25e221d6afde1bde578a17c505cc1dbbb22308aea8c5da45bb0a45eae42880000000000000000840396dd41a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a094acc027205dbe6f346931a354cd7db875a51bc4f876f18452046e552b14e13e";
16+
bytes32 stateRoot = 0x8cd5c86564142d3020554cffa6b3591a6a8d2f7b8ec2d263863f29e0ab6de222;
17+
bytes32 withdrawalStorageRoot = 0x8ebc68365e414b7382e25ceed949cd8cbdf68c69e760c84d2c38ffe009452f54;
18+
bytes32 versionByte = 0x0000000000000000000000000000000000000000000000000000000000000000;
19+
20+
(, , address proxy) = disputeGameFactory.gameAtIndex(gameIndex);
21+
require(proxy != address(0), "ERR_GAME_NOT_FOUND");
22+
23+
IFaultDisputeGame game = IFaultDisputeGame(proxy);
24+
uint8 status = game.status();
25+
26+
if (status == 1) {
27+
revert("ERR_GAME_FAILED");
28+
} else if (status == 0 && game.gameCreator() != trustedGameProposer) {
29+
revert("ERR_UNFINISHED_GAME_NOT_TRUSTED");
30+
} else if (status != 2) {
31+
revert("ERR_UNKNOWN_GAME_STATUS");
32+
}
33+
34+
bytes32 rootClaim = game.rootClaim();
35+
36+
bytes32 blockHash = keccak256(blockHeader);
37+
bytes memory payload = abi.encode(stateRoot, withdrawalStorageRoot, blockHash);
38+
console.logBytes(payload);
39+
// should be:
40+
console.logBytes(
41+
hex"8cd5c86564142d3020554cffa6b3591a6a8d2f7b8ec2d263863f29e0ab6de2228ebc68365e414b7382e25ceed949cd8cbdf68c69e760c84d2c38ffe009452f54c72e9ee468bcf8d5832cb48eec27270e1675d25a32bd7e90b299bcffd730f3e2"
42+
);
43+
44+
bytes memory fullInput = bytes.concat(bytes32(versionByte), payload);
45+
console.logBytes(fullInput);
46+
// should be:
47+
console.logBytes(
48+
hex"00000000000000000000000000000000000000000000000000000000000000008cd5c86564142d3020554cffa6b3591a6a8d2f7b8ec2d263863f29e0ab6de2228ebc68365e414b7382e25ceed949cd8cbdf68c69e760c84d2c38ffe009452f54c72e9ee468bcf8d5832cb48eec27270e1675d25a32bd7e90b299bcffd730f3e2"
49+
);
50+
51+
bytes32 calculatedRoot = keccak256(fullInput);
52+
console.logBytes32(calculatedRoot);
53+
console.logBytes32(rootClaim);
54+
55+
require(rootClaim == calculatedRoot, "ERR_ROOT_CLAIM_MISMATCH");
56+
57+
uint256 blockNumber = _decodeBlockNumber(blockHeader);
58+
59+
require(blockNumber == 121524816, "ERR_BLOCK_NUMBER_MISMATCH");
60+
}
61+
62+
function _decodeBlockNumber(bytes memory headerRlp) internal pure returns (uint256) {
63+
Lib_RLPReader.RLPItem[] memory items = Lib_RLPReader.readList(Lib_RLPReader.toRLPItem(headerRlp));
64+
return Lib_RLPReader.readUint256(items[8]);
65+
}
66+
}

0 commit comments

Comments
 (0)