11// SPDX-License-Identifier: MIT
22pragma solidity 0.8.30 ;
33
4- import {SparseMerkleProof} from "../../libraries/linea/SparseMerkleProof.sol " ;
54import {ProverUtils} from "../../libraries/ProverUtils.sol " ;
65import {IStateProver} from "../../interfaces/IStateProver.sol " ;
76import {IBuffer} from "../../block-hash-pusher/interfaces/IBuffer.sol " ;
@@ -10,7 +9,6 @@ import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol";
109/// @notice Linea implementation of a child to parent IStateProver.
1110/// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the block hash buffer.
1211/// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie.
13- /// @custom:security-contact security@openzeppelin.com
1412contract ChildToParentProver is IStateProver {
1513 /// @dev Address of the block hash buffer contract.
1614 address public immutable blockHashBuffer;
@@ -23,25 +21,16 @@ contract ChildToParentProver is IStateProver {
2321
2422 error CallNotOnHomeChain ();
2523 error CallOnHomeChain ();
26- error InvalidAccountProof ();
27- error InvalidStorageProof ();
28- error StorageValueMismatch ();
29- error AccountKeyMismatch ();
30- error AccountValueMismatch ();
31- error StorageKeyMismatch ();
3224 error InvalidTargetStateCommitment ();
3325
3426 constructor (address _blockHashBuffer , uint256 _homeChainId ) {
3527 blockHashBuffer = _blockHashBuffer;
3628 homeChainId = _homeChainId;
3729 }
3830
39- /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer` using a Linea SMT proof
40- /// @dev Linea uses Sparse Merkle Trees with MiMC hashing.
41- /// Proofs must be generated using linea_getProof RPC method.
42- /// @param homeBlockHash The state root of the home chain (Linea SMT state root).
43- /// @param input ABI encoded (uint256 targetBlockNumber, uint256 accountLeafIndex, bytes[] accountProof,
44- /// bytes accountValue, uint256 storageLeafIndex, bytes[] storageProof, bytes32 claimedStorageValue)
31+ /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer` using a storage proof
32+ /// @param homeBlockHash The block hash of the home chain.
33+ /// @param input ABI encoded (bytes blockHeader, uint256 targetBlockNumber, bytes accountProof, bytes storageProof)
4534 function verifyTargetStateCommitment (bytes32 homeBlockHash , bytes calldata input )
4635 external
4736 view
@@ -50,62 +39,18 @@ contract ChildToParentProver is IStateProver {
5039 if (block .chainid == homeChainId) {
5140 revert CallOnHomeChain ();
5241 }
42+ // decode the input
43+ (bytes memory rlpBlockHeader , uint256 targetBlockNumber , bytes memory accountProof , bytes memory storageProof ) =
44+ abi.decode (input, (bytes , uint256 , bytes , bytes ));
5345
54- uint256 targetBlockNumber;
55- uint256 accountLeafIndex;
56- bytes [] memory accountProof;
57- bytes memory accountValue;
58- uint256 storageLeafIndex;
59- bytes [] memory storageProof;
60- bytes32 claimedStorageValue;
61-
62- (
63- targetBlockNumber,
64- accountLeafIndex,
65- accountProof,
66- accountValue,
67- storageLeafIndex,
68- storageProof,
69- claimedStorageValue
70- ) = abi.decode (input, (uint256 , uint256 , bytes [], bytes , uint256 , bytes [], bytes32 ));
71-
46+ // calculate the slot based on the provided block number
47+ // see: https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/contracts/Buffer.sol#L32
7248 uint256 slot = uint256 (SlotDerivation.deriveMapping (bytes32 (BLOCK_HASH_MAPPING_SLOT), targetBlockNumber));
7349
74- bool accountValid = SparseMerkleProof.verifyProof (accountProof, accountLeafIndex, homeBlockHash);
75- if (! accountValid) {
76- revert InvalidAccountProof ();
77- }
78-
79- SparseMerkleProof.Leaf memory accountLeaf = SparseMerkleProof.getLeaf (accountProof[accountProof.length - 1 ]);
80- bytes32 expectedAccountHKey = SparseMerkleProof.hashAccountKey (blockHashBuffer);
81- if (accountLeaf.hKey != expectedAccountHKey) {
82- revert AccountKeyMismatch ();
83- }
84-
85- bytes32 expectedAccountHValue = SparseMerkleProof.hashAccountValue (accountValue);
86- if (accountLeaf.hValue != expectedAccountHValue) {
87- revert AccountValueMismatch ();
88- }
89-
90- SparseMerkleProof.Account memory accountData = SparseMerkleProof.getAccount (accountValue);
91-
92- bool storageValid = SparseMerkleProof.verifyProof (storageProof, storageLeafIndex, accountData.storageRoot);
93- if (! storageValid) {
94- revert InvalidStorageProof ();
95- }
96-
97- SparseMerkleProof.Leaf memory storageLeaf = SparseMerkleProof.getLeaf (storageProof[storageProof.length - 1 ]);
98- bytes32 expectedStorageHKey = SparseMerkleProof.hashStorageKey (bytes32 (slot));
99- if (storageLeaf.hKey != expectedStorageHKey) {
100- revert StorageKeyMismatch ();
101- }
102-
103- bytes32 expectedHValue = SparseMerkleProof.hashStorageValue (claimedStorageValue);
104- if (storageLeaf.hValue != expectedHValue) {
105- revert StorageValueMismatch ();
106- }
107-
108- targetStateCommitment = claimedStorageValue;
50+ // verify proofs and get the block hash
51+ targetStateCommitment = ProverUtils.getSlotFromBlockHeader (
52+ homeBlockHash, rlpBlockHeader, blockHashBuffer, slot, accountProof, storageProof
53+ );
10954 require (targetStateCommitment != bytes32 (0 ), InvalidTargetStateCommitment ());
11055 }
11156
0 commit comments