From abb126288e375d35bb037c7d84e817e30036602c Mon Sep 17 00:00:00 2001 From: Luiz Date: Fri, 23 Jan 2026 10:24:23 -0300 Subject: [PATCH 01/25] update interfaces --- src/contracts/interfaces/IBlockHashProver.sol | 50 ------------------ src/contracts/interfaces/IStateProver.sol | 51 +++++++++++++++++++ ...verPointer.sol => IStateProverPointer.sol} | 10 ++-- 3 files changed, 56 insertions(+), 55 deletions(-) delete mode 100644 src/contracts/interfaces/IBlockHashProver.sol create mode 100644 src/contracts/interfaces/IStateProver.sol rename src/contracts/interfaces/{IBlockHashProverPointer.sol => IStateProverPointer.sol} (66%) diff --git a/src/contracts/interfaces/IBlockHashProver.sol b/src/contracts/interfaces/IBlockHashProver.sol deleted file mode 100644 index e7791ff..0000000 --- a/src/contracts/interfaces/IBlockHashProver.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.30; - -/// @notice The IBlockHashProver is responsible for retrieving the block hash of its target chain given its home chain's state. -/// The home chain's state is given either by a block hash and proof, or by the BlockHashProver executing on the home chain. -/// A single home and target chain are fixed by the logic of this contract. -interface IBlockHashProver { - /// @notice Verify the block hash of the target chain given the block hash of the home chain and a proof. - /// @dev MUST revert if called on the home chain. - /// MUST revert if the input is invalid or the input is not sufficient to determine the block hash. - /// MUST return a target chain block hash. - /// MUST be pure, with 1 exception: MAY read address(this).code. - /// @param homeBlockHash The block hash of the home chain. - /// @param input Any necessary input to determine a target chain block hash from the home chain block hash. - /// @return targetBlockHash The block hash of the target chain. - function verifyTargetBlockHash(bytes32 homeBlockHash, bytes calldata input) - external - view - returns (bytes32 targetBlockHash); - - /// @notice Get the block hash of the target chain. Does so by directly access state on the home chain. - /// @dev MUST revert if not called on the home chain. - /// MUST revert if the target chain's block hash cannot be determined. - /// MUST return a target chain block hash. - /// SHOULD use the input to determine a specific block hash to return. (e.g. input could be a block number) - /// SHOULD NOT read from its own storage. This contract is not meant to have state. - /// MAY make external calls. - /// @param input Any necessary input to fetch a target chain block hash. - /// @return targetBlockHash The block hash of the target chain. - function getTargetBlockHash(bytes calldata input) external view returns (bytes32 targetBlockHash); - - /// @notice Verify a storage slot given a target chain block hash and a proof. - /// @dev This function MUST NOT assume it is being called on the home chain. - /// MUST revert if the input is invalid or the input is not sufficient to determine a storage slot and its value. - /// MUST return a storage slot and its value on the target chain - /// MUST be pure, with 1 exception: MAY read address(this).code. - /// @param targetBlockHash The block hash of the target chain. - /// @param input Any necessary input to determine a single storage slot and its value. - /// @return account The address of the account on the target chain. - /// @return slot The storage slot of the account on the target chain. - /// @return value The value of the storage slot. - function verifyStorageSlot(bytes32 targetBlockHash, bytes calldata input) - external - view - returns (address account, uint256 slot, bytes32 value); - - /// @notice The version of the block hash prover. - /// @dev MUST be pure, with 1 exception: MAY read address(this).code. - function version() external pure returns (uint256); -} diff --git a/src/contracts/interfaces/IStateProver.sol b/src/contracts/interfaces/IStateProver.sol new file mode 100644 index 0000000..aaafd75 --- /dev/null +++ b/src/contracts/interfaces/IStateProver.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.30; + +/// @notice The IStateProver is responsible for retrieving the state commitment of its target chain given its home chain's state. +/// The home chain's state is given either by a state commitment and proof, or by the StateProver executing on the home chain. +/// A single home and target chain are fixed by the logic of this contract. +interface IStateProver { + /// @notice Verify the state commitment of the target chain given the state commitment of the home chain and a proof. + /// @dev MUST revert if called on the home chain. + /// MUST revert if the input is invalid or the input is not sufficient to determine the state commitment. + /// MUST return a target chain state commitment. + /// MUST be pure, with 1 exception: MAY read address(this).code. + /// @param homeStateCommitment The state commitment of the home chain. + /// @param input Any necessary input to determine a target chain state commitment from the home chain state commitment. + /// @return targetStateCommitment The state commitment of the target chain. + function verifyTargetStateCommitment(bytes32 homeStateCommitment, bytes calldata input) + external + view + returns (bytes32 targetStateCommitment); + + /// @notice Get the state commitment of the target chain. Does so by directly accessing state on the home chain. + /// @dev MUST revert if not called on the home chain. + /// MUST revert if the target chain's state commitment cannot be determined. + /// MUST return a target chain state commitment. + /// SHOULD use the input to determine a specific state commitment to return. (e.g. input could be a block number) + /// SHOULD NOT read from its own storage. This contract is not meant to have state. + /// MAY make external calls. + /// @param input Any necessary input to fetch a target chain state commitment. + /// @return targetStateCommitment The state commitment of the target chain. + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment); + + /// @notice Verify a storage slot given a target chain state commitment and a proof. + /// @dev This function MUST NOT assume it is being called on the home chain. + /// MUST revert if the input is invalid or the input is not sufficient to determine a storage slot and its value. + /// MUST return a storage slot and its value on the target chain. + /// MUST be pure, with 1 exception: MAY read address(this).code. + /// While messages MUST be stored in storage slots, alternative reading mechanisms may be used in some cases. + /// @param targetStateCommitment The state commitment of the target chain. + /// @param input Any necessary input to determine a single storage slot and its value. + /// @return account The address of the account on the target chain. + /// @return slot The storage slot of the account on the target chain. + /// @return value The value of the storage slot. + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) + external + view + returns (address account, uint256 slot, bytes32 value); + + /// @notice The version of the state commitment prover. + /// @dev MUST be pure, with 1 exception: MAY read address(this).code. + function version() external pure returns (uint256); +} diff --git a/src/contracts/interfaces/IBlockHashProverPointer.sol b/src/contracts/interfaces/IStateProverPointer.sol similarity index 66% rename from src/contracts/interfaces/IBlockHashProverPointer.sol rename to src/contracts/interfaces/IStateProverPointer.sol index c3b40d8..7e53bb1 100644 --- a/src/contracts/interfaces/IBlockHashProverPointer.sol +++ b/src/contracts/interfaces/IStateProverPointer.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.30; -/// @title IBlockHashProverPointer -/// @notice Keeps the code hash of the latest version of a block hash prover. -/// MUST store the code hash in storage slot BLOCK_HASH_PROVER_POINTER_SLOT. +/// @title IStateProverPointer +/// @notice Keeps the code hash of the latest version of a state commitment prover. +/// MUST store the code hash in storage slot STATE_PROVER_POINTER_SLOT. /// Different versions of the prover MUST have the same home and target chains. -/// If the pointer's prover is updated, the new prover MUST have a higher IBlockHashProver::version() than the old one. +/// If the pointer's prover is updated, the new prover MUST have a higher IStateProver::version() than the old one. /// These pointers are always referred to by their address on their home chain. -interface IBlockHashProverPointer { +interface IStateProverPointer { /// @notice Return the code hash of the latest version of the prover. function implementationCodeHash() external view returns (bytes32); From 8083f94bd858debd3086678a38de46b74844e7b1 Mon Sep 17 00:00:00 2001 From: Luiz Date: Fri, 23 Jan 2026 10:27:08 -0300 Subject: [PATCH 02/25] update interface --- src/contracts/interfaces/IReceiver.sol | 48 +++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/contracts/interfaces/IReceiver.sol b/src/contracts/interfaces/IReceiver.sol index 21c9451..8bbaf6c 100644 --- a/src/contracts/interfaces/IReceiver.sol +++ b/src/contracts/interfaces/IReceiver.sol @@ -5,23 +5,25 @@ import {IBlockHashProver} from "./IBlockHashProver.sol"; /// @notice Reads messages from a broadcaster. interface IReceiver { - /// @notice Arguments required to read storage of an account on a remote chain. - /// @dev The storage proof is always for a single slot, if the proof is for multiple slots the IReceiver MUST revert - /// @param route The home chain addresses of the BlockHashProverPointers along the route to the remote chain. - /// @param bhpInputs The inputs to the BlockHashProver / BlockHashProverCopies. - /// @param storageProof Proof passed to the last BlockHashProver / BlockHashProverCopy - /// to verify a storage slot given a target block hash. + /// @notice Arguments required to read state of an account on a remote chain. + /// @dev The proof is always for a single storage slot. If the proof is for multiple slots the IReceiver MUST revert. + /// The proof format depends on the state commitment scheme used by the StateProver (e.g., storage proofs). + /// While messages MUST be stored in storage slots, alternative reading mechanisms may be used in some cases. + /// @param route The home chain addresses of the StateProverPointers along the route to the remote chain. + /// @param scpInputs The inputs to the StateProver / StateProverCopies. + /// @param proof Proof passed to the last StateProver / StateProverCopy + /// to verify a storage slot given a target state commitment. struct RemoteReadArgs { address[] route; - bytes[] bhpInputs; - bytes storageProof; + bytes[] scpInputs; + bytes proof; } /// @notice Reads a broadcast message from a remote chain. /// @param broadcasterReadArgs A RemoteReadArgs object: /// - The route points to the broadcasting chain /// - The account proof is for the broadcaster's account - /// - The storage proof is for the message slot + /// - The proof is for the message storage slot (MAY accept proofs of other transmission mechanisms (e.g., child-to-parent native bridges) if the broadcaster contract uses other transmission mechanisms) /// @param message The message to read. /// @param publisher The address of the publisher who broadcast the message. /// @return broadcasterId The broadcaster's unique identifier. @@ -31,22 +33,20 @@ interface IReceiver { view returns (bytes32 broadcasterId, uint256 timestamp); - /// @notice Updates the block hash prover copy in storage. - /// Checks that BlockHashProverCopy has the same code hash as stored in the BlockHashProverPointer + /// @notice Updates the state commitment prover copy in storage. + /// Checks that StateProverCopy has the same code hash as stored in the StateProverPointer /// Checks that the version is increasing. - /// @param bhpPointerReadArgs A RemoteReadArgs object: - /// - The route points to the BlockHashProverPointer's home chain - /// - The account proof is for the BlockHashProverPointer's account - /// - The storage proof is for the BLOCK_HASH_PROVER_POINTER_SLOT - /// @param bhpCopy The BlockHashProver copy on the local chain. - /// @return bhpPointerId The ID of the BlockHashProverPointer - function updateBlockHashProverCopy(RemoteReadArgs calldata bhpPointerReadArgs, IBlockHashProver bhpCopy) + /// @param scpPointerReadArgs A RemoteReadArgs object: + /// - The route points to the StateProverPointer's home chain + /// - The account proof is for the StateProverPointer's account + /// - The proof is for the STATE_PROVER_POINTER_SLOT + /// @param scpCopy The StateProver copy on the local chain. + /// @return scpPointerId The ID of the StateProverPointer + function updateStateProverCopy(RemoteReadArgs calldata scpPointerReadArgs, IStateProver scpCopy) external - returns (bytes32 bhpPointerId); + returns (bytes32 scpPointerId); - /// @notice The BlockHashProverCopy on the local chain corresponding to the bhpPointerId - /// MUST return 0 if the BlockHashProverPointer does not exist. - /// @param bhpPointerId The unique identifier of the BlockHashProverPointer. - /// @return bhpCopy The BlockHashProver copy stored on the local chain, or address(0) if not found. - function blockHashProverCopy(bytes32 bhpPointerId) external view returns (IBlockHashProver bhpCopy); + /// @notice The StateProverCopy on the local chain corresponding to the scpPointerId + /// MUST return 0 if the StateProverPointer does not exist. + function stateProverCopy(bytes32 scpPointerId) external view returns (IStateProver scpCopy); } From 7f926e12f1e49e8385bb6933dbe4fcd48d4b9fad Mon Sep 17 00:00:00 2001 From: Luiz Date: Fri, 23 Jan 2026 10:33:01 -0300 Subject: [PATCH 03/25] update references to interfaces --- README.md | 2 +- src/contracts/BlockHashProverPointer.sol | 10 +++++----- src/contracts/Receiver.sol | 16 ++++++++-------- src/contracts/interfaces/IReceiver.sol | 2 +- src/contracts/libraries/ProverUtils.sol | 2 +- .../provers/arbitrum/ChildToParentProver.sol | 8 ++++---- .../provers/arbitrum/ParentToChildProver.sol | 8 ++++---- .../provers/linea/ChildToParentProver.sol | 6 +++--- .../provers/linea/ParentToChildProver.sol | 6 +++--- .../provers/optimism/ChildToParentProver.sol | 8 ++++---- .../provers/optimism/ParentToChildProver.sol | 8 ++++---- .../provers/scroll/ChildToParentProver.sol | 8 ++++---- .../provers/scroll/ParentToChildProver.sol | 8 ++++---- .../provers/taiko/ChildToParentProver.sol | 8 ++++---- .../provers/taiko/ParentToChildProver.sol | 8 ++++---- .../provers/zksync/ChildToParentProver.sol | 8 ++++---- .../provers/zksync/ParentToChildProver.sol | 8 ++++---- src/ts/ChildToParentProverHelper.ts | 2 +- src/ts/IProverHelper.ts | 8 ++++---- test/Receiver.ethereum.t.sol | 4 ++-- test/Receiver.t.sol | 4 ++-- test/mocks/MockProver.sol | 4 ++-- 22 files changed, 73 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 6c89933..18e766e 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Ethereum reference implementation for [ERC-7888: Crosschain Broadcaster](https:/ - `src/contracts/Receiver.sol`: Verifies broadcast messages from remote chains using a route of block-hash provers and a final storage proof; can cache prover copies. - `src/contracts/BlockHashProverPointer.sol`: Ownable pointer storing the current prover implementation address and code hash with version monotonicity checks. - `src/contracts/libraries/ProverUtils.sol`: Shared helpers for verifying block headers and MPT proofs (state root, account data, storage slot). -- Interfaces: `IBroadcaster`, `IReceiver`, `IBlockHashProver`, `IBlockHashProverPointer`. +- Interfaces: `IBroadcaster`, `IReceiver`, `IStateProver`, `IStateProverPointer`. ## Key concepts - **Broadcaster**: Singleton per chain that timestamps 32-byte messages in deterministic slots and emits `MessageBroadcast`. diff --git a/src/contracts/BlockHashProverPointer.sol b/src/contracts/BlockHashProverPointer.sol index 5981f69..1f39bd5 100644 --- a/src/contracts/BlockHashProverPointer.sol +++ b/src/contracts/BlockHashProverPointer.sol @@ -3,8 +3,8 @@ pragma solidity 0.8.30; import {StorageSlot} from "@openzeppelin/contracts/utils/StorageSlot.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -import {IBlockHashProver} from "./interfaces/IBlockHashProver.sol"; -import {IBlockHashProverPointer} from "./interfaces/IBlockHashProverPointer.sol"; +import {IStateProver} from "./interfaces/IStateProver.sol"; +import {IStateProverPointer} from "./interfaces/IStateProverPointer.sol"; bytes32 constant BLOCK_HASH_PROVER_POINTER_SLOT = bytes32(uint256(keccak256("eip7888.pointer.slot")) - 1); @@ -13,7 +13,7 @@ bytes32 constant BLOCK_HASH_PROVER_POINTER_SLOT = bytes32(uint256(keccak256("eip /// @dev This contract stores the address and code hash of the current BlockHashProver implementation. /// It enforces version monotonicity to ensure that updates always move to newer versions. /// The code hash is stored in a dedicated storage slot for efficient cross-chain verification. -contract BlockHashProverPointer is IBlockHashProverPointer, Ownable { +contract BlockHashProverPointer is IStateProverPointer, Ownable { address internal _implementationAddress; error NonIncreasingVersion(uint256 newVersion, uint256 oldVersion); @@ -45,7 +45,7 @@ contract BlockHashProverPointer is IBlockHashProverPointer, Ownable { } (bool success, bytes memory returnData) = - _newImplementationAddress.staticcall(abi.encodeWithSelector(IBlockHashProver.version.selector)); + _newImplementationAddress.staticcall(abi.encodeWithSelector(IStateProver.version.selector)); if (!success || returnData.length != 32) { revert InvalidImplementationAddress(); } @@ -54,7 +54,7 @@ contract BlockHashProverPointer is IBlockHashProverPointer, Ownable { address currentImplementationAddress = implementationAddress(); if (currentImplementationAddress != address(0)) { - uint256 oldVersion = IBlockHashProver(currentImplementationAddress).version(); + uint256 oldVersion = IStateProver(currentImplementationAddress).version(); if (newVersion <= oldVersion) { revert NonIncreasingVersion(newVersion, oldVersion); } diff --git a/src/contracts/Receiver.sol b/src/contracts/Receiver.sol index 3f5af19..5bc700b 100644 --- a/src/contracts/Receiver.sol +++ b/src/contracts/Receiver.sol @@ -2,8 +2,8 @@ pragma solidity 0.8.30; import {IReceiver} from "./interfaces/IReceiver.sol"; -import {IBlockHashProver} from "./interfaces/IBlockHashProver.sol"; -import {IBlockHashProverPointer} from "./interfaces/IBlockHashProverPointer.sol"; +import {IStateProver} from "./interfaces/IStateProver.sol"; +import {IStateProverPointer} from "./interfaces/IStateProverPointer.sol"; import {BLOCK_HASH_PROVER_POINTER_SLOT} from "./BlockHashProverPointer.sol"; /// @title Receiver @@ -15,7 +15,7 @@ import {BLOCK_HASH_PROVER_POINTER_SLOT} from "./BlockHashProverPointer.sol"; /// The verification process ensures that a message was actually broadcast on a remote chain /// at a specific timestamp without requiring trust in intermediaries. contract Receiver is IReceiver { - mapping(bytes32 blockHashProverPointerId => IBlockHashProver blockHashProverCopy) private _blockHashProverCopies; + mapping(bytes32 blockHashProverPointerId => IStateProver blockHashProverCopy) private _blockHashProverCopies; error InvalidRouteLength(); error EmptyRoute(); @@ -77,7 +77,7 @@ contract Receiver is IReceiver { /// @custom:throws WrongBlockHashProverPointerSlot if the proof doesn't read from the expected slot /// @custom:throws DifferentCodeHash if the local copy's code hash doesn't match the remote pointer's stored hash /// @custom:throws NewerProverVersion if an existing local copy has a version >= the new copy's version - function updateBlockHashProverCopy(RemoteReadArgs calldata bhpPointerReadArgs, IBlockHashProver bhpCopy) + function updateBlockHashProverCopy(RemoteReadArgs calldata bhpPointerReadArgs, IStateProver bhpCopy) external returns (bytes32 bhpPointerId) { @@ -93,7 +93,7 @@ contract Receiver is IReceiver { revert DifferentCodeHash(); } - IBlockHashProver oldProverCopy = _blockHashProverCopies[bhpPointerId]; + IStateProver oldProverCopy = _blockHashProverCopies[bhpPointerId]; if (address(oldProverCopy) != address(0) && oldProverCopy.version() >= bhpCopy.version()) { revert NewerProverVersion(); @@ -106,7 +106,7 @@ contract Receiver is IReceiver { /// MUST return 0 if the BlockHashProverPointer does not exist. /// @param bhpPointerId The unique identifier of the BlockHashProverPointer. /// @return bhpCopy The BlockHashProver copy stored on the local chain, or address(0) if not found. - function blockHashProverCopy(bytes32 bhpPointerId) external view returns (IBlockHashProver bhpCopy) { + function blockHashProverCopy(bytes32 bhpPointerId) external view returns (IStateProver bhpCopy) { bhpCopy = _blockHashProverCopies[bhpPointerId]; } @@ -123,14 +123,14 @@ contract Receiver is IReceiver { revert EmptyRoute(); } - IBlockHashProver prover; + IStateProver prover; bytes32 blockHash; for (uint256 i = 0; i < readArgs.route.length; i++) { remoteAccountId = accumulator(remoteAccountId, readArgs.route[i]); if (i == 0) { - prover = IBlockHashProver(IBlockHashProverPointer(readArgs.route[0]).implementationAddress()); + prover = IStateProver(IStateProverPointer(readArgs.route[0]).implementationAddress()); blockHash = prover.getTargetBlockHash(readArgs.bhpInputs[0]); } else { prover = _blockHashProverCopies[remoteAccountId]; diff --git a/src/contracts/interfaces/IReceiver.sol b/src/contracts/interfaces/IReceiver.sol index 8bbaf6c..a73ebd6 100644 --- a/src/contracts/interfaces/IReceiver.sol +++ b/src/contracts/interfaces/IReceiver.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.30; -import {IBlockHashProver} from "./IBlockHashProver.sol"; +import {IStateProver} from "./IStateProver.sol"; /// @notice Reads messages from a broadcaster. interface IReceiver { diff --git a/src/contracts/libraries/ProverUtils.sol b/src/contracts/libraries/ProverUtils.sol index 949f315..81f1e95 100644 --- a/src/contracts/libraries/ProverUtils.sol +++ b/src/contracts/libraries/ProverUtils.sol @@ -5,7 +5,7 @@ import {Lib_SecureMerkleTrie} from "@eth-optimism/contracts/libraries/trie/Lib_S import {RLP} from "@openzeppelin/contracts/utils/RLP.sol"; import {Memory} from "@openzeppelin/contracts/utils/Memory.sol"; -/// @notice Base contract for IBlockHashProver contracts. Contains helpers for verifying block headers and MPT proofs. +/// @notice Base contract for IStateProver contracts. Contains helpers for verifying block headers and MPT proofs. library ProverUtils { using Memory for bytes; using RLP for Memory.Slice; diff --git a/src/contracts/provers/arbitrum/ChildToParentProver.sol b/src/contracts/provers/arbitrum/ChildToParentProver.sol index ce5cf93..8633b2a 100644 --- a/src/contracts/provers/arbitrum/ChildToParentProver.sol +++ b/src/contracts/provers/arbitrum/ChildToParentProver.sol @@ -2,15 +2,15 @@ pragma solidity 0.8.30; import {ProverUtils} from "../../libraries/ProverUtils.sol"; -import {IBlockHashProver} from "../../interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../../interfaces/IStateProver.sol"; import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; -/// @notice Arbitrum implementation of a child to parent IBlockHashProver. +/// @notice Arbitrum implementation of a child to parent IStateProver. /// @dev verifyTargetBlockHash and getTargetBlockHash get block hashes from the block hash buffer at 0x0000000048C4Ed10cF14A02B9E0AbDDA5227b071. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12 for more details. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. -contract ChildToParentProver is IBlockHashProver { +contract ChildToParentProver is IStateProver { /// @dev Address of the block hash buffer contract /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/.env.example#L12 address public constant blockHashBuffer = 0x0000000048C4Ed10cF14A02B9E0AbDDA5227b071; @@ -86,7 +86,7 @@ contract ChildToParentProver is IBlockHashProver { ); } - /// @inheritdoc IBlockHashProver + /// @inheritdoc IStateProver function version() external pure returns (uint256) { return 1; } diff --git a/src/contracts/provers/arbitrum/ParentToChildProver.sol b/src/contracts/provers/arbitrum/ParentToChildProver.sol index 3a51d07..937f4cf 100644 --- a/src/contracts/provers/arbitrum/ParentToChildProver.sol +++ b/src/contracts/provers/arbitrum/ParentToChildProver.sol @@ -2,14 +2,14 @@ pragma solidity 0.8.30; import {ProverUtils} from "../../libraries/ProverUtils.sol"; -import {IBlockHashProver} from "../../interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../../interfaces/IStateProver.sol"; import {IOutbox} from "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; -/// @notice Arbitrum implementation of a parent to child IBlockHashProver. +/// @notice Arbitrum implementation of a parent to child IStateProver. /// @dev verifyTargetBlockHash and getTargetBlockHash get block hashes from the child chain's Outbox contract. /// verifyStorageSlot is implemented to work against any Arbitrum child chain with a standard Ethereum block header and state trie. -contract ParentToChildProver is IBlockHashProver { +contract ParentToChildProver is IStateProver { /// @dev Address of the child chain's Outbox contract address public immutable outbox; /// @dev Storage slot the Outbox contract uses to store roots. @@ -97,7 +97,7 @@ contract ParentToChildProver is IBlockHashProver { ); } - /// @inheritdoc IBlockHashProver + /// @inheritdoc IStateProver function version() external pure returns (uint256) { return 1; } diff --git a/src/contracts/provers/linea/ChildToParentProver.sol b/src/contracts/provers/linea/ChildToParentProver.sol index e7c122c..38e426e 100644 --- a/src/contracts/provers/linea/ChildToParentProver.sol +++ b/src/contracts/provers/linea/ChildToParentProver.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.28; import {ProverUtils} from "../../libraries/ProverUtils.sol"; -import {IBlockHashProver} from "../../interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../../interfaces/IStateProver.sol"; import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; -contract ChildToParentProver is IBlockHashProver { +contract ChildToParentProver is IStateProver { address public immutable blockHashBuffer; /// @dev Storage slot the buffer contract uses to store block hashes. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/contracts/Buffer.sol#L32 @@ -81,7 +81,7 @@ contract ChildToParentProver is IBlockHashProver { ); } - /// @inheritdoc IBlockHashProver + /// @inheritdoc IStateProver function version() external pure returns (uint256) { return 1; } diff --git a/src/contracts/provers/linea/ParentToChildProver.sol b/src/contracts/provers/linea/ParentToChildProver.sol index 4fbf8ec..42aac5d 100644 --- a/src/contracts/provers/linea/ParentToChildProver.sol +++ b/src/contracts/provers/linea/ParentToChildProver.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.28; import {SparseMerkleProof} from "../../libraries/linea/SparseMerkleProof.sol"; import {ProverUtils} from "../../libraries/ProverUtils.sol"; -import {IBlockHashProver} from "../../interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../../interfaces/IStateProver.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; interface ILineaRollup { @@ -22,7 +22,7 @@ interface ILineaRollup { /// /// Note: Linea uses Sparse Merkle Tree (SMT) with MiMC hashing, NOT Merkle-Patricia Trie (MPT). /// The state root stored on L1 is the SMT root, which requires linea_getProof for verification. -contract ParentToChildProver is IBlockHashProver { +contract ParentToChildProver is IStateProver { /// @dev Address of the LineaRollup contract on L1 address public immutable lineaRollup; @@ -201,7 +201,7 @@ contract ParentToChildProver is IBlockHashProver { value = claimedStorageValue; } - /// @inheritdoc IBlockHashProver + /// @inheritdoc IStateProver function version() external pure returns (uint256) { return 1; } diff --git a/src/contracts/provers/optimism/ChildToParentProver.sol b/src/contracts/provers/optimism/ChildToParentProver.sol index 51f9800..f0f7a77 100644 --- a/src/contracts/provers/optimism/ChildToParentProver.sol +++ b/src/contracts/provers/optimism/ChildToParentProver.sol @@ -2,13 +2,13 @@ pragma solidity 0.8.30; import {ProverUtils} from "../../libraries/ProverUtils.sol"; -import {IBlockHashProver} from "../../interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../../interfaces/IStateProver.sol"; interface IL1Block { function hash() external view returns (bytes32); } -/// @notice OP-stack implementation of a child to parent IBlockHashProver. +/// @notice OP-stack implementation of a child to parent IStateProver. /// @dev verifyTargetBlockHash and getTargetBlockHash get block hashes from the L1Block predeploy. /// verifyStorageSlot is implemented to work against any target chain with a standard Ethereum block header and state trie. /// @@ -16,7 +16,7 @@ interface IL1Block { /// Historical messages CAN be verified by generating fresh proofs on-demand. /// Pre-generated proofs become stale when L1Block updates (~5 minutes). /// Operational difference from Arbitrum: proofs must be generated just-in-time rather than pre-cached. -contract ChildToParentProver is IBlockHashProver { +contract ChildToParentProver is IStateProver { address public constant l1BlockPredeploy = 0x4200000000000000000000000000000000000015; uint256 public constant l1BlockHashSlot = 2; // hash is at slot 2 @@ -91,7 +91,7 @@ contract ChildToParentProver is IBlockHashProver { ); } - /// @inheritdoc IBlockHashProver + /// @inheritdoc IStateProver function version() external pure returns (uint256) { return 1; } diff --git a/src/contracts/provers/optimism/ParentToChildProver.sol b/src/contracts/provers/optimism/ParentToChildProver.sol index 3f7cc19..3f234c2 100644 --- a/src/contracts/provers/optimism/ParentToChildProver.sol +++ b/src/contracts/provers/optimism/ParentToChildProver.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.30; import {Lib_SecureMerkleTrie} from "@eth-optimism/contracts/libraries/trie/Lib_SecureMerkleTrie.sol"; import {Lib_RLPReader} from "@eth-optimism/contracts/libraries/rlp/Lib_RLPReader.sol"; import {ProverUtils} from "../../libraries/ProverUtils.sol"; -import {IBlockHashProver} from "../../interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../../interfaces/IStateProver.sol"; import {Bytes} from "@openzeppelin/contracts/utils/Bytes.sol"; interface IAnchorStateRegistry { @@ -15,10 +15,10 @@ interface IFaultDisputeGame { function rootClaim() external view returns (bytes32); } -/// @notice OP-stack implementation of a parent to child IBlockHashProver. +/// @notice OP-stack implementation of a parent to child IStateProver. /// @dev verifyTargetBlockHash and getTargetBlockHash get block hashes from a valid fault dispute game proxy contract. /// verifyStorageSlot is implemented to work against any OP-stack child chain with a standard Ethereum block header and state trie. -contract ParentToChildProver is IBlockHashProver { +contract ParentToChildProver is IStateProver { using Lib_RLPReader for Lib_RLPReader.RLPItem; struct OutputRootProof { @@ -155,7 +155,7 @@ contract ParentToChildProver is IBlockHashProver { ); } - /// @inheritdoc IBlockHashProver + /// @inheritdoc IStateProver function version() external pure returns (uint256) { return 1; } diff --git a/src/contracts/provers/scroll/ChildToParentProver.sol b/src/contracts/provers/scroll/ChildToParentProver.sol index ad442cf..e130ed9 100644 --- a/src/contracts/provers/scroll/ChildToParentProver.sol +++ b/src/contracts/provers/scroll/ChildToParentProver.sol @@ -2,15 +2,15 @@ pragma solidity ^0.8.28; import {ProverUtils} from "../../libraries/ProverUtils.sol"; -import {IBlockHashProver} from "../../interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../../interfaces/IStateProver.sol"; import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; -/// @notice implementation of a child to parent IBlockHashProver. +/// @notice implementation of a child to parent IStateProver. /// @dev verifyTargetBlockHash and getTargetBlockHash get block hashes from the block hash buffer on Scroll. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12 for more details. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. -contract ChildToParentProver is IBlockHashProver { +contract ChildToParentProver is IStateProver { address public immutable blockHashBuffer; /// @dev Storage slot the buffer contract uses to store block hashes. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/contracts/Buffer.sol#L32 @@ -85,7 +85,7 @@ contract ChildToParentProver is IBlockHashProver { ); } - /// @inheritdoc IBlockHashProver + /// @inheritdoc IStateProver function version() external pure returns (uint256) { return 1; } diff --git a/src/contracts/provers/scroll/ParentToChildProver.sol b/src/contracts/provers/scroll/ParentToChildProver.sol index 4471f17..7955389 100644 --- a/src/contracts/provers/scroll/ParentToChildProver.sol +++ b/src/contracts/provers/scroll/ParentToChildProver.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.30; import {ProverUtils} from "../../libraries/ProverUtils.sol"; -import {IBlockHashProver} from "../../interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../../interfaces/IStateProver.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; /// @notice Interface for Scroll's ScrollChain contract on L1 @@ -18,7 +18,7 @@ interface IScrollChain { function isBatchFinalized(uint256 batchIndex) external view returns (bool); } -/// @notice Scroll implementation of a parent to child IBlockHashProver. +/// @notice Scroll implementation of a parent to child IStateProver. /// @dev Home chain: L1 (Ethereum). Target chain: L2 (Scroll). /// getTargetBlockHash reads finalized L2 state roots directly from L1's ScrollChain. /// verifyTargetBlockHash verifies L2 state roots via storage proof against L1's ScrollChain. @@ -28,7 +28,7 @@ interface IScrollChain { /// in the ScrollChain contract. The "targetBlockHash" returned by this prover is actually /// the L2 state root, which can be used directly for MPT verification without needing /// the L2 block header. -contract ParentToChildProver is IBlockHashProver { +contract ParentToChildProver is IStateProver { /// @dev Address of the ScrollChain contract on L1 address public immutable scrollChain; @@ -135,7 +135,7 @@ contract ParentToChildProver is IBlockHashProver { ); } - /// @inheritdoc IBlockHashProver + /// @inheritdoc IStateProver function version() external pure returns (uint256) { return 1; } diff --git a/src/contracts/provers/taiko/ChildToParentProver.sol b/src/contracts/provers/taiko/ChildToParentProver.sol index ccde7c5..9a20447 100644 --- a/src/contracts/provers/taiko/ChildToParentProver.sol +++ b/src/contracts/provers/taiko/ChildToParentProver.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.28; import {ProverUtils} from "../../libraries/ProverUtils.sol"; -import {IBlockHashProver} from "../../interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../../interfaces/IStateProver.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; interface ICheckpointStore { @@ -15,12 +15,12 @@ interface ICheckpointStore { function getCheckpoint(uint48 _blockNumber) external view returns (Checkpoint memory); } -/// @notice Taiko implementation of a child to parent IBlockHashProver. +/// @notice Taiko implementation of a child to parent IStateProver. /// @dev Home chain: L2 (Taiko). Target chain: L1 (Ethereum). /// verifyTargetBlockHash gets L1 block hashes from L2's SignalService checkpoint storage. /// getTargetBlockHash reads L1 block hashes directly from L2's SignalService. /// verifyStorageSlot works against any Ethereum-compatible chain with standard block headers. -contract ChildToParentProver is IBlockHashProver { +contract ChildToParentProver is IStateProver { /// @dev Address of the L2 SignalService contract address public immutable signalService; @@ -121,7 +121,7 @@ contract ChildToParentProver is IBlockHashProver { ); } - /// @inheritdoc IBlockHashProver + /// @inheritdoc IStateProver function version() external pure returns (uint256) { return 1; } diff --git a/src/contracts/provers/taiko/ParentToChildProver.sol b/src/contracts/provers/taiko/ParentToChildProver.sol index 7135dde..825845b 100644 --- a/src/contracts/provers/taiko/ParentToChildProver.sol +++ b/src/contracts/provers/taiko/ParentToChildProver.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.28; import {ProverUtils} from "../../libraries/ProverUtils.sol"; -import {IBlockHashProver} from "../../interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../../interfaces/IStateProver.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; interface ICheckpointStore { @@ -15,12 +15,12 @@ interface ICheckpointStore { function getCheckpoint(uint48 _blockNumber) external view returns (Checkpoint memory); } -/// @notice Taiko implementation of a parent to child IBlockHashProver. +/// @notice Taiko implementation of a parent to child IStateProver. /// @dev Home chain: L1 (Ethereum). Target chain: L2 (Taiko). /// verifyTargetBlockHash gets L2 block hashes from L1's SignalService checkpoint storage. /// getTargetBlockHash reads L2 block hashes directly from L1's SignalService. /// verifyStorageSlot works against any Ethereum-compatible chain with standard block headers. -contract ParentToChildProver is IBlockHashProver { +contract ParentToChildProver is IStateProver { /// @dev Address of the L1 SignalService contract address public immutable signalService; @@ -121,7 +121,7 @@ contract ParentToChildProver is IBlockHashProver { ); } - /// @inheritdoc IBlockHashProver + /// @inheritdoc IStateProver function version() external pure returns (uint256) { return 1; } diff --git a/src/contracts/provers/zksync/ChildToParentProver.sol b/src/contracts/provers/zksync/ChildToParentProver.sol index e65ea18..cc956dd 100644 --- a/src/contracts/provers/zksync/ChildToParentProver.sol +++ b/src/contracts/provers/zksync/ChildToParentProver.sol @@ -2,15 +2,15 @@ pragma solidity ^0.8.28; import {ProverUtils} from "../../libraries/ProverUtils.sol"; -import {IBlockHashProver} from "../../interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../../interfaces/IStateProver.sol"; import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; -/// @notice implementation of a child to parent IBlockHashProver. +/// @notice implementation of a child to parent IStateProver. /// @dev verifyTargetBlockHash and getTargetBlockHash get block hashes from the block hash buffer on ZkSync. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12 for more details. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. -contract ChildToParentProver is IBlockHashProver { +contract ChildToParentProver is IStateProver { address public immutable blockHashBuffer; /// @dev Storage slot the buffer contract uses to store block hashes. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/contracts/Buffer.sol#L32 @@ -85,7 +85,7 @@ contract ChildToParentProver is IBlockHashProver { ); } - /// @inheritdoc IBlockHashProver + /// @inheritdoc IStateProver function version() external pure returns (uint256) { return 1; } diff --git a/src/contracts/provers/zksync/ParentToChildProver.sol b/src/contracts/provers/zksync/ParentToChildProver.sol index 1d7588b..c4db37f 100644 --- a/src/contracts/provers/zksync/ParentToChildProver.sol +++ b/src/contracts/provers/zksync/ParentToChildProver.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.30; import {ProverUtils} from "../../libraries/ProverUtils.sol"; -import {IBlockHashProver} from "../../interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../../interfaces/IStateProver.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; import {MessageHashing, ProofData} from "./libraries/MessageHashing.sol"; @@ -54,14 +54,14 @@ struct ZkSyncProof { bytes32[] proof; } -/// @notice ZkSync implementation of a parent to child IBlockHashProver. +/// @notice ZkSync implementation of a parent to child IStateProver. /// @dev This contract verifies L2 logs root hashes from ZkSync child chains on the parent chain (L1). /// The `verifyTargetBlockHash` and `getTargetBlockHash` functions retrieve L2 logs root hashes /// from the child chain's ZkChain contract. The `verifyStorageSlot` function is implemented /// to work against any ZkSync child chain with a standard Ethereum block header and state trie. /// This implementation is used to verify zkChain L2 log hash inclusion on L1 for messages that /// use the gateway as a middleware between the L2 and the L1. -contract ParentToChildProver is IBlockHashProver { +contract ParentToChildProver is IStateProver { /// @notice The ZkChain contract address on the gateway chain that stores L2 logs root hashes. IZkChain public immutable gatewayZkChain; @@ -276,7 +276,7 @@ contract ParentToChildProver is IBlockHashProver { } /// @notice Returns the version of this block hash prover implementation. - /// @inheritdoc IBlockHashProver + /// @inheritdoc IStateProver /// @return The version number (currently 1). function version() external pure returns (uint256) { return 1; diff --git a/src/ts/ChildToParentProverHelper.ts b/src/ts/ChildToParentProverHelper.ts index f5027a9..9c9c623 100644 --- a/src/ts/ChildToParentProverHelper.ts +++ b/src/ts/ChildToParentProverHelper.ts @@ -16,7 +16,7 @@ import { childToParentProverAbi, iBufferAbi } from '../../wagmi/abi' /** * ChildToParentProverHelper is a class that provides helper methods for interacting - * with the child to parent IBlockHashProver contract. + * with the child to parent IStateProver contract. * * It extends the BaseProverHelper class and implements the IProverHelper interface. * diff --git a/src/ts/IProverHelper.ts b/src/ts/IProverHelper.ts index b8a1c3b..e07ea22 100644 --- a/src/ts/IProverHelper.ts +++ b/src/ts/IProverHelper.ts @@ -1,13 +1,13 @@ import { Address, Hash, Hex } from 'viem' /** - * IProverHelper defines the interface that IBlockHashProver helper classes must implement. + * IProverHelper defines the interface that IStateProver helper classes must implement. * * Implementations should avoid relying on specialized RPC capabilities such as large log queries. */ export interface IProverHelper { /** - * Builds the bytes input argument for the IBlockHashProver::getTargetBlockHash function. + * Builds the bytes input argument for the IStateProver::getTargetBlockHash function. * Finds the newest block hash that can be returned by getTargetBlockHash on the prover. * @returns The input bytes and the resulting target block hash. */ @@ -17,7 +17,7 @@ export interface IProverHelper { }> /** - * Build the bytes input argument for the IBlockHashProver::verifyTargetBlockHash function. + * Build the bytes input argument for the IStateProver::verifyTargetBlockHash function. * Finds the newest block hash that can be returned by verifyTargetBlockHash on the prover given the home block hash. * @param homeBlockHash Home chain block hash that will be passed to the prover and proven against */ @@ -26,7 +26,7 @@ export interface IProverHelper { ): Promise<{ input: Hex; targetBlockHash: Hash }> /** - * Build the bytes input argument for the IBlockHashProver::verifyStorageSlot function. + * Build the bytes input argument for the IStateProver::verifyStorageSlot function. * @param targetBlockHash Target chain block hash that will be passed to the prover and proven against * @param account The account to prove the storage slot for * @param slot The storage slot to prove diff --git a/test/Receiver.ethereum.t.sol b/test/Receiver.ethereum.t.sol index 8aa3f71..abe61ad 100644 --- a/test/Receiver.ethereum.t.sol +++ b/test/Receiver.ethereum.t.sol @@ -5,9 +5,9 @@ import {console, Test} from "forge-std/Test.sol"; import {stdJson} from "forge-std/StdJson.sol"; import {Receiver} from "../src/contracts/Receiver.sol"; import {IReceiver} from "../src/contracts/interfaces/IReceiver.sol"; -import {IBlockHashProver} from "../src/contracts/interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../src/contracts/interfaces/IStateProver.sol"; import {IOutbox} from "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol"; -import {IBlockHashProverPointer} from "../src/contracts/interfaces/IBlockHashProverPointer.sol"; +import {IStateProverPointer} from "../src/contracts/interfaces/IStateProverPointer.sol"; import {BLOCK_HASH_PROVER_POINTER_SLOT} from "../src/contracts/BlockHashProverPointer.sol"; import {BlockHeaders} from "./utils/BlockHeaders.sol"; import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; diff --git a/test/Receiver.t.sol b/test/Receiver.t.sol index 0774cbf..4214a76 100644 --- a/test/Receiver.t.sol +++ b/test/Receiver.t.sol @@ -5,9 +5,9 @@ import {console, Test} from "forge-std/Test.sol"; import {stdJson} from "forge-std/StdJson.sol"; import {Receiver} from "../src/contracts/Receiver.sol"; import {IReceiver} from "../src/contracts/interfaces/IReceiver.sol"; -import {IBlockHashProver} from "../src/contracts/interfaces/IBlockHashProver.sol"; +import {IStateProver} from "../src/contracts/interfaces/IStateProver.sol"; import {IOutbox} from "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol"; -import {IBlockHashProverPointer} from "../src/contracts/interfaces/IBlockHashProverPointer.sol"; +import {IStateProverPointer} from "../src/contracts/interfaces/IStateProverPointer.sol"; import {BLOCK_HASH_PROVER_POINTER_SLOT} from "../src/contracts/BlockHashProverPointer.sol"; import {BlockHeaders} from "./utils/BlockHeaders.sol"; import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; diff --git a/test/mocks/MockProver.sol b/test/mocks/MockProver.sol index 3d3d32c..be920bd 100644 --- a/test/mocks/MockProver.sol +++ b/test/mocks/MockProver.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.30; -import {IBlockHashProver} from "src/contracts/interfaces/IBlockHashProver.sol"; +import {IStateProver} from "src/contracts/interfaces/IStateProver.sol"; -contract MockProver is IBlockHashProver { +contract MockProver is IStateProver { function verifyTargetBlockHash( bytes32 homeBlockHash, bytes calldata /*input*/ From 8dd8092b6e0eef076ddde17c35aba6f7327906f8 Mon Sep 17 00:00:00 2001 From: Luiz Date: Fri, 23 Jan 2026 10:37:31 -0300 Subject: [PATCH 04/25] rename --- README.md | 4 ++-- src/contracts/Receiver.sol | 2 +- test/Receiver.t.sol | 28 ++++++++++++++-------------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 18e766e..fe77cd9 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Ethereum reference implementation for [ERC-7888: Crosschain Broadcaster](https:/ - `bhpInputs`: prover-specific inputs for each hop (built off-chain with the TS helpers). - `storageProof`: a storage proof for the `Broadcaster` slot on the source chain at the proven block hash. 3) `Receiver` accumulates the route to derive unique IDs, ensures the proven slot matches `keccak(message, publisher)`, and returns `(broadcasterId, timestamp)`. -4) Before verifying, callers can seed `Receiver.updateBlockHashProverCopy` with a local prover copy whose code hash matches the pointer slot and whose `version()` increases. +4) Before verifying, callers can seed `Receiver.updateStateProverCopy` with a local prover copy whose code hash matches the pointer slot and whose `version()` increases. ## Repository layout - `src/contracts/` – Solidity contracts and interfaces. @@ -57,7 +57,7 @@ Ethereum reference implementation for [ERC-7888: Crosschain Broadcaster](https:/ ## Using the contracts (high level) - Deploy a `Broadcaster` on each chain where messages originate. - Deploy a `BlockHashProverPointer` per chain pair direction; point it to the canonical `BlockHashProver` implementation (must expose `version()` and stable code hash). -- On destination chains, deploy `Receiver` and register local prover copies via `updateBlockHashProverCopy` once the pointer’s code hash is provably available. +- On destination chains, deploy `Receiver` and register local prover copies via `updateStateProverCopy` once the pointer’s code hash is provably available. - Off-chain, use the TS helpers (or your own tooling) to: 1) Find a route (e.g., L2→L1→L2), 2) Build `bhpInputs` per hop plus the final `storageProof`, diff --git a/src/contracts/Receiver.sol b/src/contracts/Receiver.sol index 5bc700b..7da366f 100644 --- a/src/contracts/Receiver.sol +++ b/src/contracts/Receiver.sol @@ -77,7 +77,7 @@ contract Receiver is IReceiver { /// @custom:throws WrongBlockHashProverPointerSlot if the proof doesn't read from the expected slot /// @custom:throws DifferentCodeHash if the local copy's code hash doesn't match the remote pointer's stored hash /// @custom:throws NewerProverVersion if an existing local copy has a version >= the new copy's version - function updateBlockHashProverCopy(RemoteReadArgs calldata bhpPointerReadArgs, IStateProver bhpCopy) + function updateStateProverCopy(RemoteReadArgs calldata bhpPointerReadArgs, IStateProver bhpCopy) external returns (bytes32 bhpPointerId) { diff --git a/test/Receiver.t.sol b/test/Receiver.t.sol index 4214a76..2e72458 100644 --- a/test/Receiver.t.sol +++ b/test/Receiver.t.sol @@ -320,7 +320,7 @@ contract ReceiverTest is Test { assertEq(timestamp, uint256(value), "wrong timestamp"); } - function test_updateBlockHashProverCopy_from_Arbitrum_into_OP() public { + function test_updateStateProverCopy_from_Arbitrum_into_OP() public { vm.selectFork(optimismForkId); receiver = new Receiver(); @@ -373,7 +373,7 @@ contract ReceiverTest is Test { ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); - bytes32 bhpPointerId = receiver.updateBlockHashProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( bhpPointerId, @@ -393,7 +393,7 @@ contract ReceiverTest is Test { assertEq(address(arbParentToChildProverCopy).codehash, value, "wrong storage slot value"); } - function test_updateBlockHashProverCopy_from_Arbitrum_into_OP_reverts_when_different_code_hash() public { + function test_updateStateProverCopy_from_Arbitrum_into_OP_reverts_when_different_code_hash() public { vm.selectFork(optimismForkId); receiver = new Receiver(); @@ -447,7 +447,7 @@ contract ReceiverTest is Test { ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); vm.expectRevert(Receiver.DifferentCodeHash.selector); - receiver.updateBlockHashProverCopy(remoteReadArgs, arbParentToChildProverCopy); + receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); } function test_verifyBroadcastMessage_from_Arbitrum_into_OP() public { @@ -509,7 +509,7 @@ contract ReceiverTest is Test { IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); - bytes32 bhpPointerId = receiver.updateBlockHashProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( bhpPointerId, @@ -607,7 +607,7 @@ contract ReceiverTest is Test { assertEq(timestamp, uint256(valueArbitrum), "wrong timestamp"); } - function test_updateBlockHashProverCopy_from_Arbitrum_into_Zksync() public { + function test_updateStateProverCopy_from_Arbitrum_into_Zksync() public { vm.selectFork(zksyncForkId); receiver = new Receiver(); @@ -660,7 +660,7 @@ contract ReceiverTest is Test { ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); - bytes32 bhpPointerId = receiver.updateBlockHashProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( bhpPointerId, @@ -739,7 +739,7 @@ contract ReceiverTest is Test { IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); - bytes32 bhpPointerId = receiver.updateBlockHashProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( bhpPointerId, @@ -835,7 +835,7 @@ contract ReceiverTest is Test { assertEq(timestamp, uint256(valueArbitrum), "wrong timestamp"); } - function test_updateBlockHashProverCopy_from_Arbitrum_into_Linea() public { + function test_updateStateProverCopy_from_Arbitrum_into_Linea() public { vm.selectFork(lineaForkId); receiver = new Receiver(); @@ -888,7 +888,7 @@ contract ReceiverTest is Test { ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); - bytes32 bhpPointerId = receiver.updateBlockHashProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( bhpPointerId, @@ -967,7 +967,7 @@ contract ReceiverTest is Test { IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); - bytes32 bhpPointerId = receiver.updateBlockHashProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( bhpPointerId, @@ -1063,7 +1063,7 @@ contract ReceiverTest is Test { assertEq(timestamp, uint256(valueArbitrum), "wrong timestamp"); } - function test_updateBlockHashProverCopy_from_Arbitrum_into_Scroll() public { + function test_updateStateProverCopy_from_Arbitrum_into_Scroll() public { vm.selectFork(scrollForkId); receiver = new Receiver(); @@ -1116,7 +1116,7 @@ contract ReceiverTest is Test { ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); - bytes32 bhpPointerId = receiver.updateBlockHashProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( bhpPointerId, @@ -1195,7 +1195,7 @@ contract ReceiverTest is Test { IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); - bytes32 bhpPointerId = receiver.updateBlockHashProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( bhpPointerId, From 143d68d94c84f454a250d952527968052b1c51ec Mon Sep 17 00:00:00 2001 From: Luiz Date: Fri, 23 Jan 2026 10:42:47 -0300 Subject: [PATCH 05/25] rename getTargetBlockHash --- scripts/generate-optimism-test-payloads.ts | 2 +- scripts/taiko/README.txt | 2 +- src/contracts/Receiver.sol | 2 +- .../provers/arbitrum/ChildToParentProver.sol | 4 +-- .../provers/arbitrum/ParentToChildProver.sol | 4 +-- .../provers/linea/ChildToParentProver.sol | 2 +- .../provers/linea/ParentToChildProver.sol | 6 ++-- .../provers/optimism/ChildToParentProver.sol | 4 +-- .../provers/optimism/ParentToChildProver.sol | 4 +-- .../provers/scroll/ChildToParentProver.sol | 4 +-- .../provers/scroll/ParentToChildProver.sol | 4 +-- .../provers/taiko/ChildToParentProver.sol | 4 +-- .../provers/taiko/ParentToChildProver.sol | 4 +-- .../provers/zksync/ChildToParentProver.sol | 4 +-- .../provers/zksync/ParentToChildProver.sol | 4 +-- src/ts/IProverHelper.ts | 4 +-- src/ts/optimism/ChildToParentProverHelper.ts | 4 +-- test/Receiver.t.sol | 8 ++--- test/VerifyBroadcastMessageBenchmark.t.sol | 2 +- test/mocks/MockProver.sol | 2 +- test/payloads/linea/broadcast-info.json | 2 +- .../arbitrum/ChildToParentProver.t.sol | 20 ++++++------- .../arbitrum/ParentToChildProver.t.sol | 6 ++-- test/provers/linea/ParentToChildProver.t.sol | 22 +++++++------- .../optimism/ChildToParentProver.t.sol | 12 ++++---- test/provers/scroll/ParentToChildProver.t.sol | 22 +++++++------- test/provers/taiko/ChildToParentProver.t.sol | 26 ++++++++-------- test/provers/taiko/ParentToChildProver.t.sol | 30 +++++++++---------- test/provers/zksync/ParentChildToProver.t.sol | 12 ++++---- 29 files changed, 113 insertions(+), 113 deletions(-) diff --git a/scripts/generate-optimism-test-payloads.ts b/scripts/generate-optimism-test-payloads.ts index 22f5a96..d63f8db 100644 --- a/scripts/generate-optimism-test-payloads.ts +++ b/scripts/generate-optimism-test-payloads.ts @@ -5,7 +5,7 @@ * Run with: npx hardhat run scripts/generate-optimism-test-payloads.ts * * Generates: - * - calldata_get.hex: For getTargetBlockHash() test + * - calldata_get.hex: For getTargetStateCommitment() test * - calldata_verify_target.hex: For verifyTargetBlockHash() test * - calldata_verify_slot.hex: For verifyStorageSlot() test */ diff --git a/scripts/taiko/README.txt b/scripts/taiko/README.txt index b9bc28a..94d2032 100644 --- a/scripts/taiko/README.txt +++ b/scripts/taiko/README.txt @@ -359,6 +359,6 @@ IMPORTANT NOTES - storage-proof-generator uses debug_getRawHeader for Taiko - ParentToChildProver deployed on L1, reads L2 - ChildToParentProver deployed on L2, reads L1 -- Both use getTargetBlockHash in tests (direct SignalService read) +- Both use getTargetStateCommitment in tests (direct SignalService read) - Production would use verifyTargetBlockHash (with proofs) diff --git a/src/contracts/Receiver.sol b/src/contracts/Receiver.sol index 7da366f..afa0692 100644 --- a/src/contracts/Receiver.sol +++ b/src/contracts/Receiver.sol @@ -131,7 +131,7 @@ contract Receiver is IReceiver { if (i == 0) { prover = IStateProver(IStateProverPointer(readArgs.route[0]).implementationAddress()); - blockHash = prover.getTargetBlockHash(readArgs.bhpInputs[0]); + blockHash = prover.getTargetStateCommitment(readArgs.bhpInputs[0]); } else { prover = _blockHashProverCopies[remoteAccountId]; if (address(prover) == address(0)) { diff --git a/src/contracts/provers/arbitrum/ChildToParentProver.sol b/src/contracts/provers/arbitrum/ChildToParentProver.sol index 8633b2a..04102dc 100644 --- a/src/contracts/provers/arbitrum/ChildToParentProver.sol +++ b/src/contracts/provers/arbitrum/ChildToParentProver.sol @@ -7,7 +7,7 @@ import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; /// @notice Arbitrum implementation of a child to parent IStateProver. -/// @dev verifyTargetBlockHash and getTargetBlockHash get block hashes from the block hash buffer at 0x0000000048C4Ed10cF14A02B9E0AbDDA5227b071. +/// @dev verifyTargetBlockHash and getTargetStateCommitment get block hashes from the block hash buffer at 0x0000000048C4Ed10cF14A02B9E0AbDDA5227b071. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12 for more details. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. contract ChildToParentProver is IStateProver { @@ -54,7 +54,7 @@ contract ChildToParentProver is IStateProver { /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer`. /// @param input ABI encoded (uint256 targetBlockNumber) - function getTargetBlockHash(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } diff --git a/src/contracts/provers/arbitrum/ParentToChildProver.sol b/src/contracts/provers/arbitrum/ParentToChildProver.sol index 937f4cf..8147104 100644 --- a/src/contracts/provers/arbitrum/ParentToChildProver.sol +++ b/src/contracts/provers/arbitrum/ParentToChildProver.sol @@ -7,7 +7,7 @@ import {IOutbox} from "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; /// @notice Arbitrum implementation of a parent to child IStateProver. -/// @dev verifyTargetBlockHash and getTargetBlockHash get block hashes from the child chain's Outbox contract. +/// @dev verifyTargetBlockHash and getTargetStateCommitment get block hashes from the child chain's Outbox contract. /// verifyStorageSlot is implemented to work against any Arbitrum child chain with a standard Ethereum block header and state trie. contract ParentToChildProver is IStateProver { /// @dev Address of the child chain's Outbox contract @@ -61,7 +61,7 @@ contract ParentToChildProver is IStateProver { /// @notice Get a target chain block hash given a target chain sendRoot /// @param input ABI encoded (bytes32 sendRoot) - function getTargetBlockHash(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } diff --git a/src/contracts/provers/linea/ChildToParentProver.sol b/src/contracts/provers/linea/ChildToParentProver.sol index 38e426e..45da062 100644 --- a/src/contracts/provers/linea/ChildToParentProver.sol +++ b/src/contracts/provers/linea/ChildToParentProver.sol @@ -49,7 +49,7 @@ contract ChildToParentProver is IStateProver { /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer`. /// @param input ABI encoded (uint256 targetBlockNumber) - function getTargetBlockHash(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } diff --git a/src/contracts/provers/linea/ParentToChildProver.sol b/src/contracts/provers/linea/ParentToChildProver.sol index 42aac5d..89dac65 100644 --- a/src/contracts/provers/linea/ParentToChildProver.sol +++ b/src/contracts/provers/linea/ParentToChildProver.sol @@ -16,7 +16,7 @@ interface ILineaRollup { /// @title Linea ParentToChildProver /// @notice Enables verification of Linea L2 state from Ethereum L1 /// @dev Home chain: L1 (Ethereum). Target chain: L2 (Linea). -/// On L1: getTargetBlockHash reads L2 state root directly from LineaRollup +/// On L1: getTargetStateCommitment reads L2 state root directly from LineaRollup /// On L2: verifyTargetBlockHash proves L2 state root from L1 LineaRollup storage /// verifyStorageSlot: Verifies storage against the L2 state root using Sparse Merkle Tree proofs /// @@ -86,7 +86,7 @@ contract ParentToChildProver is IStateProver { /// @dev Called on home chain (L1) /// @param input ABI encoded (uint256 l2BlockNumber) /// @return targetBlockHash The L2 state root - function getTargetBlockHash(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } @@ -123,7 +123,7 @@ contract ParentToChildProver is IStateProver { /// 5. The storage proof corresponds to the claimed slot (hKey check) /// 6. The storage value matches the proof's hValue /// - /// @param targetBlockHash The L2 SMT state root (from getTargetBlockHash or verifyTargetBlockHash) + /// @param targetBlockHash The L2 SMT state root (from getTargetStateCommitment or verifyTargetBlockHash) /// @param input ABI encoded proof data from linea_getProof /// @return account The address of the account on L2 /// @return slot The storage slot diff --git a/src/contracts/provers/optimism/ChildToParentProver.sol b/src/contracts/provers/optimism/ChildToParentProver.sol index f0f7a77..ebd9011 100644 --- a/src/contracts/provers/optimism/ChildToParentProver.sol +++ b/src/contracts/provers/optimism/ChildToParentProver.sol @@ -9,7 +9,7 @@ interface IL1Block { } /// @notice OP-stack implementation of a child to parent IStateProver. -/// @dev verifyTargetBlockHash and getTargetBlockHash get block hashes from the L1Block predeploy. +/// @dev verifyTargetBlockHash and getTargetStateCommitment get block hashes from the L1Block predeploy. /// verifyStorageSlot is implemented to work against any target chain with a standard Ethereum block header and state trie. /// /// @dev Note: L1Block only stores the LATEST L1 block hash. @@ -63,7 +63,7 @@ contract ChildToParentProver is IStateProver { /// If the L1Block is consistently updated too frequently, calls to the Receiver may be DoS'd. /// In this case, this prover contract may need to be modified to use a different source of block hashes, /// such as a backup contract that calls the L1Block predeploy and caches the latest block hash. - function getTargetBlockHash(bytes calldata) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata) external view returns (bytes32 targetBlockHash) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } diff --git a/src/contracts/provers/optimism/ParentToChildProver.sol b/src/contracts/provers/optimism/ParentToChildProver.sol index 3f234c2..1a90f32 100644 --- a/src/contracts/provers/optimism/ParentToChildProver.sol +++ b/src/contracts/provers/optimism/ParentToChildProver.sol @@ -16,7 +16,7 @@ interface IFaultDisputeGame { } /// @notice OP-stack implementation of a parent to child IStateProver. -/// @dev verifyTargetBlockHash and getTargetBlockHash get block hashes from a valid fault dispute game proxy contract. +/// @dev verifyTargetBlockHash and getTargetStateCommitment get block hashes from a valid fault dispute game proxy contract. /// verifyStorageSlot is implemented to work against any OP-stack child chain with a standard Ethereum block header and state trie. contract ParentToChildProver is IStateProver { using Lib_RLPReader for Lib_RLPReader.RLPItem; @@ -117,7 +117,7 @@ contract ParentToChildProver is IStateProver { /// 2. Verify the root claim preimage against the game's root claim. /// 3. Return the latest block hash from the root claim preimage. /// @param input ABI encoded (address gameProxy, OutputRootProof rootClaimPreimage) - function getTargetBlockHash(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } diff --git a/src/contracts/provers/scroll/ChildToParentProver.sol b/src/contracts/provers/scroll/ChildToParentProver.sol index e130ed9..ed28b15 100644 --- a/src/contracts/provers/scroll/ChildToParentProver.sol +++ b/src/contracts/provers/scroll/ChildToParentProver.sol @@ -7,7 +7,7 @@ import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; /// @notice implementation of a child to parent IStateProver. -/// @dev verifyTargetBlockHash and getTargetBlockHash get block hashes from the block hash buffer on Scroll. +/// @dev verifyTargetBlockHash and getTargetStateCommitment get block hashes from the block hash buffer on Scroll. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12 for more details. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. contract ChildToParentProver is IStateProver { @@ -53,7 +53,7 @@ contract ChildToParentProver is IStateProver { /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer`. /// @param input ABI encoded (uint256 targetBlockNumber) - function getTargetBlockHash(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } diff --git a/src/contracts/provers/scroll/ParentToChildProver.sol b/src/contracts/provers/scroll/ParentToChildProver.sol index 7955389..1aaf867 100644 --- a/src/contracts/provers/scroll/ParentToChildProver.sol +++ b/src/contracts/provers/scroll/ParentToChildProver.sol @@ -20,7 +20,7 @@ interface IScrollChain { /// @notice Scroll implementation of a parent to child IStateProver. /// @dev Home chain: L1 (Ethereum). Target chain: L2 (Scroll). -/// getTargetBlockHash reads finalized L2 state roots directly from L1's ScrollChain. +/// getTargetStateCommitment reads finalized L2 state roots directly from L1's ScrollChain. /// verifyTargetBlockHash verifies L2 state roots via storage proof against L1's ScrollChain. /// verifyStorageSlot verifies storage against the L2 state root using standard MPT proofs. /// @@ -90,7 +90,7 @@ contract ParentToChildProver is IStateProver { /// @dev Called on home chain (L1) /// @param input ABI encoded (uint256 batchIndex) /// @return targetBlockHash The L2 state root (NOTE: this is a state root, not a block hash) - function getTargetBlockHash(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } diff --git a/src/contracts/provers/taiko/ChildToParentProver.sol b/src/contracts/provers/taiko/ChildToParentProver.sol index 9a20447..534f67b 100644 --- a/src/contracts/provers/taiko/ChildToParentProver.sol +++ b/src/contracts/provers/taiko/ChildToParentProver.sol @@ -18,7 +18,7 @@ interface ICheckpointStore { /// @notice Taiko implementation of a child to parent IStateProver. /// @dev Home chain: L2 (Taiko). Target chain: L1 (Ethereum). /// verifyTargetBlockHash gets L1 block hashes from L2's SignalService checkpoint storage. -/// getTargetBlockHash reads L1 block hashes directly from L2's SignalService. +/// getTargetStateCommitment reads L1 block hashes directly from L2's SignalService. /// verifyStorageSlot works against any Ethereum-compatible chain with standard block headers. contract ChildToParentProver is IStateProver { /// @dev Address of the L2 SignalService contract @@ -79,7 +79,7 @@ contract ChildToParentProver is IStateProver { /// @dev Called on home chain (L2) /// @param input ABI encoded (uint48 l1BlockNumber) /// @return targetBlockHash The L1 block hash - function getTargetBlockHash(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } diff --git a/src/contracts/provers/taiko/ParentToChildProver.sol b/src/contracts/provers/taiko/ParentToChildProver.sol index 825845b..6be84ea 100644 --- a/src/contracts/provers/taiko/ParentToChildProver.sol +++ b/src/contracts/provers/taiko/ParentToChildProver.sol @@ -18,7 +18,7 @@ interface ICheckpointStore { /// @notice Taiko implementation of a parent to child IStateProver. /// @dev Home chain: L1 (Ethereum). Target chain: L2 (Taiko). /// verifyTargetBlockHash gets L2 block hashes from L1's SignalService checkpoint storage. -/// getTargetBlockHash reads L2 block hashes directly from L1's SignalService. +/// getTargetStateCommitment reads L2 block hashes directly from L1's SignalService. /// verifyStorageSlot works against any Ethereum-compatible chain with standard block headers. contract ParentToChildProver is IStateProver { /// @dev Address of the L1 SignalService contract @@ -79,7 +79,7 @@ contract ParentToChildProver is IStateProver { /// @dev Called on home chain (L1) /// @param input ABI encoded (uint48 l2BlockNumber) /// @return targetBlockHash The L2 block hash - function getTargetBlockHash(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } diff --git a/src/contracts/provers/zksync/ChildToParentProver.sol b/src/contracts/provers/zksync/ChildToParentProver.sol index cc956dd..aff075c 100644 --- a/src/contracts/provers/zksync/ChildToParentProver.sol +++ b/src/contracts/provers/zksync/ChildToParentProver.sol @@ -7,7 +7,7 @@ import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; /// @notice implementation of a child to parent IStateProver. -/// @dev verifyTargetBlockHash and getTargetBlockHash get block hashes from the block hash buffer on ZkSync. +/// @dev verifyTargetBlockHash and getTargetStateCommitment get block hashes from the block hash buffer on ZkSync. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12 for more details. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. contract ChildToParentProver is IStateProver { @@ -53,7 +53,7 @@ contract ChildToParentProver is IStateProver { /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer`. /// @param input ABI encoded (uint256 targetBlockNumber) - function getTargetBlockHash(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } diff --git a/src/contracts/provers/zksync/ParentToChildProver.sol b/src/contracts/provers/zksync/ParentToChildProver.sol index c4db37f..e15fb5b 100644 --- a/src/contracts/provers/zksync/ParentToChildProver.sol +++ b/src/contracts/provers/zksync/ParentToChildProver.sol @@ -56,7 +56,7 @@ struct ZkSyncProof { /// @notice ZkSync implementation of a parent to child IStateProver. /// @dev This contract verifies L2 logs root hashes from ZkSync child chains on the parent chain (L1). -/// The `verifyTargetBlockHash` and `getTargetBlockHash` functions retrieve L2 logs root hashes +/// The `verifyTargetBlockHash` and `getTargetStateCommitment` functions retrieve L2 logs root hashes /// from the child chain's ZkChain contract. The `verifyStorageSlot` function is implemented /// to work against any ZkSync child chain with a standard Ethereum block header and state trie. /// This implementation is used to verify zkChain L2 log hash inclusion on L1 for messages that @@ -144,7 +144,7 @@ contract ParentToChildProver is IStateProver { /// @param input ABI encoded uint256 batchNumber - the batch number for which to retrieve the L2 logs root hash. /// @return l2LogsRootHash The L2 logs root hash for the specified batch number. /// @custom:reverts L2LogsRootHashNotFound if the L2 logs root hash is not found (returns zero). - function getTargetBlockHash(bytes calldata input) external view returns (bytes32 l2LogsRootHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 l2LogsRootHash) { if (block.chainid != homeChainId) { revert NotInHomeChain(); } diff --git a/src/ts/IProverHelper.ts b/src/ts/IProverHelper.ts index e07ea22..2621319 100644 --- a/src/ts/IProverHelper.ts +++ b/src/ts/IProverHelper.ts @@ -7,8 +7,8 @@ import { Address, Hash, Hex } from 'viem' */ export interface IProverHelper { /** - * Builds the bytes input argument for the IStateProver::getTargetBlockHash function. - * Finds the newest block hash that can be returned by getTargetBlockHash on the prover. + * Builds the bytes input argument for the IStateProver::getTargetStateCommitment function. + * Finds the newest block hash that can be returned by getTargetStateCommitment on the prover. * @returns The input bytes and the resulting target block hash. */ buildInputForGetTargetBlockHash(): Promise<{ diff --git a/src/ts/optimism/ChildToParentProverHelper.ts b/src/ts/optimism/ChildToParentProverHelper.ts index e366110..76e6719 100644 --- a/src/ts/optimism/ChildToParentProverHelper.ts +++ b/src/ts/optimism/ChildToParentProverHelper.ts @@ -24,7 +24,7 @@ export class OptimismChildToParentProverHelper readonly l1BlockHashSlot: bigint = 2n // hash is at slot 2 /** - * Build input for getTargetBlockHash() + * Build input for getTargetStateCommitment() * For Optimism, this reads the L1Block predeploy directly, so input can be empty */ async buildInputForGetTargetBlockHash(): Promise<{ @@ -37,7 +37,7 @@ export class OptimismChildToParentProverHelper slot: `0x${this.l1BlockHashSlot.toString(16)}` as Hex, }) as Hash - // getTargetBlockHash() on Optimism doesn't need any input + // getTargetStateCommitment() on Optimism doesn't need any input // It reads the predeploy directly return { input: '0x' as Hex, diff --git a/test/Receiver.t.sol b/test/Receiver.t.sol index 2e72458..010874b 100644 --- a/test/Receiver.t.sol +++ b/test/Receiver.t.sol @@ -530,7 +530,7 @@ contract ReceiverTest is Test { } // Construct the route to verify a message broadcasted on Arbitrum chain in OP - // We need to construct three inputs: one for OPChildToParentProver getTargetBlockHash, + // We need to construct three inputs: one for OPChildToParentProver getTargetStateCommitment, // one for ArbParentToChildProver verifyTargetBlockHash, and one for ArbParentToChildProver verifyStorageSlot // the input to verifyStorageSlot is the proof of the broadcasted message itself. // the input for verifyTargetBlockHash is the storage proof of the slot on the outbox contract. @@ -760,7 +760,7 @@ contract ReceiverTest is Test { } // Construct the route to verify a message broadcasted on Arbitrum chain in ZkSync - // We need to construct three inputs: one for ZksyncChildToParentProver getTargetBlockHash, + // We need to construct three inputs: one for ZksyncChildToParentProver getTargetStateCommitment, // one for ArbParentToChildProver verifyTargetBlockHash, and one for ArbParentToChildProver verifyStorageSlot // the input to verifyStorageSlot is the proof of the broadcasted message itself. // the input for verifyTargetBlockHash is the storage proof of the slot on the outbox contract. @@ -988,7 +988,7 @@ contract ReceiverTest is Test { } // Construct the route to verify a message broadcasted on Arbitrum chain in Linea - // We need to construct three inputs: one for LineaChildToParentProver getTargetBlockHash, + // We need to construct three inputs: one for LineaChildToParentProver getTargetStateCommitment, // one for ArbParentToChildProver verifyTargetBlockHash, and one for ArbParentToChildProver verifyStorageSlot // the input to verifyStorageSlot is the proof of the broadcasted message itself. // the input for verifyTargetBlockHash is the storage proof of the slot on the outbox contract. @@ -1216,7 +1216,7 @@ contract ReceiverTest is Test { } // Construct the route to verify a message broadcasted on Arbitrum chain in Scroll - // We need to construct three inputs: one for ScrollChildToParentProver getTargetBlockHash, + // We need to construct three inputs: one for ScrollChildToParentProver getTargetStateCommitment, // one for ArbParentToChildProver verifyTargetBlockHash, and one for ArbParentToChildProver verifyStorageSlot // the input to verifyStorageSlot is the proof of the broadcasted message itself. // the input for verifyTargetBlockHash is the storage proof of the slot on the outbox contract. diff --git a/test/VerifyBroadcastMessageBenchmark.t.sol b/test/VerifyBroadcastMessageBenchmark.t.sol index 589c92c..076c7b5 100644 --- a/test/VerifyBroadcastMessageBenchmark.t.sol +++ b/test/VerifyBroadcastMessageBenchmark.t.sol @@ -463,7 +463,7 @@ contract VerifyBroadcastMessageBenchmark is Test { vm.startSnapshotGas("verifyBroadcastMessage", "ScrollToOptimism"); // First: get Ethereum block hash via OP C2P (simulates first hop verification) - opC2PProver.getTargetBlockHash(bytes("")); + opC2PProver.getTargetStateCommitment(bytes("")); // Second: verify Scroll storage using Scroll P2C (simulates second hop verification) scrollP2CProverCopy.verifyStorageSlot(scrollStateRoot, scrollStorageProof); diff --git a/test/mocks/MockProver.sol b/test/mocks/MockProver.sol index be920bd..7923734 100644 --- a/test/mocks/MockProver.sol +++ b/test/mocks/MockProver.sol @@ -15,7 +15,7 @@ contract MockProver is IStateProver { return homeBlockHash; } - function getTargetBlockHash(bytes calldata input) external pure returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external pure returns (bytes32 targetBlockHash) { targetBlockHash = abi.decode(input, (bytes32)); } diff --git a/test/payloads/linea/broadcast-info.json b/test/payloads/linea/broadcast-info.json index 6cb7d0c..45154ec 100644 --- a/test/payloads/linea/broadcast-info.json +++ b/test/payloads/linea/broadcast-info.json @@ -10,7 +10,7 @@ "finalization": { "batchBlockNumber": 21834331, "zkStateRoot": "0x0b9797153d1cef2b38f6e87d2c225791b74107ae7ce28e60bf498b9d1c094f14", - "note": "Linea only stores state roots at batch boundaries. Use batchBlockNumber (not txBlockNumber) for getTargetBlockHash. Uses Sparse Merkle Tree proofs (linea_getProof)." + "note": "Linea only stores state roots at batch boundaries. Use batchBlockNumber (not txBlockNumber) for getTargetStateCommitment. Uses Sparse Merkle Tree proofs (linea_getProof)." }, "storageSlot": { "slot": "0xc7f3206d60205e1634924ee1e67de7607b9a5991744aaf3526fde997abcc5170", diff --git a/test/provers/arbitrum/ChildToParentProver.t.sol b/test/provers/arbitrum/ChildToParentProver.t.sol index 6660fd2..6754b70 100644 --- a/test/provers/arbitrum/ChildToParentProver.t.sol +++ b/test/provers/arbitrum/ChildToParentProver.t.sol @@ -81,7 +81,7 @@ contract BroadcasterTest is Test { payload = vm.parseBytes(vm.readFile(string.concat(vm.projectRoot(), "/", path))); } - function test_getTargetBlockHash() public { + function test_getTargetStateCommitment() public { vm.selectFork(childForkId); bytes memory payload = _loadPayload("test/payloads/arbitrum/calldata_get.hex"); @@ -95,23 +95,23 @@ contract BroadcasterTest is Test { targetBlockHash := mload(add(payload, 0x40)) } - bytes32 result = childToParentProver.getTargetBlockHash(abi.encode(input)); + bytes32 result = childToParentProver.getTargetStateCommitment(abi.encode(input)); assertEq(result, targetBlockHash); } - function test_getTargetBlockHash_broadcast() public { + function test_getTargetStateCommitment_broadcast() public { vm.selectFork(childForkId); bytes32 targetBlockHash = 0x57845b0a97194c2869580ed8857fee67c91f2bb9cdf54368685c0ea5bf25f6c2; uint256 blockNumber = 9043658; - bytes32 result = childToParentProver.getTargetBlockHash(abi.encode(blockNumber)); + bytes32 result = childToParentProver.getTargetStateCommitment(abi.encode(blockNumber)); assertEq(result, targetBlockHash); } - function test_getTargetBlockHash_broadcaster() public { + function test_getTargetStateCommitment_broadcaster() public { vm.selectFork(childForkId); bytes memory payload = _loadPayload("test/payloads/arbitrum/broadcaster_get.hex"); @@ -125,12 +125,12 @@ contract BroadcasterTest is Test { targetBlockHash := mload(add(payload, 0x40)) } - bytes32 result = childToParentProver.getTargetBlockHash(abi.encode(input)); + bytes32 result = childToParentProver.getTargetStateCommitment(abi.encode(input)); assertEq(result, targetBlockHash); } - function test_reverts_getTargetBlockHash_on_target_chain() public { + function test_reverts_getTargetStateCommitment_on_target_chain() public { vm.selectFork(parentForkId); bytes memory payload = _loadPayload("test/payloads/arbitrum/calldata_get.hex"); @@ -147,16 +147,16 @@ contract BroadcasterTest is Test { } vm.expectRevert(ChildToParentProver.CallNotOnHomeChain.selector); - newChildToParentProver.getTargetBlockHash(abi.encode(input)); + newChildToParentProver.getTargetStateCommitment(abi.encode(input)); } - function test_reverts_getTargetBlockHash_reverts_not_found() public { + function test_reverts_getTargetStateCommitment_reverts_not_found() public { vm.selectFork(childForkId); uint256 input = type(uint256).max; vm.expectRevert(abi.encodeWithSelector(IBuffer.UnknownParentChainBlockHash.selector, input)); - childToParentProver.getTargetBlockHash(abi.encode(input)); + childToParentProver.getTargetStateCommitment(abi.encode(input)); } function test_verifyTargetBlockHash() public { diff --git a/test/provers/arbitrum/ParentToChildProver.t.sol b/test/provers/arbitrum/ParentToChildProver.t.sol index 9fc69bb..532bbd0 100644 --- a/test/provers/arbitrum/ParentToChildProver.t.sol +++ b/test/provers/arbitrum/ParentToChildProver.t.sol @@ -84,15 +84,15 @@ contract ArbitrumParentToChildProverTest is Test { mockOutbox.updateSendRoot(sendRoot, targetBlockHashFromProof); } - function test_getTargetBlockHash() public { + function test_getTargetStateCommitment() public { vm.selectFork(parentForkId); // Test with the sendRoot from the proof data bytes32 sendRoot = 0x7995a5be000a0212a46f7f128e5ffd6f6a99fa9c72046d9e9b0668bd080712cd; ParentToChildProver mockProver = new ParentToChildProver(address(mockOutbox), rootSlot, block.chainid); - bytes32 result = mockProver.getTargetBlockHash(abi.encode(sendRoot)); + bytes32 result = mockProver.getTargetStateCommitment(abi.encode(sendRoot)); bytes32 expectedTargetBlockHash = 0xa97ce065a04d2abfec36a459db323721847718d3159d51c4256d271ee3b37e42; - assertEq(result, expectedTargetBlockHash, "getTargetBlockHash should return correct Arbitrum block hash"); + assertEq(result, expectedTargetBlockHash, "getTargetStateCommitment should return correct Arbitrum block hash"); } function test_verifyTargetBlockHash() public { diff --git a/test/provers/linea/ParentToChildProver.t.sol b/test/provers/linea/ParentToChildProver.t.sol index e5d1936..04c87c4 100644 --- a/test/provers/linea/ParentToChildProver.t.sol +++ b/test/provers/linea/ParentToChildProver.t.sol @@ -73,51 +73,51 @@ contract LineaParentToChildProverTest is Test { } // ═══════════════════════════════════════════════════════════════════════════ - // getTargetBlockHash Tests (Home Chain - L1) + // getTargetStateCommitment Tests (Home Chain - L1) // ═══════════════════════════════════════════════════════════════════════════ - function test_getTargetBlockHash_success() public { + function test_getTargetStateCommitment_success() public { // Set up mock to return a state root mockLineaRollup.setStateRootHash(L2_BLOCK_NUMBER, L2_STATE_ROOT); // We're on L1 (home chain) by default in tests vm.chainId(ETH_MAINNET_CHAIN_ID); - bytes32 stateRoot = prover.getTargetBlockHash(abi.encode(L2_BLOCK_NUMBER)); + bytes32 stateRoot = prover.getTargetStateCommitment(abi.encode(L2_BLOCK_NUMBER)); assertEq(stateRoot, L2_STATE_ROOT); } - function test_getTargetBlockHash_revertsWhenNotFound() public { + function test_getTargetStateCommitment_revertsWhenNotFound() public { // State root not set (returns bytes32(0)) vm.chainId(ETH_MAINNET_CHAIN_ID); vm.expectRevert(ParentToChildProver.TargetStateRootNotFound.selector); - prover.getTargetBlockHash(abi.encode(L2_BLOCK_NUMBER)); + prover.getTargetStateCommitment(abi.encode(L2_BLOCK_NUMBER)); } - function test_getTargetBlockHash_revertsOffHomeChain() public { + function test_getTargetStateCommitment_revertsOffHomeChain() public { // Switch to Linea L2 (not home chain) vm.chainId(LINEA_MAINNET_CHAIN_ID); vm.expectRevert(ParentToChildProver.CallNotOnHomeChain.selector); - prover.getTargetBlockHash(abi.encode(L2_BLOCK_NUMBER)); + prover.getTargetStateCommitment(abi.encode(L2_BLOCK_NUMBER)); } - function test_getTargetBlockHash_zeroBlockNumber() public { + function test_getTargetStateCommitment_zeroBlockNumber() public { mockLineaRollup.setStateRootHash(0, L2_STATE_ROOT); vm.chainId(ETH_MAINNET_CHAIN_ID); - bytes32 stateRoot = prover.getTargetBlockHash(abi.encode(uint256(0))); + bytes32 stateRoot = prover.getTargetStateCommitment(abi.encode(uint256(0))); assertEq(stateRoot, L2_STATE_ROOT); } - function testFuzz_getTargetBlockHash_revertsOnUnknownBlock(uint48 blockNumber) public { + function testFuzz_getTargetStateCommitment_revertsOnUnknownBlock(uint48 blockNumber) public { // Don't set any state root vm.chainId(ETH_MAINNET_CHAIN_ID); vm.expectRevert(ParentToChildProver.TargetStateRootNotFound.selector); - prover.getTargetBlockHash(abi.encode(uint256(blockNumber))); + prover.getTargetStateCommitment(abi.encode(uint256(blockNumber))); } // ═══════════════════════════════════════════════════════════════════════════ diff --git a/test/provers/optimism/ChildToParentProver.t.sol b/test/provers/optimism/ChildToParentProver.t.sol index 5d00286..a3c332f 100644 --- a/test/provers/optimism/ChildToParentProver.t.sol +++ b/test/provers/optimism/ChildToParentProver.t.sol @@ -36,10 +36,10 @@ contract OptimismChildToParentProverTest is Test { payload = vm.parseBytes(vm.readFile(string.concat(vm.projectRoot(), "/", path))); } - /// @notice Test getTargetBlockHash() - reads L1Block predeploy on Optimism + /// @notice Test getTargetStateCommitment() - reads L1Block predeploy on Optimism /// @dev Uses LIVE data instead of payload files because L1Block updates constantly. /// This approach is more reliable than static payloads for Optimism. - function test_getTargetBlockHash() public { + function test_getTargetStateCommitment() public { vm.selectFork(childForkId); // Read the CURRENT L1 block hash from the predeploy @@ -52,14 +52,14 @@ contract OptimismChildToParentProverTest is Test { expectedL1Hash = abi.decode(data, (bytes32)); // Test our prover returns the same value - bytes32 result = childToParentProver.getTargetBlockHash(""); + bytes32 result = childToParentProver.getTargetStateCommitment(""); assertEq(result, expectedL1Hash, "Block hash should match L1Block predeploy"); assertTrue(result != bytes32(0), "Block hash should not be zero"); } - /// @notice Test getTargetBlockHash() reverts when called on target chain (Ethereum) - function test_reverts_getTargetBlockHash_on_target_chain() public { + /// @notice Test getTargetStateCommitment() reverts when called on target chain (Ethereum) + function test_reverts_getTargetStateCommitment_on_target_chain() public { vm.selectFork(parentForkId); bytes memory payload = _loadPayload("test/payloads/optimism/calldata_get.hex"); @@ -75,7 +75,7 @@ contract OptimismChildToParentProverTest is Test { // Should revert because we're on Ethereum, not Optimism vm.expectRevert(ChildToParentProver.CallNotOnHomeChain.selector); - newChildToParentProver.getTargetBlockHash(abi.encode(input)); + newChildToParentProver.getTargetStateCommitment(abi.encode(input)); } /// @notice Test verifyTargetBlockHash() - uses Merkle proofs diff --git a/test/provers/scroll/ParentToChildProver.t.sol b/test/provers/scroll/ParentToChildProver.t.sol index ea0219b..a2a2fe8 100644 --- a/test/provers/scroll/ParentToChildProver.t.sol +++ b/test/provers/scroll/ParentToChildProver.t.sol @@ -59,8 +59,8 @@ contract ScrollChainMock is IScrollChain { l2ChainId = 534352; // Scroll mainnet chain ID } - /// @notice Test getTargetBlockHash returns state root when called on home chain - function test_getTargetBlockHash_success() public { + /// @notice Test getTargetStateCommitment returns state root when called on home chain + function test_getTargetStateCommitment_success() public { vm.selectFork(l1ForkId); uint256 batchIndex = 12345; @@ -69,15 +69,15 @@ contract ScrollChainMock is IScrollChain { // Set up the mock scrollChainMock.setFinalizedStateRoot(batchIndex, expectedStateRoot); - // Call getTargetBlockHash + // Call getTargetStateCommitment bytes memory input = abi.encode(batchIndex); - bytes32 stateRoot = parentToChildProver.getTargetBlockHash(input); + bytes32 stateRoot = parentToChildProver.getTargetStateCommitment(input); assertEq(stateRoot, expectedStateRoot, "State root mismatch"); } - /// @notice Test getTargetBlockHash reverts when batch is not finalized - function test_getTargetBlockHash_stateRootNotFound() public { + /// @notice Test getTargetStateCommitment reverts when batch is not finalized + function test_getTargetStateCommitment_stateRootNotFound() public { vm.selectFork(l1ForkId); uint256 batchIndex = 99999; // Non-existent batch @@ -85,11 +85,11 @@ contract ScrollChainMock is IScrollChain { bytes memory input = abi.encode(batchIndex); vm.expectRevert(ParentToChildProver.StateRootNotFound.selector); - parentToChildProver.getTargetBlockHash(input); + parentToChildProver.getTargetStateCommitment(input); } - /// @notice Test getTargetBlockHash reverts when not on home chain - function test_getTargetBlockHash_notOnHomeChain() public { + /// @notice Test getTargetStateCommitment reverts when not on home chain + function test_getTargetStateCommitment_notOnHomeChain() public { // Simulate being on a different chain (Scroll L2) vm.chainId(l2ChainId); @@ -97,7 +97,7 @@ contract ScrollChainMock is IScrollChain { bytes memory input = abi.encode(batchIndex); vm.expectRevert(ParentToChildProver.CallNotOnHomeChain.selector); - parentToChildProver.getTargetBlockHash(input); + parentToChildProver.getTargetStateCommitment(input); } /// @notice Test verifyStorageSlot with real proof data @@ -180,7 +180,7 @@ contract ScrollChainMock is IScrollChain { // Step 2: Get the state root (simulating what happens on L1) bytes memory getInput = abi.encode(batchIndex); - bytes32 retrievedStateRoot = parentToChildProver.getTargetBlockHash(getInput); + bytes32 retrievedStateRoot = parentToChildProver.getTargetStateCommitment(getInput); assertEq(retrievedStateRoot, stateRoot, "Retrieved state root should match"); diff --git a/test/provers/taiko/ChildToParentProver.t.sol b/test/provers/taiko/ChildToParentProver.t.sol index 5129901..0f77b4c 100644 --- a/test/provers/taiko/ChildToParentProver.t.sol +++ b/test/provers/taiko/ChildToParentProver.t.sol @@ -5,7 +5,7 @@ import {Test, console} from "forge-std/Test.sol"; import {stdJson} from "forge-std/StdJson.sol"; import {ChildToParentProver} from "../../../src/contracts/provers/taiko/ChildToParentProver.sol"; -/// @notice Mock SignalService for testing getTargetBlockHash +/// @notice Mock SignalService for testing getTargetStateCommitment contract MockSignalService { struct Checkpoint { uint48 blockNumber; @@ -31,7 +31,7 @@ contract MockSignalService { /// @title ChildToParentProver Tests /// @notice Tests for the Taiko ChildToParentProver (L2 → L1 verification) /// @dev Home chain: L2 (Taiko). Target chain: L1 (Ethereum). -/// - getTargetBlockHash: Called on L2 to read L1 block hash from L2's SignalService +/// - getTargetStateCommitment: Called on L2 to read L1 block hash from L2's SignalService /// - verifyTargetBlockHash: Called on L1 to verify L1 block hash via storage proof /// - verifyStorageSlot: Verifies storage slots against a trusted block hash contract TaikoChildToParentProverTest is Test { @@ -89,32 +89,32 @@ contract TaikoChildToParentProverTest is Test { prover.verifyTargetBlockHash(bytes32(0), input); } - function test_getTargetBlockHash_revertsOffHomeChain() public { + function test_getTargetStateCommitment_revertsOffHomeChain() public { vm.chainId(L1_CHAIN_ID); bytes memory input = abi.encode(uint48(0)); vm.expectRevert(ChildToParentProver.CallNotOnHomeChain.selector); - prover.getTargetBlockHash(input); + prover.getTargetStateCommitment(input); } // ═══════════════════════════════════════════════════════════════════════════ - // getTargetBlockHash Tests (Called on L2 to read L1 block hash) + // getTargetStateCommitment Tests (Called on L2 to read L1 block hash) // ═══════════════════════════════════════════════════════════════════════════ - function test_getTargetBlockHash_success() public { + function test_getTargetStateCommitment_success() public { vm.chainId(L2_CHAIN_ID); // Set checkpoint in mock SignalService mockSignalService.setCheckpoint(uint48(L1_BLOCK_NUMBER), L1_BLOCK_HASH, L1_STATE_ROOT); bytes memory input = abi.encode(uint48(L1_BLOCK_NUMBER)); - bytes32 targetBlockHash = prover.getTargetBlockHash(input); + bytes32 targetBlockHash = prover.getTargetStateCommitment(input); assertEq(targetBlockHash, L1_BLOCK_HASH, "targetBlockHash mismatch"); } - function test_getTargetBlockHash_revertsWhenNotFound() public { + function test_getTargetStateCommitment_revertsWhenNotFound() public { vm.chainId(L2_CHAIN_ID); // Don't set any checkpoint - it doesn't exist @@ -122,7 +122,7 @@ contract TaikoChildToParentProverTest is Test { // Reverts with SignalService's SS_CHECKPOINT_NOT_FOUND error vm.expectRevert(MockSignalService.SS_CHECKPOINT_NOT_FOUND.selector); - prover.getTargetBlockHash(input); + prover.getTargetStateCommitment(input); } // ═══════════════════════════════════════════════════════════════════════════ @@ -211,7 +211,7 @@ contract TaikoChildToParentProverTest is Test { /// @dev This test: /// 1. Deploys the prover configured for L2 as home chain /// 2. Sets L2's SignalService with an L1 checkpoint - /// 3. Uses getTargetBlockHash (on L2) to get L1 block hash + /// 3. Uses getTargetStateCommitment (on L2) to get L1 block hash /// 4. Uses verifyStorageSlot to verify L1 Broadcaster storage function test_integration_L1ToL2_verification() public { // Step 1: Configure chain as L2 (home chain) @@ -222,7 +222,7 @@ contract TaikoChildToParentProverTest is Test { // Step 3: Get L1 block hash from L2's SignalService bytes memory getInput = abi.encode(uint48(L1_BLOCK_NUMBER)); - bytes32 l1BlockHash = prover.getTargetBlockHash(getInput); + bytes32 l1BlockHash = prover.getTargetStateCommitment(getInput); assertEq(l1BlockHash, L1_BLOCK_HASH, "L1 block hash mismatch"); // Step 4: Load proof data and verify L1 storage @@ -250,7 +250,7 @@ contract TaikoChildToParentProverTest is Test { // Edge Case Tests // ═══════════════════════════════════════════════════════════════════════════ - function test_getTargetBlockHash_zeroBlockNumber() public { + function test_getTargetStateCommitment_zeroBlockNumber() public { vm.chainId(L2_CHAIN_ID); // Block 0 with no checkpoint should revert @@ -258,7 +258,7 @@ contract TaikoChildToParentProverTest is Test { // Reverts with SignalService's SS_CHECKPOINT_NOT_FOUND error vm.expectRevert(MockSignalService.SS_CHECKPOINT_NOT_FOUND.selector); - prover.getTargetBlockHash(input); + prover.getTargetStateCommitment(input); } function test_constructor_differentParameters() public { diff --git a/test/provers/taiko/ParentToChildProver.t.sol b/test/provers/taiko/ParentToChildProver.t.sol index e6374ff..96859db 100644 --- a/test/provers/taiko/ParentToChildProver.t.sol +++ b/test/provers/taiko/ParentToChildProver.t.sol @@ -5,7 +5,7 @@ import {Test, console} from "forge-std/Test.sol"; import {stdJson} from "forge-std/StdJson.sol"; import {ParentToChildProver} from "../../../src/contracts/provers/taiko/ParentToChildProver.sol"; -/// @notice Mock SignalService for testing getTargetBlockHash +/// @notice Mock SignalService for testing getTargetStateCommitment contract MockSignalService { struct Checkpoint { uint48 blockNumber; @@ -31,7 +31,7 @@ contract MockSignalService { /// @title ParentToChildProver Tests /// @notice Tests for the Taiko ParentToChildProver (L1 → L2 verification) /// @dev Home chain: L1 (Ethereum). Target chain: L2 (Taiko). -/// - getTargetBlockHash: Called on L1 to read L2 block hash from L1's SignalService +/// - getTargetStateCommitment: Called on L1 to read L2 block hash from L1's SignalService /// - verifyTargetBlockHash: Called on L2 to verify L2 block hash via storage proof /// - verifyStorageSlot: Verifies storage slots against a trusted block hash contract TaikoParentToChildProverTest is Test { @@ -89,32 +89,32 @@ contract TaikoParentToChildProverTest is Test { prover.verifyTargetBlockHash(bytes32(0), input); } - function test_getTargetBlockHash_revertsOffHomeChain() public { + function test_getTargetStateCommitment_revertsOffHomeChain() public { vm.chainId(L2_CHAIN_ID); bytes memory input = abi.encode(uint48(0)); vm.expectRevert(ParentToChildProver.CallNotOnHomeChain.selector); - prover.getTargetBlockHash(input); + prover.getTargetStateCommitment(input); } // ═══════════════════════════════════════════════════════════════════════════ - // getTargetBlockHash Tests (Called on L1 to read L2 block hash) + // getTargetStateCommitment Tests (Called on L1 to read L2 block hash) // ═══════════════════════════════════════════════════════════════════════════ - function test_getTargetBlockHash_success() public { + function test_getTargetStateCommitment_success() public { vm.chainId(L1_CHAIN_ID); // Set checkpoint in mock SignalService mockSignalService.setCheckpoint(uint48(L2_BLOCK_NUMBER), L2_BLOCK_HASH, L2_STATE_ROOT); bytes memory input = abi.encode(uint48(L2_BLOCK_NUMBER)); - bytes32 targetBlockHash = prover.getTargetBlockHash(input); + bytes32 targetBlockHash = prover.getTargetStateCommitment(input); assertEq(targetBlockHash, L2_BLOCK_HASH, "targetBlockHash mismatch"); } - function test_getTargetBlockHash_revertsWhenNotFound() public { + function test_getTargetStateCommitment_revertsWhenNotFound() public { vm.chainId(L1_CHAIN_ID); // Don't set any checkpoint - it doesn't exist @@ -122,7 +122,7 @@ contract TaikoParentToChildProverTest is Test { // Reverts with SignalService's SS_CHECKPOINT_NOT_FOUND error vm.expectRevert(MockSignalService.SS_CHECKPOINT_NOT_FOUND.selector); - prover.getTargetBlockHash(input); + prover.getTargetStateCommitment(input); } // ═══════════════════════════════════════════════════════════════════════════ @@ -211,7 +211,7 @@ contract TaikoParentToChildProverTest is Test { /// @dev This test: /// 1. Deploys the prover configured for L1 as home chain /// 2. Sets L1's SignalService with an L2 checkpoint - /// 3. Uses getTargetBlockHash (on L1) to get L2 block hash + /// 3. Uses getTargetStateCommitment (on L1) to get L2 block hash /// 4. Uses verifyStorageSlot to verify L2 Broadcaster storage function test_integration_L2ToL1_verification() public { // Step 1: Configure chain as L1 (home chain) @@ -222,7 +222,7 @@ contract TaikoParentToChildProverTest is Test { // Step 3: Get L2 block hash from L1's SignalService bytes memory getInput = abi.encode(uint48(L2_BLOCK_NUMBER)); - bytes32 l2BlockHash = prover.getTargetBlockHash(getInput); + bytes32 l2BlockHash = prover.getTargetStateCommitment(getInput); assertEq(l2BlockHash, L2_BLOCK_HASH, "L2 block hash mismatch"); // Step 4: Load proof data and verify L2 storage @@ -250,7 +250,7 @@ contract TaikoParentToChildProverTest is Test { // Edge Case Tests // ═══════════════════════════════════════════════════════════════════════════ - function test_getTargetBlockHash_zeroBlockNumber() public { + function test_getTargetStateCommitment_zeroBlockNumber() public { vm.chainId(L1_CHAIN_ID); // Block 0 with no checkpoint should revert @@ -258,7 +258,7 @@ contract TaikoParentToChildProverTest is Test { // Reverts with SignalService's SS_CHECKPOINT_NOT_FOUND error vm.expectRevert(MockSignalService.SS_CHECKPOINT_NOT_FOUND.selector); - prover.getTargetBlockHash(input); + prover.getTargetStateCommitment(input); } function test_constructor_differentParameters() public { @@ -277,7 +277,7 @@ contract TaikoParentToChildProverTest is Test { // Fuzz Tests // ═══════════════════════════════════════════════════════════════════════════ - function testFuzz_getTargetBlockHash_revertsOnUnknownBlock(uint48 blockNumber) public { + function testFuzz_getTargetStateCommitment_revertsOnUnknownBlock(uint48 blockNumber) public { vm.chainId(L1_CHAIN_ID); // Any block number without a mocked checkpoint should revert @@ -285,7 +285,7 @@ contract TaikoParentToChildProverTest is Test { // Reverts with SignalService's SS_CHECKPOINT_NOT_FOUND error vm.expectRevert(MockSignalService.SS_CHECKPOINT_NOT_FOUND.selector); - prover.getTargetBlockHash(input); + prover.getTargetStateCommitment(input); } function testFuzz_constructor_acceptsAnyParameters(address signalService, uint256 slot, uint256 chainId) public { diff --git a/test/provers/zksync/ParentChildToProver.t.sol b/test/provers/zksync/ParentChildToProver.t.sol index 629e0c2..f91ba06 100644 --- a/test/provers/zksync/ParentChildToProver.t.sol +++ b/test/provers/zksync/ParentChildToProver.t.sol @@ -122,7 +122,7 @@ contract ZkSyncParentToChildProverTest is Test { prover.verifyStorageSlot(expectedL2LogsRootHash, abi.encode(proof)); } - function test_getTargetBlockHash() public { + function test_getTargetStateCommitment() public { vm.selectFork(parentForkId); MockZkChain mockZkChain = new MockZkChain(); @@ -130,7 +130,7 @@ contract ZkSyncParentToChildProverTest is Test { ParentToChildProver prover = new ParentToChildProver(address(mockZkChain), 0, 300, 32657, parentChainId); - bytes32 targetL2LogsRootHash = prover.getTargetBlockHash(abi.encode(43984)); + bytes32 targetL2LogsRootHash = prover.getTargetStateCommitment(abi.encode(43984)); assertEq( targetL2LogsRootHash, 0x4cbeceb2a95a01369ab104ec6a305e37cb22d3717abb91da6880e038c3160470, @@ -138,22 +138,22 @@ contract ZkSyncParentToChildProverTest is Test { ); } - function test_getTargetBlockHash_revertsWithNotFound() public { + function test_getTargetStateCommitment_revertsWithNotFound() public { vm.selectFork(parentForkId); MockZkChain mockZkChain = new MockZkChain(); ParentToChildProver prover = new ParentToChildProver(address(mockZkChain), 0, 300, 32657, parentChainId); vm.expectRevert(ParentToChildProver.L2LogsRootHashNotFound.selector); - prover.getTargetBlockHash(abi.encode(43985)); + prover.getTargetStateCommitment(abi.encode(43985)); } - function test_getTargetBlockHash_revertsWithNotInHomeChain() public { + function test_getTargetStateCommitment_revertsWithNotInHomeChain() public { MockZkChain mockZkChain = new MockZkChain(); ParentToChildProver prover = new ParentToChildProver(address(mockZkChain), 0, 300, 32657, parentChainId); vm.expectRevert(ParentToChildProver.NotInHomeChain.selector); - prover.getTargetBlockHash(abi.encode(43985)); + prover.getTargetStateCommitment(abi.encode(43985)); } } From e2494e49f4c09d996f22f2a302752e7bcf7df413 Mon Sep 17 00:00:00 2001 From: Luiz Date: Fri, 23 Jan 2026 10:50:39 -0300 Subject: [PATCH 06/25] rename verifyTargetBlockHash --- scripts/generate-optimism-test-payloads.ts | 2 +- scripts/taiko/README.txt | 2 +- src/contracts/Receiver.sol | 2 +- .../provers/arbitrum/ChildToParentProver.sol | 4 ++-- .../provers/arbitrum/ParentToChildProver.sol | 4 ++-- .../provers/linea/ChildToParentProver.sol | 2 +- .../provers/linea/ParentToChildProver.sol | 6 +++--- .../provers/optimism/ChildToParentProver.sol | 4 ++-- .../provers/optimism/ParentToChildProver.sol | 4 ++-- .../provers/scroll/ChildToParentProver.sol | 4 ++-- .../provers/scroll/ParentToChildProver.sol | 4 ++-- .../provers/taiko/ChildToParentProver.sol | 4 ++-- .../provers/taiko/ParentToChildProver.sol | 4 ++-- .../provers/zksync/ChildToParentProver.sol | 4 ++-- .../provers/zksync/ParentToChildProver.sol | 4 ++-- src/ts/IProverHelper.ts | 4 ++-- src/ts/optimism/ChildToParentProverHelper.ts | 2 +- test/Receiver.t.sol | 16 ++++++++-------- test/mocks/MockProver.sol | 2 +- test/provers/arbitrum/ChildToParentProver.t.sol | 8 ++++---- test/provers/arbitrum/ParentToChildProver.t.sol | 10 ++++++---- test/provers/linea/ParentToChildProver.t.sol | 12 ++++++------ test/provers/optimism/ChildToParentProver.t.sol | 14 +++++++------- test/provers/scroll/ParentToChildProver.t.sol | 6 +++--- test/provers/taiko/ChildToParentProver.t.sol | 16 ++++++++-------- test/provers/taiko/ParentToChildProver.t.sol | 16 ++++++++-------- 26 files changed, 81 insertions(+), 79 deletions(-) diff --git a/scripts/generate-optimism-test-payloads.ts b/scripts/generate-optimism-test-payloads.ts index d63f8db..d0765e0 100644 --- a/scripts/generate-optimism-test-payloads.ts +++ b/scripts/generate-optimism-test-payloads.ts @@ -6,7 +6,7 @@ * * Generates: * - calldata_get.hex: For getTargetStateCommitment() test - * - calldata_verify_target.hex: For verifyTargetBlockHash() test + * - calldata_verify_target.hex: For verifyTargetStateCommitment() test * - calldata_verify_slot.hex: For verifyStorageSlot() test */ diff --git a/scripts/taiko/README.txt b/scripts/taiko/README.txt index 94d2032..0aa95dc 100644 --- a/scripts/taiko/README.txt +++ b/scripts/taiko/README.txt @@ -360,5 +360,5 @@ IMPORTANT NOTES - ParentToChildProver deployed on L1, reads L2 - ChildToParentProver deployed on L2, reads L1 - Both use getTargetStateCommitment in tests (direct SignalService read) -- Production would use verifyTargetBlockHash (with proofs) +- Production would use verifyTargetStateCommitment (with proofs) diff --git a/src/contracts/Receiver.sol b/src/contracts/Receiver.sol index afa0692..fa863e5 100644 --- a/src/contracts/Receiver.sol +++ b/src/contracts/Receiver.sol @@ -138,7 +138,7 @@ contract Receiver is IReceiver { revert ProverCopyNotFound(); } - blockHash = prover.verifyTargetBlockHash(blockHash, readArgs.bhpInputs[i]); + blockHash = prover.verifyTargetStateCommitment(blockHash, readArgs.bhpInputs[i]); } } diff --git a/src/contracts/provers/arbitrum/ChildToParentProver.sol b/src/contracts/provers/arbitrum/ChildToParentProver.sol index 04102dc..3681013 100644 --- a/src/contracts/provers/arbitrum/ChildToParentProver.sol +++ b/src/contracts/provers/arbitrum/ChildToParentProver.sol @@ -7,7 +7,7 @@ import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; /// @notice Arbitrum implementation of a child to parent IStateProver. -/// @dev verifyTargetBlockHash and getTargetStateCommitment get block hashes from the block hash buffer at 0x0000000048C4Ed10cF14A02B9E0AbDDA5227b071. +/// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the block hash buffer at 0x0000000048C4Ed10cF14A02B9E0AbDDA5227b071. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12 for more details. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. contract ChildToParentProver is IStateProver { @@ -30,7 +30,7 @@ contract ChildToParentProver is IStateProver { /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer` using a storage proof /// @param homeBlockHash The block hash of the home chain. /// @param input ABI encoded (bytes blockHeader, uint256 targetBlockNumber, bytes accountProof, bytes storageProof) - function verifyTargetBlockHash(bytes32 homeBlockHash, bytes calldata input) + function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view returns (bytes32 targetBlockHash) diff --git a/src/contracts/provers/arbitrum/ParentToChildProver.sol b/src/contracts/provers/arbitrum/ParentToChildProver.sol index 8147104..9f8fb98 100644 --- a/src/contracts/provers/arbitrum/ParentToChildProver.sol +++ b/src/contracts/provers/arbitrum/ParentToChildProver.sol @@ -7,7 +7,7 @@ import {IOutbox} from "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; /// @notice Arbitrum implementation of a parent to child IStateProver. -/// @dev verifyTargetBlockHash and getTargetStateCommitment get block hashes from the child chain's Outbox contract. +/// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the child chain's Outbox contract. /// verifyStorageSlot is implemented to work against any Arbitrum child chain with a standard Ethereum block header and state trie. contract ParentToChildProver is IStateProver { /// @dev Address of the child chain's Outbox contract @@ -33,7 +33,7 @@ contract ParentToChildProver is IStateProver { /// @notice Verify a target chain block hash given a home chain block hash and a proof. /// @param homeBlockHash The block hash of the home chain. /// @param input ABI encoded (bytes blockHeader, bytes32 sendRoot, bytes accountProof, bytes storageProof) - function verifyTargetBlockHash(bytes32 homeBlockHash, bytes calldata input) + function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view returns (bytes32 targetBlockHash) diff --git a/src/contracts/provers/linea/ChildToParentProver.sol b/src/contracts/provers/linea/ChildToParentProver.sol index 45da062..c3a8eca 100644 --- a/src/contracts/provers/linea/ChildToParentProver.sol +++ b/src/contracts/provers/linea/ChildToParentProver.sol @@ -25,7 +25,7 @@ contract ChildToParentProver is IStateProver { /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer` using a storage proof /// @param homeBlockHash The block hash of the home chain. /// @param input ABI encoded (bytes blockHeader, uint256 targetBlockNumber, bytes accountProof, bytes storageProof) - function verifyTargetBlockHash(bytes32 homeBlockHash, bytes calldata input) + function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view returns (bytes32 targetBlockHash) diff --git a/src/contracts/provers/linea/ParentToChildProver.sol b/src/contracts/provers/linea/ParentToChildProver.sol index 89dac65..a007085 100644 --- a/src/contracts/provers/linea/ParentToChildProver.sol +++ b/src/contracts/provers/linea/ParentToChildProver.sol @@ -17,7 +17,7 @@ interface ILineaRollup { /// @notice Enables verification of Linea L2 state from Ethereum L1 /// @dev Home chain: L1 (Ethereum). Target chain: L2 (Linea). /// On L1: getTargetStateCommitment reads L2 state root directly from LineaRollup -/// On L2: verifyTargetBlockHash proves L2 state root from L1 LineaRollup storage +/// On L2: verifyTargetStateCommitment proves L2 state root from L1 LineaRollup storage /// verifyStorageSlot: Verifies storage against the L2 state root using Sparse Merkle Tree proofs /// /// Note: Linea uses Sparse Merkle Tree (SMT) with MiMC hashing, NOT Merkle-Patricia Trie (MPT). @@ -55,7 +55,7 @@ contract ParentToChildProver is IStateProver { /// @param homeBlockHash The L1 block hash /// @param input ABI encoded (bytes rlpBlockHeader, uint256 l2BlockNumber, bytes accountProof, bytes storageProof) /// @return targetBlockHash The L2 state root (named "blockHash" for interface compatibility) - function verifyTargetBlockHash(bytes32 homeBlockHash, bytes calldata input) + function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view returns (bytes32 targetBlockHash) @@ -123,7 +123,7 @@ contract ParentToChildProver is IStateProver { /// 5. The storage proof corresponds to the claimed slot (hKey check) /// 6. The storage value matches the proof's hValue /// - /// @param targetBlockHash The L2 SMT state root (from getTargetStateCommitment or verifyTargetBlockHash) + /// @param targetBlockHash The L2 SMT state root (from getTargetStateCommitment or verifyTargetStateCommitment) /// @param input ABI encoded proof data from linea_getProof /// @return account The address of the account on L2 /// @return slot The storage slot diff --git a/src/contracts/provers/optimism/ChildToParentProver.sol b/src/contracts/provers/optimism/ChildToParentProver.sol index ebd9011..82dc39a 100644 --- a/src/contracts/provers/optimism/ChildToParentProver.sol +++ b/src/contracts/provers/optimism/ChildToParentProver.sol @@ -9,7 +9,7 @@ interface IL1Block { } /// @notice OP-stack implementation of a child to parent IStateProver. -/// @dev verifyTargetBlockHash and getTargetStateCommitment get block hashes from the L1Block predeploy. +/// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the L1Block predeploy. /// verifyStorageSlot is implemented to work against any target chain with a standard Ethereum block header and state trie. /// /// @dev Note: L1Block only stores the LATEST L1 block hash. @@ -33,7 +33,7 @@ contract ChildToParentProver is IStateProver { /// @notice Verify the latest available target block hash given a home chain block hash and a storage proof of the L1Block predeploy. /// @param homeBlockHash The block hash of the home chain. /// @param input ABI encoded (bytes blockHeader, bytes accountProof, bytes storageProof) - function verifyTargetBlockHash(bytes32 homeBlockHash, bytes calldata input) + function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view returns (bytes32 targetBlockHash) diff --git a/src/contracts/provers/optimism/ParentToChildProver.sol b/src/contracts/provers/optimism/ParentToChildProver.sol index 1a90f32..4d50855 100644 --- a/src/contracts/provers/optimism/ParentToChildProver.sol +++ b/src/contracts/provers/optimism/ParentToChildProver.sol @@ -16,7 +16,7 @@ interface IFaultDisputeGame { } /// @notice OP-stack implementation of a parent to child IStateProver. -/// @dev verifyTargetBlockHash and getTargetStateCommitment get block hashes from a valid fault dispute game proxy contract. +/// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from a valid fault dispute game proxy contract. /// verifyStorageSlot is implemented to work against any OP-stack child chain with a standard Ethereum block header and state trie. contract ParentToChildProver is IStateProver { using Lib_RLPReader for Lib_RLPReader.RLPItem; @@ -59,7 +59,7 @@ contract ParentToChildProver is IStateProver { /// bytes gameProxyAccountProof, /// bytes gameProxyCode, /// bytes rootClaimPreimage) - function verifyTargetBlockHash(bytes32 homeBlockHash, bytes calldata input) + function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view returns (bytes32 targetBlockHash) diff --git a/src/contracts/provers/scroll/ChildToParentProver.sol b/src/contracts/provers/scroll/ChildToParentProver.sol index ed28b15..6c92309 100644 --- a/src/contracts/provers/scroll/ChildToParentProver.sol +++ b/src/contracts/provers/scroll/ChildToParentProver.sol @@ -7,7 +7,7 @@ import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; /// @notice implementation of a child to parent IStateProver. -/// @dev verifyTargetBlockHash and getTargetStateCommitment get block hashes from the block hash buffer on Scroll. +/// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the block hash buffer on Scroll. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12 for more details. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. contract ChildToParentProver is IStateProver { @@ -29,7 +29,7 @@ contract ChildToParentProver is IStateProver { /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer` using a storage proof /// @param homeBlockHash The block hash of the home chain. /// @param input ABI encoded (bytes blockHeader, uint256 targetBlockNumber, bytes accountProof, bytes storageProof) - function verifyTargetBlockHash(bytes32 homeBlockHash, bytes calldata input) + function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view returns (bytes32 targetBlockHash) diff --git a/src/contracts/provers/scroll/ParentToChildProver.sol b/src/contracts/provers/scroll/ParentToChildProver.sol index 1aaf867..0362097 100644 --- a/src/contracts/provers/scroll/ParentToChildProver.sol +++ b/src/contracts/provers/scroll/ParentToChildProver.sol @@ -21,7 +21,7 @@ interface IScrollChain { /// @notice Scroll implementation of a parent to child IStateProver. /// @dev Home chain: L1 (Ethereum). Target chain: L2 (Scroll). /// getTargetStateCommitment reads finalized L2 state roots directly from L1's ScrollChain. -/// verifyTargetBlockHash verifies L2 state roots via storage proof against L1's ScrollChain. +/// verifyTargetStateCommitment verifies L2 state roots via storage proof against L1's ScrollChain. /// verifyStorageSlot verifies storage against the L2 state root using standard MPT proofs. /// /// NOTE: Unlike other provers that return block hashes, Scroll stores STATE ROOTS directly @@ -59,7 +59,7 @@ contract ParentToChildProver is IStateProver { /// @param homeBlockHash The L1 block hash /// @param input ABI encoded (bytes rlpBlockHeader, uint256 batchIndex, bytes accountProof, bytes storageProof) /// @return targetBlockHash The L2 state root stored in L1's ScrollChain (NOTE: this is a state root, not a block hash) - function verifyTargetBlockHash(bytes32 homeBlockHash, bytes calldata input) + function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view returns (bytes32 targetBlockHash) diff --git a/src/contracts/provers/taiko/ChildToParentProver.sol b/src/contracts/provers/taiko/ChildToParentProver.sol index 534f67b..c147767 100644 --- a/src/contracts/provers/taiko/ChildToParentProver.sol +++ b/src/contracts/provers/taiko/ChildToParentProver.sol @@ -17,7 +17,7 @@ interface ICheckpointStore { /// @notice Taiko implementation of a child to parent IStateProver. /// @dev Home chain: L2 (Taiko). Target chain: L1 (Ethereum). -/// verifyTargetBlockHash gets L1 block hashes from L2's SignalService checkpoint storage. +/// verifyTargetStateCommitment gets L1 block hashes from L2's SignalService checkpoint storage. /// getTargetStateCommitment reads L1 block hashes directly from L2's SignalService. /// verifyStorageSlot works against any Ethereum-compatible chain with standard block headers. contract ChildToParentProver is IStateProver { @@ -47,7 +47,7 @@ contract ChildToParentProver is IStateProver { /// @param homeBlockHash The L2 block hash /// @param input ABI encoded (bytes rlpBlockHeader, uint48 l1BlockNumber, bytes accountProof, bytes storageProof) /// @return targetBlockHash The L1 block hash stored in L2's SignalService - function verifyTargetBlockHash(bytes32 homeBlockHash, bytes calldata input) + function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view returns (bytes32 targetBlockHash) diff --git a/src/contracts/provers/taiko/ParentToChildProver.sol b/src/contracts/provers/taiko/ParentToChildProver.sol index 6be84ea..aa86227 100644 --- a/src/contracts/provers/taiko/ParentToChildProver.sol +++ b/src/contracts/provers/taiko/ParentToChildProver.sol @@ -17,7 +17,7 @@ interface ICheckpointStore { /// @notice Taiko implementation of a parent to child IStateProver. /// @dev Home chain: L1 (Ethereum). Target chain: L2 (Taiko). -/// verifyTargetBlockHash gets L2 block hashes from L1's SignalService checkpoint storage. +/// verifyTargetStateCommitment gets L2 block hashes from L1's SignalService checkpoint storage. /// getTargetStateCommitment reads L2 block hashes directly from L1's SignalService. /// verifyStorageSlot works against any Ethereum-compatible chain with standard block headers. contract ParentToChildProver is IStateProver { @@ -47,7 +47,7 @@ contract ParentToChildProver is IStateProver { /// @param homeBlockHash The L1 block hash /// @param input ABI encoded (bytes rlpBlockHeader, uint48 l2BlockNumber, bytes accountProof, bytes storageProof) /// @return targetBlockHash The L2 block hash stored in L1's SignalService - function verifyTargetBlockHash(bytes32 homeBlockHash, bytes calldata input) + function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view returns (bytes32 targetBlockHash) diff --git a/src/contracts/provers/zksync/ChildToParentProver.sol b/src/contracts/provers/zksync/ChildToParentProver.sol index aff075c..b05a5d6 100644 --- a/src/contracts/provers/zksync/ChildToParentProver.sol +++ b/src/contracts/provers/zksync/ChildToParentProver.sol @@ -7,7 +7,7 @@ import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; /// @notice implementation of a child to parent IStateProver. -/// @dev verifyTargetBlockHash and getTargetStateCommitment get block hashes from the block hash buffer on ZkSync. +/// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the block hash buffer on ZkSync. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12 for more details. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. contract ChildToParentProver is IStateProver { @@ -29,7 +29,7 @@ contract ChildToParentProver is IStateProver { /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer` using a storage proof /// @param homeBlockHash The block hash of the home chain. /// @param input ABI encoded (bytes blockHeader, uint256 targetBlockNumber, bytes accountProof, bytes storageProof) - function verifyTargetBlockHash(bytes32 homeBlockHash, bytes calldata input) + function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view returns (bytes32 targetBlockHash) diff --git a/src/contracts/provers/zksync/ParentToChildProver.sol b/src/contracts/provers/zksync/ParentToChildProver.sol index e15fb5b..c2db99c 100644 --- a/src/contracts/provers/zksync/ParentToChildProver.sol +++ b/src/contracts/provers/zksync/ParentToChildProver.sol @@ -56,7 +56,7 @@ struct ZkSyncProof { /// @notice ZkSync implementation of a parent to child IStateProver. /// @dev This contract verifies L2 logs root hashes from ZkSync child chains on the parent chain (L1). -/// The `verifyTargetBlockHash` and `getTargetStateCommitment` functions retrieve L2 logs root hashes +/// The `verifyTargetStateCommitment` and `getTargetStateCommitment` functions retrieve L2 logs root hashes /// from the child chain's ZkChain contract. The `verifyStorageSlot` function is implemented /// to work against any ZkSync child chain with a standard Ethereum block header and state trie. /// This implementation is used to verify zkChain L2 log hash inclusion on L1 for messages that @@ -118,7 +118,7 @@ contract ParentToChildProver is IStateProver { /// - batchNumber: The batch number for which to retrieve the L2 logs root hash. /// - storageProof: Storage proof for the storage slot containing the L2 logs root hash. /// @return targetL2LogsRootHash The L2 logs root hash for the specified batch number. - function verifyTargetBlockHash(bytes32 homeBlockHash, bytes calldata input) + function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view returns (bytes32 targetL2LogsRootHash) diff --git a/src/ts/IProverHelper.ts b/src/ts/IProverHelper.ts index 2621319..8ce8a8a 100644 --- a/src/ts/IProverHelper.ts +++ b/src/ts/IProverHelper.ts @@ -17,8 +17,8 @@ export interface IProverHelper { }> /** - * Build the bytes input argument for the IStateProver::verifyTargetBlockHash function. - * Finds the newest block hash that can be returned by verifyTargetBlockHash on the prover given the home block hash. + * Build the bytes input argument for the IStateProver::verifyTargetStateCommitment function. + * Finds the newest block hash that can be returned by verifyTargetStateCommitment on the prover given the home block hash. * @param homeBlockHash Home chain block hash that will be passed to the prover and proven against */ buildInputForVerifyTargetBlockHash( diff --git a/src/ts/optimism/ChildToParentProverHelper.ts b/src/ts/optimism/ChildToParentProverHelper.ts index 76e6719..7db8969 100644 --- a/src/ts/optimism/ChildToParentProverHelper.ts +++ b/src/ts/optimism/ChildToParentProverHelper.ts @@ -46,7 +46,7 @@ export class OptimismChildToParentProverHelper } /** - * Build input for verifyTargetBlockHash() + * Build input for verifyTargetStateCommitment() * This requires Merkle proofs of the L1Block predeploy's storage */ async buildInputForVerifyTargetBlockHash( diff --git a/test/Receiver.t.sol b/test/Receiver.t.sol index 010874b..8dd1f74 100644 --- a/test/Receiver.t.sol +++ b/test/Receiver.t.sol @@ -531,9 +531,9 @@ contract ReceiverTest is Test { // Construct the route to verify a message broadcasted on Arbitrum chain in OP // We need to construct three inputs: one for OPChildToParentProver getTargetStateCommitment, - // one for ArbParentToChildProver verifyTargetBlockHash, and one for ArbParentToChildProver verifyStorageSlot + // one for ArbParentToChildProver verifyTargetStateCommitment, and one for ArbParentToChildProver verifyStorageSlot // the input to verifyStorageSlot is the proof of the broadcasted message itself. - // the input for verifyTargetBlockHash is the storage proof of the slot on the outbox contract. + // the input for verifyTargetStateCommitment is the storage proof of the slot on the outbox contract. string memory pathEthereum = "test/payloads/ethereum/output_storage_proof_block_9567705.json"; @@ -761,9 +761,9 @@ contract ReceiverTest is Test { // Construct the route to verify a message broadcasted on Arbitrum chain in ZkSync // We need to construct three inputs: one for ZksyncChildToParentProver getTargetStateCommitment, - // one for ArbParentToChildProver verifyTargetBlockHash, and one for ArbParentToChildProver verifyStorageSlot + // one for ArbParentToChildProver verifyTargetStateCommitment, and one for ArbParentToChildProver verifyStorageSlot // the input to verifyStorageSlot is the proof of the broadcasted message itself. - // the input for verifyTargetBlockHash is the storage proof of the slot on the outbox contract. + // the input for verifyTargetStateCommitment is the storage proof of the slot on the outbox contract. string memory pathEthereum = "test/payloads/ethereum/output_storage_proof_block_9567705.json"; @@ -989,9 +989,9 @@ contract ReceiverTest is Test { // Construct the route to verify a message broadcasted on Arbitrum chain in Linea // We need to construct three inputs: one for LineaChildToParentProver getTargetStateCommitment, - // one for ArbParentToChildProver verifyTargetBlockHash, and one for ArbParentToChildProver verifyStorageSlot + // one for ArbParentToChildProver verifyTargetStateCommitment, and one for ArbParentToChildProver verifyStorageSlot // the input to verifyStorageSlot is the proof of the broadcasted message itself. - // the input for verifyTargetBlockHash is the storage proof of the slot on the outbox contract. + // the input for verifyTargetStateCommitment is the storage proof of the slot on the outbox contract. string memory pathEthereum = "test/payloads/ethereum/output_storage_proof_block_9567705.json"; @@ -1217,9 +1217,9 @@ contract ReceiverTest is Test { // Construct the route to verify a message broadcasted on Arbitrum chain in Scroll // We need to construct three inputs: one for ScrollChildToParentProver getTargetStateCommitment, - // one for ArbParentToChildProver verifyTargetBlockHash, and one for ArbParentToChildProver verifyStorageSlot + // one for ArbParentToChildProver verifyTargetStateCommitment, and one for ArbParentToChildProver verifyStorageSlot // the input to verifyStorageSlot is the proof of the broadcasted message itself. - // the input for verifyTargetBlockHash is the storage proof of the slot on the outbox contract. + // the input for verifyTargetStateCommitment is the storage proof of the slot on the outbox contract. string memory pathEthereum = "test/payloads/ethereum/output_storage_proof_block_9567705.json"; diff --git a/test/mocks/MockProver.sol b/test/mocks/MockProver.sol index 7923734..ae6ab86 100644 --- a/test/mocks/MockProver.sol +++ b/test/mocks/MockProver.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.30; import {IStateProver} from "src/contracts/interfaces/IStateProver.sol"; contract MockProver is IStateProver { - function verifyTargetBlockHash( + function verifyTargetStateCommitment( bytes32 homeBlockHash, bytes calldata /*input*/ ) diff --git a/test/provers/arbitrum/ChildToParentProver.t.sol b/test/provers/arbitrum/ChildToParentProver.t.sol index 6754b70..5f09a02 100644 --- a/test/provers/arbitrum/ChildToParentProver.t.sol +++ b/test/provers/arbitrum/ChildToParentProver.t.sol @@ -159,7 +159,7 @@ contract BroadcasterTest is Test { childToParentProver.getTargetStateCommitment(abi.encode(input)); } - function test_verifyTargetBlockHash() public { + function test_verifyTargetStateCommitment() public { vm.selectFork(parentForkId); bytes memory payload = _loadPayload("test/payloads/arbitrum/calldata_verify_target.hex"); @@ -178,12 +178,12 @@ contract BroadcasterTest is Test { targetBlockHash := mload(add(payload, 0x40)) } - bytes32 result = childToParentProverCopy.verifyTargetBlockHash(homeBlockHash, input); + bytes32 result = childToParentProverCopy.verifyTargetStateCommitment(homeBlockHash, input); assertEq(result, targetBlockHash); } - function test_verifyTargetBlockHash_reverts_on_home_chain() public { + function test_verifyTargetStateCommitment_reverts_on_home_chain() public { vm.selectFork(childForkId); bytes memory payload = _loadPayload("test/payloads/arbitrum/calldata_verify_target.hex"); @@ -203,7 +203,7 @@ contract BroadcasterTest is Test { } vm.expectRevert(ChildToParentProver.CallOnHomeChain.selector); - childToParentProverCopy.verifyTargetBlockHash(homeBlockHash, input); + childToParentProverCopy.verifyTargetStateCommitment(homeBlockHash, input); } function test_verifyStorageSlot() public { diff --git a/test/provers/arbitrum/ParentToChildProver.t.sol b/test/provers/arbitrum/ParentToChildProver.t.sol index 532bbd0..abd5c1b 100644 --- a/test/provers/arbitrum/ParentToChildProver.t.sol +++ b/test/provers/arbitrum/ParentToChildProver.t.sol @@ -95,7 +95,7 @@ contract ArbitrumParentToChildProverTest is Test { assertEq(result, expectedTargetBlockHash, "getTargetStateCommitment should return correct Arbitrum block hash"); } - function test_verifyTargetBlockHash() public { + function test_verifyTargetStateCommitment() public { vm.selectFork(parentForkId); uint256 proverHomeChainId = block.chainid; ParentToChildProver prover = new ParentToChildProver(address(outbox), rootSlot, proverHomeChainId); @@ -116,11 +116,13 @@ contract ArbitrumParentToChildProverTest is Test { bytes memory input = abi.encode(rlpBlockHeader, sendRoot, rlpAccountProof, rlpStorageProof); bytes32 expectedTargetBlockHash = 0xcb53c786e7e875d7e3b1d3a770adbe02877ee5daab2ebfa55b935798b3ee9d24; - // verifyTargetBlockHash MUST be called off the prover's home chain. + // verifyTargetStateCommitment MUST be called off the prover's home chain. vm.chainId(proverHomeChainId + 1); - bytes32 result = prover.verifyTargetBlockHash(homeBlockHash, input); - assertEq(result, expectedTargetBlockHash, "verifyTargetBlockHash should return correct Arbitrum block hash"); + bytes32 result = prover.verifyTargetStateCommitment(homeBlockHash, input); + assertEq( + result, expectedTargetBlockHash, "verifyTargetStateCommitment should return correct Arbitrum block hash" + ); } function test_verifyStorageSlot() public { diff --git a/test/provers/linea/ParentToChildProver.t.sol b/test/provers/linea/ParentToChildProver.t.sol index 04c87c4..260c103 100644 --- a/test/provers/linea/ParentToChildProver.t.sol +++ b/test/provers/linea/ParentToChildProver.t.sol @@ -121,20 +121,20 @@ contract LineaParentToChildProverTest is Test { } // ═══════════════════════════════════════════════════════════════════════════ - // verifyTargetBlockHash Tests (Non-Home Chain) + // verifyTargetStateCommitment Tests (Non-Home Chain) // ═══════════════════════════════════════════════════════════════════════════ - function test_verifyTargetBlockHash_revertsOnHomeChain() public { - // On L1 (home chain), verifyTargetBlockHash should revert + function test_verifyTargetStateCommitment_revertsOnHomeChain() public { + // On L1 (home chain), verifyTargetStateCommitment should revert vm.chainId(ETH_MAINNET_CHAIN_ID); vm.expectRevert(ParentToChildProver.CallOnHomeChain.selector); - prover.verifyTargetBlockHash(bytes32(0), bytes("")); + prover.verifyTargetStateCommitment(bytes32(0), bytes("")); } /// @dev This test requires a real storage proof from L1 LineaRollup /// For now, we test that the function reverts with invalid proofs - function test_verifyTargetBlockHash_revertsWithInvalidProof() public { + function test_verifyTargetStateCommitment_revertsWithInvalidProof() public { vm.chainId(LINEA_MAINNET_CHAIN_ID); bytes memory input = abi.encode( @@ -146,7 +146,7 @@ contract LineaParentToChildProverTest is Test { // Should revert due to invalid proof vm.expectRevert(); - prover.verifyTargetBlockHash(bytes32(uint256(1)), input); + prover.verifyTargetStateCommitment(bytes32(uint256(1)), input); } // ═══════════════════════════════════════════════════════════════════════════ diff --git a/test/provers/optimism/ChildToParentProver.t.sol b/test/provers/optimism/ChildToParentProver.t.sol index a3c332f..93584e2 100644 --- a/test/provers/optimism/ChildToParentProver.t.sol +++ b/test/provers/optimism/ChildToParentProver.t.sol @@ -78,12 +78,12 @@ contract OptimismChildToParentProverTest is Test { newChildToParentProver.getTargetStateCommitment(abi.encode(input)); } - /// @notice Test verifyTargetBlockHash() - uses Merkle proofs + /// @notice Test verifyTargetStateCommitment() - uses Merkle proofs /// @dev Currently skipped due to memory allocation issues during proof decoding /// The underlying Merkle proof verification logic IS tested in Arbitrum tests. /// Root cause: Likely an ABI decoding issue with the specific proof structure from Optimism. /// The ProverUtils.getSlotFromBlockHeader() function is identical for both chains. - function skip_test_verifyTargetBlockHash() public { + function skip_test_verifyTargetStateCommitment() public { vm.selectFork(parentForkId); // Run verification on Ethereum bytes memory payload = _loadPayload("test/payloads/optimism/calldata_verify_target.hex"); @@ -101,13 +101,13 @@ contract OptimismChildToParentProverTest is Test { targetBlockHash := mload(add(payload, 0x40)) } - bytes32 result = childToParentProverCopy.verifyTargetBlockHash(homeBlockHash, input); + bytes32 result = childToParentProverCopy.verifyTargetStateCommitment(homeBlockHash, input); assertEq(result, targetBlockHash, "Target block hash should match"); } - /// @notice Test verifyTargetBlockHash() reverts when called on home chain (Optimism) - function test_verifyTargetBlockHash_reverts_on_home_chain() public { + /// @notice Test verifyTargetStateCommitment() reverts when called on home chain (Optimism) + function test_verifyTargetStateCommitment_reverts_on_home_chain() public { vm.selectFork(childForkId); // On Optimism (home chain) bytes memory payload = _loadPayload("test/payloads/optimism/calldata_verify_target.hex"); @@ -125,13 +125,13 @@ contract OptimismChildToParentProverTest is Test { // Should revert because we're on Optimism (home chain) vm.expectRevert(ChildToParentProver.CallOnHomeChain.selector); - childToParentProverCopy.verifyTargetBlockHash(homeBlockHash, input); + childToParentProverCopy.verifyTargetStateCommitment(homeBlockHash, input); } /// @notice Test verifyStorageSlot() - verifies Ethereum storage from Optimism /// @dev Currently skipped due to memory allocation issues during proof decoding /// The underlying storage proof verification logic IS tested in Arbitrum tests. - /// Root cause: Same ABI decoding issue as skip_test_verifyTargetBlockHash. + /// Root cause: Same ABI decoding issue as skip_test_verifyTargetStateCommitment. /// The ProverUtils.getSlotFromBlockHeader() function is identical for both chains. function skip_test_verifyStorageSlot() public { vm.selectFork(parentForkId); // Run on Ethereum diff --git a/test/provers/scroll/ParentToChildProver.t.sol b/test/provers/scroll/ParentToChildProver.t.sol index a2a2fe8..dc0df58 100644 --- a/test/provers/scroll/ParentToChildProver.t.sol +++ b/test/provers/scroll/ParentToChildProver.t.sol @@ -194,8 +194,8 @@ contract ScrollChainMock is IScrollChain { assertEq(actualValue, expectedValue, "value mismatch"); } - /// @notice Test verifyTargetBlockHash reverts when called on home chain - function test_verifyTargetBlockHash_onHomeChain() public { + /// @notice Test verifyTargetStateCommitment reverts when called on home chain + function test_verifyTargetStateCommitment_onHomeChain() public { vm.selectFork(l1ForkId); bytes32 homeBlockHash = bytes32(uint256(1)); @@ -207,7 +207,7 @@ contract ScrollChainMock is IScrollChain { ); vm.expectRevert(ParentToChildProver.CallOnHomeChain.selector); - parentToChildProver.verifyTargetBlockHash(homeBlockHash, input); + parentToChildProver.verifyTargetStateCommitment(homeBlockHash, input); } /// @notice Test version returns 1 diff --git a/test/provers/taiko/ChildToParentProver.t.sol b/test/provers/taiko/ChildToParentProver.t.sol index 0f77b4c..806bc36 100644 --- a/test/provers/taiko/ChildToParentProver.t.sol +++ b/test/provers/taiko/ChildToParentProver.t.sol @@ -32,7 +32,7 @@ contract MockSignalService { /// @notice Tests for the Taiko ChildToParentProver (L2 → L1 verification) /// @dev Home chain: L2 (Taiko). Target chain: L1 (Ethereum). /// - getTargetStateCommitment: Called on L2 to read L1 block hash from L2's SignalService -/// - verifyTargetBlockHash: Called on L1 to verify L1 block hash via storage proof +/// - verifyTargetStateCommitment: Called on L1 to verify L1 block hash via storage proof /// - verifyStorageSlot: Verifies storage slots against a trusted block hash contract TaikoChildToParentProverTest is Test { using stdJson for string; @@ -80,13 +80,13 @@ contract TaikoChildToParentProverTest is Test { // Chain ID Validation Tests // ═══════════════════════════════════════════════════════════════════════════ - function test_verifyTargetBlockHash_revertsOnHomeChain() public { + function test_verifyTargetStateCommitment_revertsOnHomeChain() public { vm.chainId(L2_CHAIN_ID); bytes memory input = abi.encode(bytes(""), uint48(0), bytes(""), bytes("")); vm.expectRevert(ChildToParentProver.CallOnHomeChain.selector); - prover.verifyTargetBlockHash(bytes32(0), input); + prover.verifyTargetStateCommitment(bytes32(0), input); } function test_getTargetStateCommitment_revertsOffHomeChain() public { @@ -172,17 +172,17 @@ contract TaikoChildToParentProverTest is Test { } // ═══════════════════════════════════════════════════════════════════════════ - // verifyTargetBlockHash Tests (Called on L1 to verify via storage proof) + // verifyTargetStateCommitment Tests (Called on L1 to verify via storage proof) // ═══════════════════════════════════════════════════════════════════════════ - /// @notice Test verifyTargetBlockHash with mocked L2 state + /// @notice Test verifyTargetStateCommitment with mocked L2 state /// @dev This simulates being on L1 and verifying that L2's SignalService /// contains a checkpoint for a specific L1 block - function test_verifyTargetBlockHash_withMockedProof() public { + function test_verifyTargetStateCommitment_withMockedProof() public { // Simulate being on L1 (not home chain) vm.chainId(L1_CHAIN_ID); - // For verifyTargetBlockHash, we need: + // For verifyTargetStateCommitment, we need: // 1. An L2 block hash (homeBlockHash) - the trusted anchor // 2. Proof that L2's SignalService contains the L1 checkpoint @@ -200,7 +200,7 @@ contract TaikoChildToParentProverTest is Test { // This will revert because the proof is invalid, but it proves we're past chain ID check vm.expectRevert(); // Will revert on invalid RLP/proof - prover.verifyTargetBlockHash(bytes32(uint256(1)), input); + prover.verifyTargetStateCommitment(bytes32(uint256(1)), input); } // ═══════════════════════════════════════════════════════════════════════════ diff --git a/test/provers/taiko/ParentToChildProver.t.sol b/test/provers/taiko/ParentToChildProver.t.sol index 96859db..116b943 100644 --- a/test/provers/taiko/ParentToChildProver.t.sol +++ b/test/provers/taiko/ParentToChildProver.t.sol @@ -32,7 +32,7 @@ contract MockSignalService { /// @notice Tests for the Taiko ParentToChildProver (L1 → L2 verification) /// @dev Home chain: L1 (Ethereum). Target chain: L2 (Taiko). /// - getTargetStateCommitment: Called on L1 to read L2 block hash from L1's SignalService -/// - verifyTargetBlockHash: Called on L2 to verify L2 block hash via storage proof +/// - verifyTargetStateCommitment: Called on L2 to verify L2 block hash via storage proof /// - verifyStorageSlot: Verifies storage slots against a trusted block hash contract TaikoParentToChildProverTest is Test { using stdJson for string; @@ -80,13 +80,13 @@ contract TaikoParentToChildProverTest is Test { // Chain ID Validation Tests // ═══════════════════════════════════════════════════════════════════════════ - function test_verifyTargetBlockHash_revertsOnHomeChain() public { + function test_verifyTargetStateCommitment_revertsOnHomeChain() public { vm.chainId(L1_CHAIN_ID); bytes memory input = abi.encode(bytes(""), uint48(0), bytes(""), bytes("")); vm.expectRevert(ParentToChildProver.CallOnHomeChain.selector); - prover.verifyTargetBlockHash(bytes32(0), input); + prover.verifyTargetStateCommitment(bytes32(0), input); } function test_getTargetStateCommitment_revertsOffHomeChain() public { @@ -172,17 +172,17 @@ contract TaikoParentToChildProverTest is Test { } // ═══════════════════════════════════════════════════════════════════════════ - // verifyTargetBlockHash Tests (Called on L2 to verify via storage proof) + // verifyTargetStateCommitment Tests (Called on L2 to verify via storage proof) // ═══════════════════════════════════════════════════════════════════════════ - /// @notice Test verifyTargetBlockHash with mocked L1 state + /// @notice Test verifyTargetStateCommitment with mocked L1 state /// @dev This simulates being on L2 and verifying that L1's SignalService /// contains a checkpoint for a specific L2 block - function test_verifyTargetBlockHash_withMockedProof() public { + function test_verifyTargetStateCommitment_withMockedProof() public { // Simulate being on L2 (not home chain) vm.chainId(L2_CHAIN_ID); - // For verifyTargetBlockHash, we need: + // For verifyTargetStateCommitment, we need: // 1. An L1 block hash (homeBlockHash) - the trusted anchor // 2. Proof that L1's SignalService contains the L2 checkpoint @@ -200,7 +200,7 @@ contract TaikoParentToChildProverTest is Test { // This will revert because the proof is invalid, but it proves we're past chain ID check vm.expectRevert(); // Will revert on invalid RLP/proof - prover.verifyTargetBlockHash(bytes32(uint256(1)), input); + prover.verifyTargetStateCommitment(bytes32(uint256(1)), input); } // ═══════════════════════════════════════════════════════════════════════════ From 0411b3032249f3a86613cfdee34c933a45791338 Mon Sep 17 00:00:00 2001 From: Luiz Date: Mon, 26 Jan 2026 11:52:25 -0300 Subject: [PATCH 07/25] renamings --- README.md | 28 ++-- scripts/taiko/README.txt | 10 +- scripts/taiko/deploy-all.s.sol | 6 +- scripts/taiko/deploy.sh | 16 +- scripts/taiko/provers-l2.s.sol | 4 +- scripts/taiko/provers.s.sol | 4 +- scripts/taiko/verify-message.s.sol | 6 +- scripts/taiko/verify-on-chain.s.sol | 12 +- src/contracts/Receiver.sol | 42 ++--- ...overPointer.sol => StateProverPointer.sol} | 14 +- test/BlockHashProverPointer.t.sol | 14 +- test/Receiver.Taiko.t.sol | 28 ++-- test/Receiver.ethereum.t.sol | 20 +-- test/Receiver.t.sol | 150 +++++++++--------- test/VerifyBroadcastMessageBenchmark.t.sol | 52 +++--- 15 files changed, 203 insertions(+), 203 deletions(-) rename src/contracts/{BlockHashProverPointer.sol => StateProverPointer.sol} (88%) diff --git a/README.md b/README.md index fe77cd9..253b1a6 100644 --- a/README.md +++ b/README.md @@ -3,40 +3,40 @@ Ethereum reference implementation for [ERC-7888: Crosschain Broadcaster](https://eips.ethereum.org/EIPS/eip-7888). The standard defines a storage-proof based way to publish 32-byte messages on one chain and verify their existence on any other chain that shares a common ancestor. - **Broadcast**: `Broadcaster` stores `block.timestamp` in slot `keccak(message, publisher)`, emits `MessageBroadcast`, and prevents duplicates per publisher. -- **Prove**: `Receiver` walks a user-specified route of `BlockHashProver` contracts to recover a finalized target block hash, proves a storage slot on a remote `Broadcaster`, checks the slot is non-zero and matches the expected `(message, publisher)` slot, then returns the timestamp. -- **Upgrade safely**: `BlockHashProverPointer` holds the latest prover implementation address and code hash in a fixed slot (`BLOCK_HASH_PROVER_POINTER_SLOT`), enforcing monotonic `version()` upgrades so routes stay stable while provers evolve. -- **Reusable proving code**: `BlockHashProver` copies can be deployed on any chain; the pointer-stored code hash guarantees the copy matches the canonical implementation. +- **Prove**: `Receiver` walks a user-specified route of `StateProver` contracts to recover a finalized target block hash, proves a storage slot on a remote `Broadcaster`, checks the slot is non-zero and matches the expected `(message, publisher)` slot, then returns the timestamp. +- **Upgrade safely**: `StateProverPointer` holds the latest prover implementation address and code hash in a fixed slot (`BLOCK_HASH_PROVER_POINTER_SLOT`), enforcing monotonic `version()` upgrades so routes stay stable while provers evolve. +- **Reusable proving code**: `StateProver` copies can be deployed on any chain; the pointer-stored code hash guarantees the copy matches the canonical implementation. ## Contracts - `src/contracts/Broadcaster.sol`: Minimal broadcaster with deduplication and timestamp storage. - `src/contracts/Receiver.sol`: Verifies broadcast messages from remote chains using a route of block-hash provers and a final storage proof; can cache prover copies. -- `src/contracts/BlockHashProverPointer.sol`: Ownable pointer storing the current prover implementation address and code hash with version monotonicity checks. +- `src/contracts/StateProverPointer.sol`: Ownable pointer storing the current prover implementation address and code hash with version monotonicity checks. - `src/contracts/libraries/ProverUtils.sol`: Shared helpers for verifying block headers and MPT proofs (state root, account data, storage slot). - Interfaces: `IBroadcaster`, `IReceiver`, `IStateProver`, `IStateProverPointer`. ## Key concepts - **Broadcaster**: Singleton per chain that timestamps 32-byte messages in deterministic slots and emits `MessageBroadcast`. - **Receiver**: Trustlessly reads a remote `Broadcaster` slot by following a prover route, checking slot correctness, and returning `(broadcasterId, timestamp)`. -- **BlockHashProver**: Chain-specific verifier that proves a target block hash from a home chain state root and verifies arbitrary storage for that block. -- **BlockHashProverPointer**: Stable address that stores the prover implementation address and code hash in `BLOCK_HASH_PROVER_POINTER_SLOT`, enforcing increasing `version()`. -- **BlockHashProverCopy**: Locally deployed prover contract whose `codehash` matches the pointer; used by `Receiver` when proving multi-hop routes. +- **StateProver**: Chain-specific verifier that proves a target block hash from a home chain state root and verifies arbitrary storage for that block. +- **StateProverPointer**: Stable address that stores the prover implementation address and code hash in `BLOCK_HASH_PROVER_POINTER_SLOT`, enforcing increasing `version()`. +- **StateProverCopy**: Locally deployed prover contract whose `codehash` matches the pointer; used by `Receiver` when proving multi-hop routes. - **Route**: Ordered addresses of prover pointers from the destination back to the origin chain; hashed cumulatively in `Receiver` to produce unique IDs. ## Two-hop proof flow (L2 → L1 → L2) 1) Publisher broadcasts on L2-A → `Broadcaster` stores timestamp at `keccak(message, publisher)`. 2) On L2-B, caller gives `Receiver.verifyBroadcastMessage`: - Route: `[L2-A→L1 pointer, L1→L2-B pointer]` - - `bhpInputs[0]`: proof for L2-A block hash committed to L1 - - `bhpInputs[1]`: proof for that L1 block hash committed to L2-B + - `scpInputs[0]`: proof for L2-A block hash committed to L1 + - `scpInputs[1]`: proof for that L1 block hash committed to L2-B - `storageProof`: proof for the `(message, publisher)` slot on L2-A at the proven block hash -3) `Receiver` uses a local `BlockHashProverCopy` for hop 2 (code hash must match pointer), verifies each hop, checks the slot matches `keccak(message, publisher)`, and returns `(broadcasterId, timestamp)`. +3) `Receiver` uses a local `StateProverCopy` for hop 2 (code hash must match pointer), verifies each hop, checks the slot matches `keccak(message, publisher)`, and returns `(broadcasterId, timestamp)`. 4) Subscriber contracts compare `broadcasterId` against their allowlist and mark messages as consumed. ## How the protocol fits together 1) A publisher calls `Broadcaster.broadcastMessage(message)` on Chain A. The `(message, publisher)` slot now holds the timestamp. 2) To trustlessly read that message on Chain C, a caller provides `Receiver.verifyBroadcastMessage` with: - - `route`: addresses of the `BlockHashProverPointer` hop-by-hop path (e.g., child→L1 pointer, L1→dest pointer). - - `bhpInputs`: prover-specific inputs for each hop (built off-chain with the TS helpers). + - `route`: addresses of the `StateProverPointer` hop-by-hop path (e.g., child→L1 pointer, L1→dest pointer). + - `scpInputs`: prover-specific inputs for each hop (built off-chain with the TS helpers). - `storageProof`: a storage proof for the `Broadcaster` slot on the source chain at the proven block hash. 3) `Receiver` accumulates the route to derive unique IDs, ensures the proven slot matches `keccak(message, publisher)`, and returns `(broadcasterId, timestamp)`. 4) Before verifying, callers can seed `Receiver.updateStateProverCopy` with a local prover copy whose code hash matches the pointer slot and whose `version()` increases. @@ -56,11 +56,11 @@ Ethereum reference implementation for [ERC-7888: Crosschain Broadcaster](https:/ ## Using the contracts (high level) - Deploy a `Broadcaster` on each chain where messages originate. -- Deploy a `BlockHashProverPointer` per chain pair direction; point it to the canonical `BlockHashProver` implementation (must expose `version()` and stable code hash). +- Deploy a `StateProverPointer` per chain pair direction; point it to the canonical `StateProver` implementation (must expose `version()` and stable code hash). - On destination chains, deploy `Receiver` and register local prover copies via `updateStateProverCopy` once the pointer’s code hash is provably available. - Off-chain, use the TS helpers (or your own tooling) to: 1) Find a route (e.g., L2→L1→L2), - 2) Build `bhpInputs` per hop plus the final `storageProof`, + 2) Build `scpInputs` per hop plus the final `storageProof`, 3) Call `Receiver.verifyBroadcastMessage` with `(message, publisher)`; use the returned `broadcasterId` to authorize the source broadcaster. ## Links diff --git a/scripts/taiko/README.txt b/scripts/taiko/README.txt index 0aa95dc..8a85ffa 100644 --- a/scripts/taiko/README.txt +++ b/scripts/taiko/README.txt @@ -55,7 +55,7 @@ DEPLOYMENT ./scripts/taiko/deploy.sh --force # Force re-deployment Deploys and verifies all contracts on L1 and L2: -- Broadcaster, Receiver, BlockHashProverPointer +- Broadcaster, Receiver, StateProverPointer - ParentToChildProver (L1) - reads L2 state from L1 - ChildToParentProver (L2) - reads L1 state from L2 @@ -258,7 +258,7 @@ ARCHITECTURE L1 (Ethereum/Taiko Parent - Chain ID: 32382) ├── Broadcaster (stores messages) ├── Receiver (verifies remote messages) -├── BlockHashProverPointer +├── StateProverPointer ├── ParentToChildProver (reads L2 blocks via SignalService) └── SignalService (0x53789e39E3310737E8C8cED483032AAc25B39ded) └── Stores L2 block checkpoints @@ -266,7 +266,7 @@ L1 (Ethereum/Taiko Parent - Chain ID: 32382) L2 (Taiko Child Chain - Chain ID: 167001) ├── Broadcaster (stores messages) ├── Receiver (verifies remote messages) -├── BlockHashProverPointer +├── StateProverPointer ├── ChildToParentProver (reads L1 blocks via SignalService) └── SignalService (0x1670010000000000000000000000000000000005) └── Stores L1 block checkpoints @@ -306,14 +306,14 @@ DEPLOYED CONTRACTS L1 (Taiko Parent Chain - 32382): - Broadcaster: $L1_BROADCASTER - Receiver: $L1_RECEIVER -- BlockHashProverPointer: $L1_POINTER +- StateProverPointer: $L1_POINTER - ParentToChildProver: $L1_PARENT_TO_CHILD_PROVER - ProverPointer: $L1_PROVER_POINTER L2 (Taiko Child Chain - 167001): - Broadcaster: $L2_BROADCASTER - Receiver: $L2_RECEIVER -- BlockHashProverPointer: $L2_POINTER +- StateProverPointer: $L2_POINTER - ChildToParentProver: $L2_CHILD_TO_PARENT_PROVER - ProverPointer: $L2_PROVER_POINTER diff --git a/scripts/taiko/deploy-all.s.sol b/scripts/taiko/deploy-all.s.sol index 6df8ee2..a6d9725 100644 --- a/scripts/taiko/deploy-all.s.sol +++ b/scripts/taiko/deploy-all.s.sol @@ -5,7 +5,7 @@ import { Script } from "forge-std/Script.sol"; import { console } from "forge-std/console.sol"; import { Broadcaster } from "../../src/contracts/Broadcaster.sol"; import { Receiver } from "../../src/contracts/Receiver.sol"; -import { BlockHashProverPointer } from "../../src/contracts/BlockHashProverPointer.sol"; +import { StateProverPointer } from "../../src/contracts/StateProverPointer.sol"; contract DeployAll is Script { function run() public { @@ -15,13 +15,13 @@ contract DeployAll is Script { Broadcaster broadcaster = new Broadcaster(); Receiver receiver = new Receiver(); - BlockHashProverPointer pointer = new BlockHashProverPointer(owner); + StateProverPointer pointer = new StateProverPointer(owner); vm.stopBroadcast(); console.log("Broadcaster:", address(broadcaster)); console.log("Receiver:", address(receiver)); - console.log("BlockHashProverPointer:", address(pointer)); + console.log("StateProverPointer:", address(pointer)); } } diff --git a/scripts/taiko/deploy.sh b/scripts/taiko/deploy.sh index 3be1565..04bf4e3 100755 --- a/scripts/taiko/deploy.sh +++ b/scripts/taiko/deploy.sh @@ -69,7 +69,7 @@ fi if [ "$SKIP_L1" = false ]; then L1_BROADCASTER=$(echo "$L1_OUTPUT" | grep -o "Broadcaster: 0x[a-fA-F0-9]*" | cut -d' ' -f2) L1_RECEIVER=$(echo "$L1_OUTPUT" | grep -o "Receiver: 0x[a-fA-F0-9]*" | cut -d' ' -f2) - L1_POINTER=$(echo "$L1_OUTPUT" | grep -o "BlockHashProverPointer: 0x[a-fA-F0-9]*" | cut -d' ' -f2) + L1_POINTER=$(echo "$L1_OUTPUT" | grep -o "StateProverPointer: 0x[a-fA-F0-9]*" | cut -d' ' -f2) fi if [ "$SKIP_L2" = false ]; then @@ -81,7 +81,7 @@ if [ "$SKIP_L2" = false ]; then L2_BROADCASTER=$(echo "$L2_OUTPUT" | grep -o "Broadcaster: 0x[a-fA-F0-9]*" | cut -d' ' -f2) L2_RECEIVER=$(echo "$L2_OUTPUT" | grep -o "Receiver: 0x[a-fA-F0-9]*" | cut -d' ' -f2) - L2_POINTER=$(echo "$L2_OUTPUT" | grep -o "BlockHashProverPointer: 0x[a-fA-F0-9]*" | cut -d' ' -f2) + L2_POINTER=$(echo "$L2_OUTPUT" | grep -o "StateProverPointer: 0x[a-fA-F0-9]*" | cut -d' ' -f2) else echo "Skipping L2 deployment (already deployed)" fi @@ -134,7 +134,7 @@ if [ "$SKIP_L1" = false ] || [ "$SKIP_L1_PROVER" = false ]; then forge verify-contract --rpc-url "$L1_RPC" --verifier blockscout --verifier-url "$L1_VERIFIER_URL" \ --constructor-args $(cast abi-encode "constructor(address)" "$TAIKO_DEPLOYER_ADDRESS") \ - "$L1_POINTER" src/contracts/BlockHashProverPointer.sol:BlockHashProverPointer || true + "$L1_POINTER" src/contracts/StateProverPointer.sol:StateProverPointer || true fi if [ "$SKIP_L1_PROVER" = false ]; then @@ -144,7 +144,7 @@ if [ "$SKIP_L1" = false ] || [ "$SKIP_L1_PROVER" = false ]; then forge verify-contract --rpc-url "$L1_RPC" --verifier blockscout --verifier-url "$L1_VERIFIER_URL" \ --constructor-args $(cast abi-encode "constructor(address)" "$TAIKO_DEPLOYER_ADDRESS") \ - "$L1_PROVER_POINTER" src/contracts/BlockHashProverPointer.sol:BlockHashProverPointer || true + "$L1_PROVER_POINTER" src/contracts/StateProverPointer.sol:StateProverPointer || true fi fi @@ -160,7 +160,7 @@ if [ "$SKIP_L2" = false ] || [ "$SKIP_L2_PROVER" = false ]; then forge verify-contract --rpc-url "$L2_RPC" --verifier blockscout --verifier-url "$L2_VERIFIER_URL" \ --constructor-args $(cast abi-encode "constructor(address)" "$TAIKO_DEPLOYER_ADDRESS") \ - "$L2_POINTER" src/contracts/BlockHashProverPointer.sol:BlockHashProverPointer || true + "$L2_POINTER" src/contracts/StateProverPointer.sol:StateProverPointer || true fi if [ "$SKIP_L2_PROVER" = false ]; then @@ -170,7 +170,7 @@ if [ "$SKIP_L2" = false ] || [ "$SKIP_L2_PROVER" = false ]; then forge verify-contract --rpc-url "$L2_RPC" --verifier blockscout --verifier-url "$L2_VERIFIER_URL" \ --constructor-args $(cast abi-encode "constructor(address)" "$TAIKO_DEPLOYER_ADDRESS") \ - "$L2_PROVER_POINTER" src/contracts/BlockHashProverPointer.sol:BlockHashProverPointer || true + "$L2_PROVER_POINTER" src/contracts/StateProverPointer.sol:StateProverPointer || true fi fi @@ -195,14 +195,14 @@ echo "" echo "L1 (Taiko Parent Chain - 32382):" echo " Broadcaster: $L1_BROADCASTER" echo " Receiver: $L1_RECEIVER" -echo " BlockHashProverPointer: $L1_POINTER" +echo " StateProverPointer: $L1_POINTER" echo " ParentToChildProver: $L1_PARENT_TO_CHILD_PROVER" echo " ProverPointer: $L1_PROVER_POINTER" echo "" echo "L2 (Taiko Child Chain - 167001):" echo " Broadcaster: $L2_BROADCASTER" echo " Receiver: $L2_RECEIVER" -echo " BlockHashProverPointer: $L2_POINTER" +echo " StateProverPointer: $L2_POINTER" echo " ChildToParentProver: $L2_CHILD_TO_PARENT_PROVER" echo " ProverPointer: $L2_PROVER_POINTER" echo "" diff --git a/scripts/taiko/provers-l2.s.sol b/scripts/taiko/provers-l2.s.sol index ea77120..1db9d4d 100644 --- a/scripts/taiko/provers-l2.s.sol +++ b/scripts/taiko/provers-l2.s.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.27; import { Script } from "forge-std/Script.sol"; import { console } from "forge-std/console.sol"; import { ChildToParentProver as TaikoChildToParentProver } from "../../src/contracts/provers/taiko/ChildToParentProver.sol"; -import { BlockHashProverPointer } from "../../src/contracts/BlockHashProverPointer.sol"; +import { StateProverPointer } from "../../src/contracts/StateProverPointer.sol"; /// @notice Deploy ChildToParentProver on L2 (Taiko Child Chain) /// @dev This script deploys the prover that allows reading L1 state from L2 @@ -24,7 +24,7 @@ contract DeployL2Prover is Script { homeChainId ); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); blockHashProverPointer.setImplementationAddress(address(childToParentProver)); vm.stopBroadcast(); diff --git a/scripts/taiko/provers.s.sol b/scripts/taiko/provers.s.sol index 358493c..fb970ed 100644 --- a/scripts/taiko/provers.s.sol +++ b/scripts/taiko/provers.s.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.27; import { Script } from "forge-std/Script.sol"; import { console } from "forge-std/console.sol"; import { ParentToChildProver as TaikoParentToChildProver } from "../../src/contracts/provers/taiko/ParentToChildProver.sol"; -import { BlockHashProverPointer } from "../../src/contracts/BlockHashProverPointer.sol"; +import { StateProverPointer } from "../../src/contracts/StateProverPointer.sol"; /// @notice Deploy ParentToChildProver on L1 (Ethereum/Taiko Parent Chain) /// @dev This script deploys the prover that allows reading L2 state from L1 @@ -24,7 +24,7 @@ contract DeployL1Prover is Script { homeChainId ); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); vm.stopBroadcast(); diff --git a/scripts/taiko/verify-message.s.sol b/scripts/taiko/verify-message.s.sol index 51c1bfa..9834c3b 100644 --- a/scripts/taiko/verify-message.s.sol +++ b/scripts/taiko/verify-message.s.sol @@ -29,12 +29,12 @@ contract VerifyMessage is Script { address[] memory route = new address[](1); route[0] = proverPointerAddress; - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(uint48(blockNumber)); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(uint48(blockNumber)); IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({ route: route, - bhpInputs: bhpInputs, + scpInputs: scpInputs, storageProof: storageProofInput }); diff --git a/scripts/taiko/verify-on-chain.s.sol b/scripts/taiko/verify-on-chain.s.sol index 268ba29..4b8abbf 100644 --- a/scripts/taiko/verify-on-chain.s.sol +++ b/scripts/taiko/verify-on-chain.s.sol @@ -57,12 +57,12 @@ contract VerifyOnChain is Script { address[] memory route = new address[](1); route[0] = getL2ProverPointer(); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(uint48(blockNumber)); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(uint48(blockNumber)); IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({ route: route, - bhpInputs: bhpInputs, + scpInputs: scpInputs, storageProof: storageProofInput }); @@ -109,12 +109,12 @@ contract VerifyOnChain is Script { address[] memory route = new address[](1); route[0] = getL1ProverPointer(); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(uint48(blockNumber)); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(uint48(blockNumber)); IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({ route: route, - bhpInputs: bhpInputs, + scpInputs: scpInputs, storageProof: storageProofInput }); diff --git a/src/contracts/Receiver.sol b/src/contracts/Receiver.sol index fa863e5..77b34f2 100644 --- a/src/contracts/Receiver.sol +++ b/src/contracts/Receiver.sol @@ -4,12 +4,12 @@ pragma solidity 0.8.30; import {IReceiver} from "./interfaces/IReceiver.sol"; import {IStateProver} from "./interfaces/IStateProver.sol"; import {IStateProverPointer} from "./interfaces/IStateProverPointer.sol"; -import {BLOCK_HASH_PROVER_POINTER_SLOT} from "./BlockHashProverPointer.sol"; +import {BLOCK_HASH_PROVER_POINTER_SLOT} from "./StateProverPointer.sol"; /// @title Receiver /// @notice Verifies broadcast messages from remote chains using cryptographic storage proofs /// @dev This contract enables cross-chain message verification by: -/// 1. Maintaining local copies of BlockHashProver contracts for different chains +/// 1. Maintaining local copies of StateProver contracts for different chains /// 2. Using these provers to verify storage proofs from remote Broadcaster contracts /// 3. Following a proof route that can span multiple chain hops /// The verification process ensures that a message was actually broadcast on a remote chain @@ -22,18 +22,18 @@ contract Receiver is IReceiver { error ProverCopyNotFound(); error MessageNotFound(); error WrongMessageSlot(); - error WrongBlockHashProverPointerSlot(); + error WrongStateProverPointerSlot(); error DifferentCodeHash(); error NewerProverVersion(); /// @notice Verifies that a message was broadcast on a remote chain - /// @dev This function uses a chain of BlockHashProvers to verify a storage proof that demonstrates + /// @dev This function uses a chain of StateProvers to verify a storage proof that demonstrates /// a message was broadcast. The verification route can span multiple chains, with each hop /// proving the next chain's state. The function verifies: /// 1. The storage slot matches the expected slot for (message, publisher) /// 2. The slot value is non-zero (message was broadcast) /// 3. The entire proof chain is valid - /// @param broadcasterReadArgs Contains the route (chain of addresses), BlockHashProver inputs for each hop, + /// @param broadcasterReadArgs Contains the route (chain of addresses), StateProver inputs for each hop, /// and the final storage proof for the broadcaster contract /// @param message The 32-byte message that was allegedly broadcast /// @param publisher The address that allegedly broadcast the message @@ -63,18 +63,18 @@ contract Receiver is IReceiver { timestamp = uint256(slotValue); } - /// @notice Updates the local copy of a BlockHashProver for a specific remote chain - /// @dev This function verifies and stores a local copy of a BlockHashProver contract from a remote chain. + /// @notice Updates the local copy of a StateProver for a specific remote chain + /// @dev This function verifies and stores a local copy of a StateProver contract from a remote chain. /// The verification process ensures: /// 1. The provided proof reads from the correct storage slot (BLOCK_HASH_PROVER_POINTER_SLOT) /// 2. The code hash of the local copy matches the code hash stored in the remote pointer /// 3. The new version is newer than any existing local copy (version monotonicity) - /// This allows the Receiver to trustlessly obtain and update BlockHashProver implementations + /// This allows the Receiver to trustlessly obtain and update StateProver implementations /// needed for cross-chain message verification. - /// @param bhpPointerReadArgs Contains the route and proofs to read the remote BlockHashProverPointer's storage - /// @param bhpCopy The local deployed copy of the BlockHashProver contract - /// @return bhpPointerId A unique identifier for the remote BlockHashProverPointer (accumulated hash of route) - /// @custom:throws WrongBlockHashProverPointerSlot if the proof doesn't read from the expected slot + /// @param bhpPointerReadArgs Contains the route and proofs to read the remote StateProverPointer's storage + /// @param bhpCopy The local deployed copy of the StateProver contract + /// @return bhpPointerId A unique identifier for the remote StateProverPointer (accumulated hash of route) + /// @custom:throws WrongStateProverPointerSlot if the proof doesn't read from the expected slot /// @custom:throws DifferentCodeHash if the local copy's code hash doesn't match the remote pointer's stored hash /// @custom:throws NewerProverVersion if an existing local copy has a version >= the new copy's version function updateStateProverCopy(RemoteReadArgs calldata bhpPointerReadArgs, IStateProver bhpCopy) @@ -86,7 +86,7 @@ contract Receiver is IReceiver { (bhpPointerId, slot, bhpCodeHash) = _readRemoteSlot(bhpPointerReadArgs); if (slot != uint256(BLOCK_HASH_PROVER_POINTER_SLOT)) { - revert WrongBlockHashProverPointerSlot(); + revert WrongStateProverPointerSlot(); } if (address(bhpCopy).codehash != bhpCodeHash) { @@ -102,10 +102,10 @@ contract Receiver is IReceiver { _blockHashProverCopies[bhpPointerId] = bhpCopy; } - /// @notice The BlockHashProverCopy on the local chain corresponding to the bhpPointerId - /// MUST return 0 if the BlockHashProverPointer does not exist. - /// @param bhpPointerId The unique identifier of the BlockHashProverPointer. - /// @return bhpCopy The BlockHashProver copy stored on the local chain, or address(0) if not found. + /// @notice The StateProverCopy on the local chain corresponding to the bhpPointerId + /// MUST return 0 if the StateProverPointer does not exist. + /// @param bhpPointerId The unique identifier of the StateProverPointer. + /// @return bhpCopy The StateProver copy stored on the local chain, or address(0) if not found. function blockHashProverCopy(bytes32 bhpPointerId) external view returns (IStateProver bhpCopy) { bhpCopy = _blockHashProverCopies[bhpPointerId]; } @@ -115,7 +115,7 @@ contract Receiver is IReceiver { view returns (bytes32 remoteAccountId, uint256 slot, bytes32 slotValue) { - if (readArgs.route.length != readArgs.bhpInputs.length) { + if (readArgs.route.length != readArgs.scpInputs.length) { revert InvalidRouteLength(); } @@ -131,20 +131,20 @@ contract Receiver is IReceiver { if (i == 0) { prover = IStateProver(IStateProverPointer(readArgs.route[0]).implementationAddress()); - blockHash = prover.getTargetStateCommitment(readArgs.bhpInputs[0]); + blockHash = prover.getTargetStateCommitment(readArgs.scpInputs[0]); } else { prover = _blockHashProverCopies[remoteAccountId]; if (address(prover) == address(0)) { revert ProverCopyNotFound(); } - blockHash = prover.verifyTargetStateCommitment(blockHash, readArgs.bhpInputs[i]); + blockHash = prover.verifyTargetStateCommitment(blockHash, readArgs.scpInputs[i]); } } address remoteAccount; - (remoteAccount, slot, slotValue) = prover.verifyStorageSlot(blockHash, readArgs.storageProof); + (remoteAccount, slot, slotValue) = prover.verifyStorageSlot(blockHash, readArgs.proof); remoteAccountId = accumulator(remoteAccountId, remoteAccount); } diff --git a/src/contracts/BlockHashProverPointer.sol b/src/contracts/StateProverPointer.sol similarity index 88% rename from src/contracts/BlockHashProverPointer.sol rename to src/contracts/StateProverPointer.sol index 1f39bd5..55de0e1 100644 --- a/src/contracts/BlockHashProverPointer.sol +++ b/src/contracts/StateProverPointer.sol @@ -8,12 +8,12 @@ import {IStateProverPointer} from "./interfaces/IStateProverPointer.sol"; bytes32 constant BLOCK_HASH_PROVER_POINTER_SLOT = bytes32(uint256(keccak256("eip7888.pointer.slot")) - 1); -/// @title BlockHashProverPointer -/// @notice Manages a versioned pointer to the latest BlockHashProver implementation -/// @dev This contract stores the address and code hash of the current BlockHashProver implementation. +/// @title StateProverPointer +/// @notice Manages a versioned pointer to the latest StateProver implementation +/// @dev This contract stores the address and code hash of the current StateProver implementation. /// It enforces version monotonicity to ensure that updates always move to newer versions. /// The code hash is stored in a dedicated storage slot for efficient cross-chain verification. -contract BlockHashProverPointer is IStateProverPointer, Ownable { +contract StateProverPointer is IStateProverPointer, Ownable { address internal _implementationAddress; error NonIncreasingVersion(uint256 newVersion, uint256 oldVersion); @@ -21,7 +21,7 @@ contract BlockHashProverPointer is IStateProverPointer, Ownable { constructor(address _initialOwner) Ownable(_initialOwner) {} - /// @notice Returns the address of the current BlockHashProver implementation + /// @notice Returns the address of the current StateProver implementation /// @return The address of the current implementation contract function implementationAddress() public view returns (address) { return _implementationAddress; @@ -33,11 +33,11 @@ contract BlockHashProverPointer is IStateProverPointer, Ownable { codeHash = StorageSlot.getBytes32Slot(BLOCK_HASH_PROVER_POINTER_SLOT).value; } - /// @notice Updates the BlockHashProver implementation to a new version + /// @notice Updates the StateProver implementation to a new version /// @dev This function enforces version monotonicity - the new implementation must have a higher version number /// than the current one. It also updates the stored code hash to match the new implementation. /// Can only be called by the contract owner. - /// @param _newImplementationAddress The address of the new BlockHashProver implementation + /// @param _newImplementationAddress The address of the new StateProver implementation /// @custom:throws NonIncreasingVersion if the new version is not greater than the current version function setImplementationAddress(address _newImplementationAddress) external onlyOwner { if (_newImplementationAddress == address(0)) { diff --git a/test/BlockHashProverPointer.t.sol b/test/BlockHashProverPointer.t.sol index 3fb3d93..cb0657b 100644 --- a/test/BlockHashProverPointer.t.sol +++ b/test/BlockHashProverPointer.t.sol @@ -2,17 +2,17 @@ pragma solidity 0.8.30; import {Test} from "forge-std/Test.sol"; -import {BlockHashProverPointer} from "../src/contracts/BlockHashProverPointer.sol"; +import {StateProverPointer} from "../src/contracts/StateProverPointer.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {MockProver} from "./mocks/MockProver.sol"; -contract BlockHashProverPointerTest is Test { - BlockHashProverPointer public blockHashProverPointer; +contract StateProverPointerTest is Test { + StateProverPointer public blockHashProverPointer; MockProver public mockProver; address public owner = makeAddr("owner"); function setUp() public { - blockHashProverPointer = new BlockHashProverPointer(owner); + blockHashProverPointer = new StateProverPointer(owner); mockProver = new MockProver(); } @@ -37,19 +37,19 @@ contract BlockHashProverPointerTest is Test { vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(mockProver)); vm.prank(owner); - vm.expectRevert(abi.encodeWithSelector(BlockHashProverPointer.NonIncreasingVersion.selector, 1, 1)); + vm.expectRevert(abi.encodeWithSelector(StateProverPointer.NonIncreasingVersion.selector, 1, 1)); blockHashProverPointer.setImplementationAddress(address(mockProver)); } function test_setImplementationAddress_reverts_if_implementation_address_is_invalid() public { vm.prank(owner); - vm.expectRevert(abi.encodeWithSelector(BlockHashProverPointer.InvalidImplementationAddress.selector)); + vm.expectRevert(abi.encodeWithSelector(StateProverPointer.InvalidImplementationAddress.selector)); blockHashProverPointer.setImplementationAddress(address(0)); } function test_setImplementationAddress_reverts_if_implementation_address_is_invalid_eoa() public { vm.prank(owner); - vm.expectRevert(abi.encodeWithSelector(BlockHashProverPointer.InvalidImplementationAddress.selector)); + vm.expectRevert(abi.encodeWithSelector(StateProverPointer.InvalidImplementationAddress.selector)); blockHashProverPointer.setImplementationAddress(makeAddr("invalid")); } } diff --git a/test/Receiver.Taiko.t.sol b/test/Receiver.Taiko.t.sol index 9de3e9d..b687e81 100644 --- a/test/Receiver.Taiko.t.sol +++ b/test/Receiver.Taiko.t.sol @@ -5,7 +5,7 @@ import {console, Test} from "forge-std/Test.sol"; import {stdJson} from "forge-std/StdJson.sol"; import {Receiver} from "../src/contracts/Receiver.sol"; import {IReceiver} from "../src/contracts/interfaces/IReceiver.sol"; -import {BlockHashProverPointer} from "../src/contracts/BlockHashProverPointer.sol"; +import {StateProverPointer} from "../src/contracts/StateProverPointer.sol"; import {ParentToChildProver as TaikoParentToChildProver} from "../src/contracts/provers/taiko/ParentToChildProver.sol"; import {ChildToParentProver as TaikoChildToParentProver} from "../src/contracts/provers/taiko/ChildToParentProver.sol"; @@ -25,7 +25,7 @@ contract ReceiverTaikoTest is Test { Receiver public receiver; TaikoParentToChildProver public parentToChildProver; TaikoChildToParentProver public childToParentProver; - BlockHashProverPointer public blockHashProverPointer; + StateProverPointer public blockHashProverPointer; // Note: We don't use forks anymore to avoid dependency on Taiko internal testnet // which can be reset at any time. Instead, we use local mocks with vm.chainId(). @@ -48,7 +48,7 @@ contract ReceiverTaikoTest is Test { receiver = new Receiver(); parentToChildProver = new TaikoParentToChildProver(L1_SIGNAL_SERVICE, CHECKPOINTS_SLOT, L1_CHAIN_ID); - blockHashProverPointer = new BlockHashProverPointer(owner); + blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); @@ -84,11 +84,11 @@ contract ReceiverTaikoTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(uint48(blockNumber)); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(uint48(blockNumber)); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofInput}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofInput}); // Read message info (auto-generated by broadcast-and-prove.sh) string memory infoPath = "test/payloads/taiko/taikoProofL2-info.json"; @@ -111,7 +111,7 @@ contract ReceiverTaikoTest is Test { receiver = new Receiver(); parentToChildProver = new TaikoParentToChildProver(L1_SIGNAL_SERVICE, CHECKPOINTS_SLOT, L1_CHAIN_ID); - blockHashProverPointer = new BlockHashProverPointer(owner); + blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); @@ -143,11 +143,11 @@ contract ReceiverTaikoTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(uint48(blockNumber)); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(uint48(blockNumber)); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofInput}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofInput}); // Read message info (auto-generated by broadcast-and-prove.sh) string memory infoPath = "test/payloads/taiko/taikoProofL2-info.json"; @@ -171,7 +171,7 @@ contract ReceiverTaikoTest is Test { receiver = new Receiver(); childToParentProver = new TaikoChildToParentProver(L2_SIGNAL_SERVICE, CHECKPOINTS_SLOT, L2_CHAIN_ID); - blockHashProverPointer = new BlockHashProverPointer(owner); + blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(childToParentProver)); @@ -206,11 +206,11 @@ contract ReceiverTaikoTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(uint48(blockNumber)); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(uint48(blockNumber)); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofInput}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofInput}); // Read message info (auto-generated by broadcast-and-prove.sh) string memory infoPath = "test/payloads/taiko/taikoProofL1-info.json"; diff --git a/test/Receiver.ethereum.t.sol b/test/Receiver.ethereum.t.sol index abe61ad..d8cb0b8 100644 --- a/test/Receiver.ethereum.t.sol +++ b/test/Receiver.ethereum.t.sol @@ -8,7 +8,7 @@ import {IReceiver} from "../src/contracts/interfaces/IReceiver.sol"; import {IStateProver} from "../src/contracts/interfaces/IStateProver.sol"; import {IOutbox} from "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol"; import {IStateProverPointer} from "../src/contracts/interfaces/IStateProverPointer.sol"; -import {BLOCK_HASH_PROVER_POINTER_SLOT} from "../src/contracts/BlockHashProverPointer.sol"; +import {BLOCK_HASH_PROVER_POINTER_SLOT} from "../src/contracts/StateProverPointer.sol"; import {BlockHeaders} from "./utils/BlockHeaders.sol"; import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {BufferMock} from "./mocks/BufferMock.sol"; @@ -32,7 +32,7 @@ import { import { ParentToChildProver as ScrollParentToChildProver } from "../src/contracts/provers/scroll/ParentToChildProver.sol"; -import {BlockHashProverPointer} from "../src/contracts/BlockHashProverPointer.sol"; +import {StateProverPointer} from "../src/contracts/StateProverPointer.sol"; import {RLP} from "@openzeppelin/contracts/utils/RLP.sol"; import {MockZkChain} from "./provers/zksync/ParentChildToProver.t.sol"; @@ -129,7 +129,7 @@ contract ReceiverTest is Test { ZksyncParentToChildProver parentToChildProver = new ZksyncParentToChildProver(address(mockZkChain), 0, 300, 32657, block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); @@ -146,13 +146,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(47506); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(47506); bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); (bytes32 broadcasterId, uint256 timestamp) = receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); @@ -188,7 +188,7 @@ contract ReceiverTest is Test { ZksyncParentToChildProver parentToChildProver = new ZksyncParentToChildProver(address(mockZkChain), 0, 300, 32657, block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); @@ -205,13 +205,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(47506); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(47506); bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); vm.expectRevert(ZksyncParentToChildProver.SlotMismatch.selector); receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); diff --git a/test/Receiver.t.sol b/test/Receiver.t.sol index 8dd1f74..164f633 100644 --- a/test/Receiver.t.sol +++ b/test/Receiver.t.sol @@ -8,7 +8,7 @@ import {IReceiver} from "../src/contracts/interfaces/IReceiver.sol"; import {IStateProver} from "../src/contracts/interfaces/IStateProver.sol"; import {IOutbox} from "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol"; import {IStateProverPointer} from "../src/contracts/interfaces/IStateProverPointer.sol"; -import {BLOCK_HASH_PROVER_POINTER_SLOT} from "../src/contracts/BlockHashProverPointer.sol"; +import {BLOCK_HASH_PROVER_POINTER_SLOT} from "../src/contracts/StateProverPointer.sol"; import {BlockHeaders} from "./utils/BlockHeaders.sol"; import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {BufferMock} from "./mocks/BufferMock.sol"; @@ -27,7 +27,7 @@ import { import { ParentToChildProver as ScrollParentToChildProver } from "../src/contracts/provers/scroll/ParentToChildProver.sol"; -import {BlockHashProverPointer} from "../src/contracts/BlockHashProverPointer.sol"; +import {StateProverPointer} from "../src/contracts/StateProverPointer.sol"; import {RLP} from "@openzeppelin/contracts/utils/RLP.sol"; interface IL1Block { @@ -105,7 +105,7 @@ contract ReceiverTest is Test { receiver = new Receiver(); ArbChildToParentProver childToParentProver = new ArbChildToParentProver(block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(childToParentProver)); @@ -147,13 +147,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(blockNumber); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(blockNumber); bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); (bytes32 broadcasterId, uint256 timestamp) = receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); @@ -181,7 +181,7 @@ contract ReceiverTest is Test { receiver = new Receiver(); ArbParentToChildProver parentToChildProver = _getOnChainArbProverCopy(); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); @@ -219,13 +219,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(sendRoot); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(sendRoot); bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); (bytes32 broadcasterId, uint256 timestamp) = receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); @@ -253,7 +253,7 @@ contract ReceiverTest is Test { OPChildToParentProver childToParentProver = new OPChildToParentProver(block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(childToParentProver)); @@ -292,13 +292,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = bytes(""); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = bytes(""); bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); (bytes32 broadcasterId, uint256 timestamp) = receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); @@ -327,7 +327,7 @@ contract ReceiverTest is Test { OPChildToParentProver childToParentProver = new OPChildToParentProver(block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(childToParentProver)); @@ -363,13 +363,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = bytes(""); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = bytes(""); bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -400,7 +400,7 @@ contract ReceiverTest is Test { OPChildToParentProver childToParentProver = new OPChildToParentProver(block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(childToParentProver)); @@ -436,13 +436,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = bytes(""); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = bytes(""); bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -457,7 +457,7 @@ contract ReceiverTest is Test { OPChildToParentProver childToParentProver = new OPChildToParentProver(block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -501,13 +501,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = bytes(""); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = bytes(""); bytes memory storageProofToLastProver = inputForOPChildToParentProver; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); @@ -570,16 +570,16 @@ contract ReceiverTest is Test { bytes memory input1 = abi.encode(rlpBlockHeaderEthereum, sendRootArbitrum, rlpAccountProofEthereum, rlpStorageProofEthereum); - bytes[] memory bhpInputs = new bytes[](2); - bhpInputs[0] = input0; - bhpInputs[1] = input1; + bytes[] memory scpInputs = new bytes[](2); + scpInputs[0] = input0; + scpInputs[1] = input1; bytes memory storageProofToLastProver = abi.encode( rlpBlockHeaderArbitrum, accountArbitrum, slotArbitrum, rlpAccountProofArbitrum, rlpStorageProofArbitrum ); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000074657374; // "test" address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -616,7 +616,7 @@ contract ReceiverTest is Test { ZksyncChildToParentProver childToParentProver = new ZksyncChildToParentProver(address(buffer), block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(childToParentProver)); @@ -650,13 +650,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(blockNumber); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(blockNumber); bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -689,7 +689,7 @@ contract ReceiverTest is Test { ZksyncChildToParentProver childToParentProver = new ZksyncChildToParentProver(address(buffer), block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -731,13 +731,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(blockNumber); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(blockNumber); bytes memory storageProofToLastProver = inputForOPChildToParentProver; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); @@ -798,16 +798,16 @@ contract ReceiverTest is Test { bytes memory input1 = abi.encode(rlpBlockHeaderEthereum, sendRootArbitrum, rlpAccountProofEthereum, rlpStorageProofEthereum); - bytes[] memory bhpInputs = new bytes[](2); - bhpInputs[0] = input0; - bhpInputs[1] = input1; + bytes[] memory scpInputs = new bytes[](2); + scpInputs[0] = input0; + scpInputs[1] = input1; bytes memory storageProofToLastProver = abi.encode( rlpBlockHeaderArbitrum, accountArbitrum, slotArbitrum, rlpAccountProofArbitrum, rlpStorageProofArbitrum ); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000074657374; // "test" address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -844,7 +844,7 @@ contract ReceiverTest is Test { LineaChildToParentProver childToParentProver = new LineaChildToParentProver(address(buffer), block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(childToParentProver)); @@ -878,13 +878,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(blockNumber); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(blockNumber); bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -917,7 +917,7 @@ contract ReceiverTest is Test { LineaChildToParentProver childToParentProver = new LineaChildToParentProver(address(buffer), block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -959,13 +959,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(blockNumber); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(blockNumber); bytes memory storageProofToLastProver = inputForOPChildToParentProver; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); @@ -1026,16 +1026,16 @@ contract ReceiverTest is Test { bytes memory input1 = abi.encode(rlpBlockHeaderEthereum, sendRootArbitrum, rlpAccountProofEthereum, rlpStorageProofEthereum); - bytes[] memory bhpInputs = new bytes[](2); - bhpInputs[0] = input0; - bhpInputs[1] = input1; + bytes[] memory scpInputs = new bytes[](2); + scpInputs[0] = input0; + scpInputs[1] = input1; bytes memory storageProofToLastProver = abi.encode( rlpBlockHeaderArbitrum, accountArbitrum, slotArbitrum, rlpAccountProofArbitrum, rlpStorageProofArbitrum ); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000074657374; // "test" address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -1072,7 +1072,7 @@ contract ReceiverTest is Test { ScrollChildToParentProver childToParentProver = new ScrollChildToParentProver(address(buffer), block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(childToParentProver)); @@ -1106,13 +1106,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(blockNumber); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(blockNumber); bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -1145,7 +1145,7 @@ contract ReceiverTest is Test { ScrollChildToParentProver childToParentProver = new ScrollChildToParentProver(address(buffer), block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -1187,13 +1187,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(blockNumber); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(blockNumber); bytes memory storageProofToLastProver = inputForOPChildToParentProver; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); @@ -1254,16 +1254,16 @@ contract ReceiverTest is Test { bytes memory input1 = abi.encode(rlpBlockHeaderEthereum, sendRootArbitrum, rlpAccountProofEthereum, rlpStorageProofEthereum); - bytes[] memory bhpInputs = new bytes[](2); - bhpInputs[0] = input0; - bhpInputs[1] = input1; + bytes[] memory scpInputs = new bytes[](2); + scpInputs[0] = input0; + scpInputs[1] = input1; bytes memory storageProofToLastProver = abi.encode( rlpBlockHeaderArbitrum, accountArbitrum, slotArbitrum, rlpAccountProofArbitrum, rlpStorageProofArbitrum ); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000074657374; // "test" address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -1306,7 +1306,7 @@ contract ReceiverTest is Test { ScrollParentToChildProver parentToChildProver = new ScrollParentToChildProver(scrollChain, finalizedStateRootsSlot, homeChainId); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); @@ -1362,7 +1362,7 @@ contract ReceiverTest is Test { ScrollParentToChildProver parentToChildProver = new ScrollParentToChildProver(scrollChain, finalizedStateRootsSlot, homeChainId); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); @@ -1396,11 +1396,11 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(batchIndex); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(batchIndex); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofInput}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofInput}); (bytes32 broadcasterId, uint256 timestamp) = receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); @@ -1440,7 +1440,7 @@ contract ReceiverTest is Test { LineaParentToChildProver parentToChildProver = new LineaParentToChildProver(lineaRollup, stateRootHashesSlot, homeChainId); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); @@ -1468,13 +1468,13 @@ contract ReceiverTest is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(l2BlockNumber); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(l2BlockNumber); bytes memory storageProofToLastProver = smtProof; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); // Calculate expected message hash from the slot // The slot is keccak256(abi.encode(message, publisher)) diff --git a/test/VerifyBroadcastMessageBenchmark.t.sol b/test/VerifyBroadcastMessageBenchmark.t.sol index 076c7b5..87ce0cb 100644 --- a/test/VerifyBroadcastMessageBenchmark.t.sol +++ b/test/VerifyBroadcastMessageBenchmark.t.sol @@ -5,7 +5,7 @@ import {Test, console} from "forge-std/Test.sol"; import {stdJson} from "forge-std/StdJson.sol"; import {Receiver} from "../src/contracts/Receiver.sol"; import {IReceiver} from "../src/contracts/interfaces/IReceiver.sol"; -import {BlockHashProverPointer} from "../src/contracts/BlockHashProverPointer.sol"; +import {StateProverPointer} from "../src/contracts/StateProverPointer.sol"; // Provers import {ParentToChildProver as TaikoP2C} from "../src/contracts/provers/taiko/ParentToChildProver.sol"; @@ -50,7 +50,7 @@ contract VerifyBroadcastMessageBenchmark is Test { receiver = new Receiver(); TaikoP2C prover = new TaikoP2C(address(uint160(SIGNAL_SERVICE)), CHECKPOINTS_SLOT, L1_CHAIN_ID); - BlockHashProverPointer pointer = new BlockHashProverPointer(owner); + StateProverPointer pointer = new StateProverPointer(owner); vm.prank(owner); pointer.setImplementationAddress(address(prover)); @@ -83,11 +83,11 @@ contract VerifyBroadcastMessageBenchmark is Test { address[] memory route = new address[](1); route[0] = address(pointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(uint48(blockNumber)); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(uint48(blockNumber)); IReceiver.RemoteReadArgs memory args = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProof}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProof}); // Call and snapshot receiver.verifyBroadcastMessage(args, message, publisher); @@ -105,7 +105,7 @@ contract VerifyBroadcastMessageBenchmark is Test { receiver = new Receiver(); ScrollP2C prover = new ScrollP2C(SCROLL_CHAIN, STATE_ROOTS_SLOT, HOME_CHAIN_ID); - BlockHashProverPointer pointer = new BlockHashProverPointer(owner); + StateProverPointer pointer = new StateProverPointer(owner); vm.prank(owner); pointer.setImplementationAddress(address(prover)); @@ -132,11 +132,11 @@ contract VerifyBroadcastMessageBenchmark is Test { address[] memory route = new address[](1); route[0] = address(pointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(batchIndex); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(batchIndex); IReceiver.RemoteReadArgs memory args = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProof}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProof}); // Call and snapshot receiver.verifyBroadcastMessage(args, message, publisher); @@ -154,7 +154,7 @@ contract VerifyBroadcastMessageBenchmark is Test { receiver = new Receiver(); LineaP2C prover = new LineaP2C(LINEA_ROLLUP, STATE_ROOT_SLOT, HOME_CHAIN_ID); - BlockHashProverPointer pointer = new BlockHashProverPointer(owner); + StateProverPointer pointer = new StateProverPointer(owner); vm.prank(owner); pointer.setImplementationAddress(address(prover)); @@ -180,11 +180,11 @@ contract VerifyBroadcastMessageBenchmark is Test { address[] memory route = new address[](1); route[0] = address(pointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(l2BlockNumber); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(l2BlockNumber); IReceiver.RemoteReadArgs memory args = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: smtProof}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: smtProof}); // Call and snapshot receiver.verifyBroadcastMessage(args, message, publisher); @@ -254,7 +254,7 @@ contract VerifyBroadcastMessageBenchmark is Test { receiver = new Receiver(); ZksyncP2C parentToChildProver = new ZksyncP2C(address(mockZkChain), 0, 300, 32657, block.chainid); - BlockHashProverPointer blockHashProverPointer = new BlockHashProverPointer(owner); + StateProverPointer blockHashProverPointer = new StateProverPointer(owner); vm.prank(owner); blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); @@ -269,13 +269,13 @@ contract VerifyBroadcastMessageBenchmark is Test { address[] memory route = new address[](1); route[0] = address(blockHashProverPointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(47506); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(47506); bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); vm.snapshotGasLastCall("verifyBroadcastMessage", "ZkSyncL2ToEthereum"); @@ -296,7 +296,7 @@ contract VerifyBroadcastMessageBenchmark is Test { receiver = new Receiver(); TaikoC2P prover = new TaikoC2P(address(uint160(SIGNAL_SERVICE)), CHECKPOINTS_SLOT, L2_CHAIN_ID); - BlockHashProverPointer pointer = new BlockHashProverPointer(owner); + StateProverPointer pointer = new StateProverPointer(owner); vm.prank(owner); pointer.setImplementationAddress(address(prover)); @@ -329,11 +329,11 @@ contract VerifyBroadcastMessageBenchmark is Test { address[] memory route = new address[](1); route[0] = address(pointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = abi.encode(uint48(blockNumber)); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = abi.encode(uint48(blockNumber)); IReceiver.RemoteReadArgs memory args = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProof}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProof}); // Call and snapshot receiver.verifyBroadcastMessage(args, message, publisher); @@ -349,7 +349,7 @@ contract VerifyBroadcastMessageBenchmark is Test { receiver = new Receiver(); OptimismC2P prover = new OptimismC2P(L2_CHAIN_ID); - BlockHashProverPointer pointer = new BlockHashProverPointer(owner); + StateProverPointer pointer = new StateProverPointer(owner); vm.prank(owner); pointer.setImplementationAddress(address(prover)); @@ -378,11 +378,11 @@ contract VerifyBroadcastMessageBenchmark is Test { address[] memory route = new address[](1); route[0] = address(pointer); - bytes[] memory bhpInputs = new bytes[](1); - bhpInputs[0] = bytes(""); + bytes[] memory scpInputs = new bytes[](1); + scpInputs[0] = bytes(""); IReceiver.RemoteReadArgs memory args = - IReceiver.RemoteReadArgs({route: route, bhpInputs: bhpInputs, storageProof: storageProof}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProof}); // Call and snapshot receiver.verifyBroadcastMessage(args, message, publisher); @@ -409,7 +409,7 @@ contract VerifyBroadcastMessageBenchmark is Test { // First hop prover: Optimism C2P (gets Ethereum block hash on OP L2) OptimismC2P opC2PProver = new OptimismC2P(OP_L2_CHAIN_ID); - BlockHashProverPointer opPointer = new BlockHashProverPointer(owner); + StateProverPointer opPointer = new StateProverPointer(owner); vm.prank(owner); opPointer.setImplementationAddress(address(opC2PProver)); From c5c014269328f15c88cf4fb60576ef2451848794 Mon Sep 17 00:00:00 2001 From: Luiz Date: Mon, 26 Jan 2026 11:59:07 -0300 Subject: [PATCH 08/25] update --- scripts/taiko/verify-message.s.sol | 2 +- scripts/taiko/verify-on-chain.s.sol | 4 +-- src/contracts/Receiver.sol | 4 +-- .../provers/linea/ParentToChildProver.sol | 2 +- .../provers/zksync/ParentToChildProver.sol | 2 +- test/Receiver.Taiko.t.sol | 6 ++-- test/Receiver.ethereum.t.sol | 4 +-- test/Receiver.t.sol | 36 +++++++++---------- test/VerifyBroadcastMessageBenchmark.t.sol | 12 +++---- 9 files changed, 36 insertions(+), 36 deletions(-) diff --git a/scripts/taiko/verify-message.s.sol b/scripts/taiko/verify-message.s.sol index 9834c3b..4fe84af 100644 --- a/scripts/taiko/verify-message.s.sol +++ b/scripts/taiko/verify-message.s.sol @@ -35,7 +35,7 @@ contract VerifyMessage is Script { IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({ route: route, scpInputs: scpInputs, - storageProof: storageProofInput + proof: storageProofInput }); bytes32 message = 0xd9222d7d84eefb8570069f30ab4a850423ba57a374c593b67a224c430f9736df; diff --git a/scripts/taiko/verify-on-chain.s.sol b/scripts/taiko/verify-on-chain.s.sol index 4b8abbf..1f26da4 100644 --- a/scripts/taiko/verify-on-chain.s.sol +++ b/scripts/taiko/verify-on-chain.s.sol @@ -63,7 +63,7 @@ contract VerifyOnChain is Script { IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({ route: route, scpInputs: scpInputs, - storageProof: storageProofInput + proof: storageProofInput }); // Call the deployed Receiver contract @@ -115,7 +115,7 @@ contract VerifyOnChain is Script { IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({ route: route, scpInputs: scpInputs, - storageProof: storageProofInput + proof: storageProofInput }); // Call the deployed Receiver contract diff --git a/src/contracts/Receiver.sol b/src/contracts/Receiver.sol index 77b34f2..43084c3 100644 --- a/src/contracts/Receiver.sol +++ b/src/contracts/Receiver.sol @@ -15,7 +15,7 @@ import {BLOCK_HASH_PROVER_POINTER_SLOT} from "./StateProverPointer.sol"; /// The verification process ensures that a message was actually broadcast on a remote chain /// at a specific timestamp without requiring trust in intermediaries. contract Receiver is IReceiver { - mapping(bytes32 blockHashProverPointerId => IStateProver blockHashProverCopy) private _blockHashProverCopies; + mapping(bytes32 blockHashProverPointerId => IStateProver stateProverCopy) private _blockHashProverCopies; error InvalidRouteLength(); error EmptyRoute(); @@ -106,7 +106,7 @@ contract Receiver is IReceiver { /// MUST return 0 if the StateProverPointer does not exist. /// @param bhpPointerId The unique identifier of the StateProverPointer. /// @return bhpCopy The StateProver copy stored on the local chain, or address(0) if not found. - function blockHashProverCopy(bytes32 bhpPointerId) external view returns (IStateProver bhpCopy) { + function stateProverCopy(bytes32 bhpPointerId) external view returns (IStateProver bhpCopy) { bhpCopy = _blockHashProverCopies[bhpPointerId]; } diff --git a/src/contracts/provers/linea/ParentToChildProver.sol b/src/contracts/provers/linea/ParentToChildProver.sol index a007085..b0ebe78 100644 --- a/src/contracts/provers/linea/ParentToChildProver.sol +++ b/src/contracts/provers/linea/ParentToChildProver.sol @@ -112,7 +112,7 @@ contract ParentToChildProver is IStateProver { /// - accountProof: from accountProof.proof.proofRelatedNodes (42 elements) /// - accountValue: from accountProof.proof.value (192 bytes) /// - storageLeafIndex: from storageProofs[0].leafIndex - /// - storageProof: from storageProofs[0].proof.proofRelatedNodes (42 elements) + /// - proof: from storageProofs[0].proof.proofRelatedNodes (42 elements) /// - storageValue: the claimed storage value (32 bytes, to verify) /// /// Security: This function verifies that: diff --git a/src/contracts/provers/zksync/ParentToChildProver.sol b/src/contracts/provers/zksync/ParentToChildProver.sol index c2db99c..ca5ab76 100644 --- a/src/contracts/provers/zksync/ParentToChildProver.sol +++ b/src/contracts/provers/zksync/ParentToChildProver.sol @@ -116,7 +116,7 @@ contract ParentToChildProver is IStateProver { /// @param input ABI encoded tuple: (bytes rlpBlockHeader, uint256 batchNumber, bytes storageProof). /// - rlpBlockHeader: RLP-encoded block header of the home chain. /// - batchNumber: The batch number for which to retrieve the L2 logs root hash. - /// - storageProof: Storage proof for the storage slot containing the L2 logs root hash. + /// - proof: Storage proof for the storage slot containing the L2 logs root hash. /// @return targetL2LogsRootHash The L2 logs root hash for the specified batch number. function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external diff --git a/test/Receiver.Taiko.t.sol b/test/Receiver.Taiko.t.sol index b687e81..70ec515 100644 --- a/test/Receiver.Taiko.t.sol +++ b/test/Receiver.Taiko.t.sol @@ -88,7 +88,7 @@ contract ReceiverTaikoTest is Test { scpInputs[0] = abi.encode(uint48(blockNumber)); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofInput}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofInput}); // Read message info (auto-generated by broadcast-and-prove.sh) string memory infoPath = "test/payloads/taiko/taikoProofL2-info.json"; @@ -147,7 +147,7 @@ contract ReceiverTaikoTest is Test { scpInputs[0] = abi.encode(uint48(blockNumber)); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofInput}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofInput}); // Read message info (auto-generated by broadcast-and-prove.sh) string memory infoPath = "test/payloads/taiko/taikoProofL2-info.json"; @@ -210,7 +210,7 @@ contract ReceiverTaikoTest is Test { scpInputs[0] = abi.encode(uint48(blockNumber)); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofInput}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofInput}); // Read message info (auto-generated by broadcast-and-prove.sh) string memory infoPath = "test/payloads/taiko/taikoProofL1-info.json"; diff --git a/test/Receiver.ethereum.t.sol b/test/Receiver.ethereum.t.sol index d8cb0b8..cf2f431 100644 --- a/test/Receiver.ethereum.t.sol +++ b/test/Receiver.ethereum.t.sol @@ -152,7 +152,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); (bytes32 broadcasterId, uint256 timestamp) = receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); @@ -211,7 +211,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); vm.expectRevert(ZksyncParentToChildProver.SlotMismatch.selector); receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); diff --git a/test/Receiver.t.sol b/test/Receiver.t.sol index 164f633..903d035 100644 --- a/test/Receiver.t.sol +++ b/test/Receiver.t.sol @@ -153,7 +153,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); (bytes32 broadcasterId, uint256 timestamp) = receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); @@ -225,7 +225,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); (bytes32 broadcasterId, uint256 timestamp) = receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); @@ -298,7 +298,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); (bytes32 broadcasterId, uint256 timestamp) = receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); @@ -369,7 +369,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -442,7 +442,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -507,7 +507,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = inputForOPChildToParentProver; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); @@ -579,7 +579,7 @@ contract ReceiverTest is Test { ); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000074657374; // "test" address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -656,7 +656,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -737,7 +737,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = inputForOPChildToParentProver; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); @@ -807,7 +807,7 @@ contract ReceiverTest is Test { ); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000074657374; // "test" address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -884,7 +884,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -965,7 +965,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = inputForOPChildToParentProver; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); @@ -1035,7 +1035,7 @@ contract ReceiverTest is Test { ); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000074657374; // "test" address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -1112,7 +1112,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); @@ -1193,7 +1193,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = inputForOPChildToParentProver; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); @@ -1263,7 +1263,7 @@ contract ReceiverTest is Test { ); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000074657374; // "test" address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -1400,7 +1400,7 @@ contract ReceiverTest is Test { scpInputs[0] = abi.encode(batchIndex); IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofInput}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofInput}); (bytes32 broadcasterId, uint256 timestamp) = receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); @@ -1474,7 +1474,7 @@ contract ReceiverTest is Test { bytes memory storageProofToLastProver = smtProof; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); // Calculate expected message hash from the slot // The slot is keccak256(abi.encode(message, publisher)) diff --git a/test/VerifyBroadcastMessageBenchmark.t.sol b/test/VerifyBroadcastMessageBenchmark.t.sol index 87ce0cb..1ac28e9 100644 --- a/test/VerifyBroadcastMessageBenchmark.t.sol +++ b/test/VerifyBroadcastMessageBenchmark.t.sol @@ -87,7 +87,7 @@ contract VerifyBroadcastMessageBenchmark is Test { scpInputs[0] = abi.encode(uint48(blockNumber)); IReceiver.RemoteReadArgs memory args = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProof}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProof}); // Call and snapshot receiver.verifyBroadcastMessage(args, message, publisher); @@ -136,7 +136,7 @@ contract VerifyBroadcastMessageBenchmark is Test { scpInputs[0] = abi.encode(batchIndex); IReceiver.RemoteReadArgs memory args = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProof}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProof}); // Call and snapshot receiver.verifyBroadcastMessage(args, message, publisher); @@ -184,7 +184,7 @@ contract VerifyBroadcastMessageBenchmark is Test { scpInputs[0] = abi.encode(l2BlockNumber); IReceiver.RemoteReadArgs memory args = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: smtProof}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: smtProof}); // Call and snapshot receiver.verifyBroadcastMessage(args, message, publisher); @@ -275,7 +275,7 @@ contract VerifyBroadcastMessageBenchmark is Test { bytes memory storageProofToLastProver = input; IReceiver.RemoteReadArgs memory remoteReadArgs = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProofToLastProver}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); receiver.verifyBroadcastMessage(remoteReadArgs, message, publisher); vm.snapshotGasLastCall("verifyBroadcastMessage", "ZkSyncL2ToEthereum"); @@ -333,7 +333,7 @@ contract VerifyBroadcastMessageBenchmark is Test { scpInputs[0] = abi.encode(uint48(blockNumber)); IReceiver.RemoteReadArgs memory args = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProof}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProof}); // Call and snapshot receiver.verifyBroadcastMessage(args, message, publisher); @@ -382,7 +382,7 @@ contract VerifyBroadcastMessageBenchmark is Test { scpInputs[0] = bytes(""); IReceiver.RemoteReadArgs memory args = - IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, storageProof: storageProof}); + IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProof}); // Call and snapshot receiver.verifyBroadcastMessage(args, message, publisher); From 72ef860374165541277a34f1d73cba1c079a0d0f Mon Sep 17 00:00:00 2001 From: Luiz Date: Mon, 26 Jan 2026 12:04:08 -0300 Subject: [PATCH 09/25] rename --- scripts/taiko/provers-l2.s.sol | 6 +- scripts/taiko/provers.s.sol | 6 +- src/contracts/Receiver.sol | 10 +- test/BlockHashProverPointer.t.sol | 22 ++-- test/Receiver.Taiko.t.sol | 20 ++-- test/Receiver.ethereum.t.sol | 14 +-- test/Receiver.t.sol | 130 ++++++++++----------- test/VerifyBroadcastMessageBenchmark.t.sol | 6 +- 8 files changed, 107 insertions(+), 107 deletions(-) diff --git a/scripts/taiko/provers-l2.s.sol b/scripts/taiko/provers-l2.s.sol index 1db9d4d..d3d54a2 100644 --- a/scripts/taiko/provers-l2.s.sol +++ b/scripts/taiko/provers-l2.s.sol @@ -24,13 +24,13 @@ contract DeployL2Prover is Script { homeChainId ); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); - blockHashProverPointer.setImplementationAddress(address(childToParentProver)); + StateProverPointer stateProverPointer = new StateProverPointer(owner); + stateProverPointer.setImplementationAddress(address(childToParentProver)); vm.stopBroadcast(); console.log("ChildToParentProver:", address(childToParentProver)); - console.log("L2ProverPointer:", address(blockHashProverPointer)); + console.log("L2ProverPointer:", address(stateProverPointer)); } } diff --git a/scripts/taiko/provers.s.sol b/scripts/taiko/provers.s.sol index fb970ed..48b8aa3 100644 --- a/scripts/taiko/provers.s.sol +++ b/scripts/taiko/provers.s.sol @@ -24,12 +24,12 @@ contract DeployL1Prover is Script { homeChainId ); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); - blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); + StateProverPointer stateProverPointer = new StateProverPointer(owner); + stateProverPointer.setImplementationAddress(address(parentToChildProver)); vm.stopBroadcast(); console.log("ParentToChildProver:", address(parentToChildProver)); - console.log("L1ProverPointer:", address(blockHashProverPointer)); + console.log("L1ProverPointer:", address(stateProverPointer)); } } \ No newline at end of file diff --git a/src/contracts/Receiver.sol b/src/contracts/Receiver.sol index 43084c3..8c74080 100644 --- a/src/contracts/Receiver.sol +++ b/src/contracts/Receiver.sol @@ -15,7 +15,7 @@ import {BLOCK_HASH_PROVER_POINTER_SLOT} from "./StateProverPointer.sol"; /// The verification process ensures that a message was actually broadcast on a remote chain /// at a specific timestamp without requiring trust in intermediaries. contract Receiver is IReceiver { - mapping(bytes32 blockHashProverPointerId => IStateProver stateProverCopy) private _blockHashProverCopies; + mapping(bytes32 stateProverPointerId => IStateProver stateProverCopy) private _stateProverCopies; error InvalidRouteLength(); error EmptyRoute(); @@ -93,13 +93,13 @@ contract Receiver is IReceiver { revert DifferentCodeHash(); } - IStateProver oldProverCopy = _blockHashProverCopies[bhpPointerId]; + IStateProver oldProverCopy = _stateProverCopies[bhpPointerId]; if (address(oldProverCopy) != address(0) && oldProverCopy.version() >= bhpCopy.version()) { revert NewerProverVersion(); } - _blockHashProverCopies[bhpPointerId] = bhpCopy; + _stateProverCopies[bhpPointerId] = bhpCopy; } /// @notice The StateProverCopy on the local chain corresponding to the bhpPointerId @@ -107,7 +107,7 @@ contract Receiver is IReceiver { /// @param bhpPointerId The unique identifier of the StateProverPointer. /// @return bhpCopy The StateProver copy stored on the local chain, or address(0) if not found. function stateProverCopy(bytes32 bhpPointerId) external view returns (IStateProver bhpCopy) { - bhpCopy = _blockHashProverCopies[bhpPointerId]; + bhpCopy = _stateProverCopies[bhpPointerId]; } function _readRemoteSlot(RemoteReadArgs calldata readArgs) @@ -133,7 +133,7 @@ contract Receiver is IReceiver { prover = IStateProver(IStateProverPointer(readArgs.route[0]).implementationAddress()); blockHash = prover.getTargetStateCommitment(readArgs.scpInputs[0]); } else { - prover = _blockHashProverCopies[remoteAccountId]; + prover = _stateProverCopies[remoteAccountId]; if (address(prover) == address(0)) { revert ProverCopyNotFound(); } diff --git a/test/BlockHashProverPointer.t.sol b/test/BlockHashProverPointer.t.sol index cb0657b..f04a90a 100644 --- a/test/BlockHashProverPointer.t.sol +++ b/test/BlockHashProverPointer.t.sol @@ -7,50 +7,50 @@ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {MockProver} from "./mocks/MockProver.sol"; contract StateProverPointerTest is Test { - StateProverPointer public blockHashProverPointer; + StateProverPointer public stateProverPointer; MockProver public mockProver; address public owner = makeAddr("owner"); function setUp() public { - blockHashProverPointer = new StateProverPointer(owner); + stateProverPointer = new StateProverPointer(owner); mockProver = new MockProver(); } function test_checkOwner() public view { - assertEq(blockHashProverPointer.owner(), owner); + assertEq(stateProverPointer.owner(), owner); } function test_setImplementationAddress() public { vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(mockProver)); - assertEq(blockHashProverPointer.implementationAddress(), address(mockProver)); - assertEq(blockHashProverPointer.implementationCodeHash(), address(mockProver).codehash); + stateProverPointer.setImplementationAddress(address(mockProver)); + assertEq(stateProverPointer.implementationAddress(), address(mockProver)); + assertEq(stateProverPointer.implementationCodeHash(), address(mockProver).codehash); } function test_setImplementationAddress_reverts_if_not_owner() public { vm.prank(makeAddr("notOwner")); vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, makeAddr("notOwner"))); - blockHashProverPointer.setImplementationAddress(address(mockProver)); + stateProverPointer.setImplementationAddress(address(mockProver)); } function test_setImplementationAddress_reverts_if_version_is_not_increasing() public { vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(mockProver)); + stateProverPointer.setImplementationAddress(address(mockProver)); vm.prank(owner); vm.expectRevert(abi.encodeWithSelector(StateProverPointer.NonIncreasingVersion.selector, 1, 1)); - blockHashProverPointer.setImplementationAddress(address(mockProver)); + stateProverPointer.setImplementationAddress(address(mockProver)); } function test_setImplementationAddress_reverts_if_implementation_address_is_invalid() public { vm.prank(owner); vm.expectRevert(abi.encodeWithSelector(StateProverPointer.InvalidImplementationAddress.selector)); - blockHashProverPointer.setImplementationAddress(address(0)); + stateProverPointer.setImplementationAddress(address(0)); } function test_setImplementationAddress_reverts_if_implementation_address_is_invalid_eoa() public { vm.prank(owner); vm.expectRevert(abi.encodeWithSelector(StateProverPointer.InvalidImplementationAddress.selector)); - blockHashProverPointer.setImplementationAddress(makeAddr("invalid")); + stateProverPointer.setImplementationAddress(makeAddr("invalid")); } } diff --git a/test/Receiver.Taiko.t.sol b/test/Receiver.Taiko.t.sol index 70ec515..aa8dedf 100644 --- a/test/Receiver.Taiko.t.sol +++ b/test/Receiver.Taiko.t.sol @@ -25,7 +25,7 @@ contract ReceiverTaikoTest is Test { Receiver public receiver; TaikoParentToChildProver public parentToChildProver; TaikoChildToParentProver public childToParentProver; - StateProverPointer public blockHashProverPointer; + StateProverPointer public stateProverPointer; // Note: We don't use forks anymore to avoid dependency on Taiko internal testnet // which can be reset at any time. Instead, we use local mocks with vm.chainId(). @@ -48,10 +48,10 @@ contract ReceiverTaikoTest is Test { receiver = new Receiver(); parentToChildProver = new TaikoParentToChildProver(L1_SIGNAL_SERVICE, CHECKPOINTS_SLOT, L1_CHAIN_ID); - blockHashProverPointer = new StateProverPointer(owner); + stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); + stateProverPointer.setImplementationAddress(address(parentToChildProver)); // Read proof data string memory proofPath = "test/payloads/taiko/taikoProofL2.json"; @@ -82,7 +82,7 @@ contract ReceiverTaikoTest is Test { bytes memory storageProofInput = abi.encode(rlpBlockHeader, account, slot, rlpAccountProof, rlpStorageProof); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(uint48(blockNumber)); @@ -111,10 +111,10 @@ contract ReceiverTaikoTest is Test { receiver = new Receiver(); parentToChildProver = new TaikoParentToChildProver(L1_SIGNAL_SERVICE, CHECKPOINTS_SLOT, L1_CHAIN_ID); - blockHashProverPointer = new StateProverPointer(owner); + stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); + stateProverPointer.setImplementationAddress(address(parentToChildProver)); // Read proof data string memory proofPath = "test/payloads/taiko/taikoProofL2.json"; @@ -141,7 +141,7 @@ contract ReceiverTaikoTest is Test { bytes memory storageProofInput = abi.encode(rlpBlockHeader, account, slot, rlpAccountProof, rlpStorageProof); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(uint48(blockNumber)); @@ -171,10 +171,10 @@ contract ReceiverTaikoTest is Test { receiver = new Receiver(); childToParentProver = new TaikoChildToParentProver(L2_SIGNAL_SERVICE, CHECKPOINTS_SLOT, L2_CHAIN_ID); - blockHashProverPointer = new StateProverPointer(owner); + stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(childToParentProver)); + stateProverPointer.setImplementationAddress(address(childToParentProver)); // Read proof data string memory proofPath = "test/payloads/taiko/taikoProofL1.json"; @@ -204,7 +204,7 @@ contract ReceiverTaikoTest is Test { bytes memory storageProofInput = abi.encode(rlpBlockHeader, account, slot, rlpAccountProof, rlpStorageProof); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(uint48(blockNumber)); diff --git a/test/Receiver.ethereum.t.sol b/test/Receiver.ethereum.t.sol index cf2f431..6c7a356 100644 --- a/test/Receiver.ethereum.t.sol +++ b/test/Receiver.ethereum.t.sol @@ -129,10 +129,10 @@ contract ReceiverTest is Test { ZksyncParentToChildProver parentToChildProver = new ZksyncParentToChildProver(address(mockZkChain), 0, 300, 32657, block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); + stateProverPointer.setImplementationAddress(address(parentToChildProver)); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000074657374; // "test" address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -144,7 +144,7 @@ contract ReceiverTest is Test { bytes memory input = abi.encode(proof, publisher, message); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(47506); @@ -167,7 +167,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), expectedAccount @@ -188,10 +188,10 @@ contract ReceiverTest is Test { ZksyncParentToChildProver parentToChildProver = new ZksyncParentToChildProver(address(mockZkChain), 0, 300, 32657, block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); + stateProverPointer.setImplementationAddress(address(parentToChildProver)); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000000000000; address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -203,7 +203,7 @@ contract ReceiverTest is Test { bytes memory input = abi.encode(proof, publisher, message); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(47506); diff --git a/test/Receiver.t.sol b/test/Receiver.t.sol index 903d035..9a9827e 100644 --- a/test/Receiver.t.sol +++ b/test/Receiver.t.sol @@ -105,10 +105,10 @@ contract ReceiverTest is Test { receiver = new Receiver(); ArbChildToParentProver childToParentProver = new ArbChildToParentProver(block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(childToParentProver)); + stateProverPointer.setImplementationAddress(address(childToParentProver)); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000074657374; // "test" address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -145,7 +145,7 @@ contract ReceiverTest is Test { bytes memory input = abi.encode(rlpBlockHeader, account, expectedSlot, rlpAccountProof, rlpStorageProof); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(blockNumber); @@ -164,7 +164,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), account @@ -181,10 +181,10 @@ contract ReceiverTest is Test { receiver = new Receiver(); ArbParentToChildProver parentToChildProver = _getOnChainArbProverCopy(); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); + stateProverPointer.setImplementationAddress(address(parentToChildProver)); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000074657374; // "test" address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -217,7 +217,7 @@ contract ReceiverTest is Test { outbox.updateSendRoot(sendRoot, blockHash); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(sendRoot); @@ -236,7 +236,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), account @@ -253,10 +253,10 @@ contract ReceiverTest is Test { OPChildToParentProver childToParentProver = new OPChildToParentProver(block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(childToParentProver)); + stateProverPointer.setImplementationAddress(address(childToParentProver)); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000074657374; // "test" address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -290,7 +290,7 @@ contract ReceiverTest is Test { ); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = bytes(""); @@ -309,7 +309,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), account @@ -327,10 +327,10 @@ contract ReceiverTest is Test { OPChildToParentProver childToParentProver = new OPChildToParentProver(block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(childToParentProver)); + stateProverPointer.setImplementationAddress(address(childToParentProver)); uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; @@ -361,7 +361,7 @@ contract ReceiverTest is Test { ); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = bytes(""); @@ -382,7 +382,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), account @@ -400,10 +400,10 @@ contract ReceiverTest is Test { OPChildToParentProver childToParentProver = new OPChildToParentProver(block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(childToParentProver)); + stateProverPointer.setImplementationAddress(address(childToParentProver)); uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; @@ -434,7 +434,7 @@ contract ReceiverTest is Test { ); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = bytes(""); @@ -457,14 +457,14 @@ contract ReceiverTest is Test { OPChildToParentProver childToParentProver = new OPChildToParentProver(block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); address arbParentToChildProverPointerAddress; vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(childToParentProver)); + stateProverPointer.setImplementationAddress(address(childToParentProver)); // Update the Arbitrum Prover (ParentToChildProver) copy on OP chain { uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; @@ -499,7 +499,7 @@ contract ReceiverTest is Test { ); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = bytes(""); @@ -518,7 +518,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), account @@ -563,7 +563,7 @@ contract ReceiverTest is Test { ); address[] memory route = new address[](2); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); route[1] = arbParentToChildProverPointerAddress; bytes memory input0 = bytes(""); @@ -593,7 +593,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), arbParentToChildProverPointerAddress @@ -616,10 +616,10 @@ contract ReceiverTest is Test { ZksyncChildToParentProver childToParentProver = new ZksyncChildToParentProver(address(buffer), block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(childToParentProver)); + stateProverPointer.setImplementationAddress(address(childToParentProver)); uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; @@ -648,7 +648,7 @@ contract ReceiverTest is Test { buffer.receiveHashes(blockNumber, blockHashes); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(blockNumber); @@ -669,7 +669,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), account @@ -689,14 +689,14 @@ contract ReceiverTest is Test { ZksyncChildToParentProver childToParentProver = new ZksyncChildToParentProver(address(buffer), block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); address arbParentToChildProverPointerAddress; vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(childToParentProver)); + stateProverPointer.setImplementationAddress(address(childToParentProver)); // Update the Arbitrum Prover (ParentToChildProver) copy on ZKSync chain { uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; @@ -729,7 +729,7 @@ contract ReceiverTest is Test { buffer.receiveHashes(blockNumber, blockHashes); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(blockNumber); @@ -748,7 +748,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), account @@ -791,7 +791,7 @@ contract ReceiverTest is Test { buffer.receiveHashes(blockNumberEthereum, blockHashes); address[] memory route = new address[](2); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); route[1] = arbParentToChildProverPointerAddress; bytes memory input0 = abi.encode(blockNumberEthereum); @@ -821,7 +821,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), arbParentToChildProverPointerAddress @@ -844,10 +844,10 @@ contract ReceiverTest is Test { LineaChildToParentProver childToParentProver = new LineaChildToParentProver(address(buffer), block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(childToParentProver)); + stateProverPointer.setImplementationAddress(address(childToParentProver)); uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; @@ -876,7 +876,7 @@ contract ReceiverTest is Test { buffer.receiveHashes(blockNumber, blockHashes); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(blockNumber); @@ -897,7 +897,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), account @@ -917,14 +917,14 @@ contract ReceiverTest is Test { LineaChildToParentProver childToParentProver = new LineaChildToParentProver(address(buffer), block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); address arbParentToChildProverPointerAddress; vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(childToParentProver)); + stateProverPointer.setImplementationAddress(address(childToParentProver)); // Update the Arbitrum Prover (ParentToChildProver) copy on Linea chain { uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; @@ -957,7 +957,7 @@ contract ReceiverTest is Test { buffer.receiveHashes(blockNumber, blockHashes); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(blockNumber); @@ -976,7 +976,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), account @@ -1019,7 +1019,7 @@ contract ReceiverTest is Test { buffer.receiveHashes(blockNumberEthereum, blockHashes); address[] memory route = new address[](2); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); route[1] = arbParentToChildProverPointerAddress; bytes memory input0 = abi.encode(blockNumberEthereum); @@ -1049,7 +1049,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), arbParentToChildProverPointerAddress @@ -1072,10 +1072,10 @@ contract ReceiverTest is Test { ScrollChildToParentProver childToParentProver = new ScrollChildToParentProver(address(buffer), block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(childToParentProver)); + stateProverPointer.setImplementationAddress(address(childToParentProver)); uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; @@ -1104,7 +1104,7 @@ contract ReceiverTest is Test { buffer.receiveHashes(blockNumber, blockHashes); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(blockNumber); @@ -1125,7 +1125,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), account @@ -1145,14 +1145,14 @@ contract ReceiverTest is Test { ScrollChildToParentProver childToParentProver = new ScrollChildToParentProver(address(buffer), block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); address arbParentToChildProverPointerAddress; vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(childToParentProver)); + stateProverPointer.setImplementationAddress(address(childToParentProver)); // Update the Arbitrum Prover (ParentToChildProver) copy on Scroll chain { uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; @@ -1185,7 +1185,7 @@ contract ReceiverTest is Test { buffer.receiveHashes(blockNumber, blockHashes); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(blockNumber); @@ -1204,7 +1204,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), account @@ -1247,7 +1247,7 @@ contract ReceiverTest is Test { buffer.receiveHashes(blockNumberEthereum, blockHashes); address[] memory route = new address[](2); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); route[1] = arbParentToChildProverPointerAddress; bytes memory input0 = abi.encode(blockNumberEthereum); @@ -1277,7 +1277,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), arbParentToChildProverPointerAddress @@ -1306,10 +1306,10 @@ contract ReceiverTest is Test { ScrollParentToChildProver parentToChildProver = new ScrollParentToChildProver(scrollChain, finalizedStateRootsSlot, homeChainId); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); + stateProverPointer.setImplementationAddress(address(parentToChildProver)); // Load the E2E proof data string memory path = "test/payloads/scroll/e2e-proof.json"; @@ -1362,10 +1362,10 @@ contract ReceiverTest is Test { ScrollParentToChildProver parentToChildProver = new ScrollParentToChildProver(scrollChain, finalizedStateRootsSlot, homeChainId); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); + stateProverPointer.setImplementationAddress(address(parentToChildProver)); // Load the E2E proof data string memory path = "test/payloads/scroll/e2e-proof.json"; @@ -1394,7 +1394,7 @@ contract ReceiverTest is Test { bytes memory storageProofInput = abi.encode(account, storageSlot, rlpAccountProof, rlpStorageProof); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(batchIndex); @@ -1411,7 +1411,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), account @@ -1440,10 +1440,10 @@ contract ReceiverTest is Test { LineaParentToChildProver parentToChildProver = new LineaParentToChildProver(lineaRollup, stateRootHashesSlot, homeChainId); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); + stateProverPointer.setImplementationAddress(address(parentToChildProver)); // Read the SMT proof data string memory path = "test/payloads/linea/lineaProofL2-smt.json"; @@ -1466,7 +1466,7 @@ contract ReceiverTest is Test { // Construct the route address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(l2BlockNumber); @@ -1496,7 +1496,7 @@ contract ReceiverTest is Test { keccak256( abi.encode( bytes32(0x0000000000000000000000000000000000000000000000000000000000000000), - address(blockHashProverPointer) + address(stateProverPointer) ) ), account diff --git a/test/VerifyBroadcastMessageBenchmark.t.sol b/test/VerifyBroadcastMessageBenchmark.t.sol index 1ac28e9..80b83be 100644 --- a/test/VerifyBroadcastMessageBenchmark.t.sol +++ b/test/VerifyBroadcastMessageBenchmark.t.sol @@ -254,10 +254,10 @@ contract VerifyBroadcastMessageBenchmark is Test { receiver = new Receiver(); ZksyncP2C parentToChildProver = new ZksyncP2C(address(mockZkChain), 0, 300, 32657, block.chainid); - StateProverPointer blockHashProverPointer = new StateProverPointer(owner); + StateProverPointer stateProverPointer = new StateProverPointer(owner); vm.prank(owner); - blockHashProverPointer.setImplementationAddress(address(parentToChildProver)); + stateProverPointer.setImplementationAddress(address(parentToChildProver)); bytes32 message = 0x0000000000000000000000000000000000000000000000000000000074657374; // "test" address publisher = 0x9a56fFd72F4B526c523C733F1F74197A51c495E1; @@ -267,7 +267,7 @@ contract VerifyBroadcastMessageBenchmark is Test { bytes memory input = abi.encode(proof, publisher, message); address[] memory route = new address[](1); - route[0] = address(blockHashProverPointer); + route[0] = address(stateProverPointer); bytes[] memory scpInputs = new bytes[](1); scpInputs[0] = abi.encode(47506); From 8c536cf149c2ceaa2fb9290ba66a908cdabd2a1a Mon Sep 17 00:00:00 2001 From: Luiz Date: Mon, 26 Jan 2026 12:17:30 -0300 Subject: [PATCH 10/25] renamings --- src/contracts/Receiver.sol | 40 +++++++++++----------- test/Receiver.t.sol | 32 ++++++++--------- test/VerifyBroadcastMessageBenchmark.t.sol | 4 +-- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/contracts/Receiver.sol b/src/contracts/Receiver.sol index 8c74080..0a17103 100644 --- a/src/contracts/Receiver.sol +++ b/src/contracts/Receiver.sol @@ -71,43 +71,43 @@ contract Receiver is IReceiver { /// 3. The new version is newer than any existing local copy (version monotonicity) /// This allows the Receiver to trustlessly obtain and update StateProver implementations /// needed for cross-chain message verification. - /// @param bhpPointerReadArgs Contains the route and proofs to read the remote StateProverPointer's storage - /// @param bhpCopy The local deployed copy of the StateProver contract - /// @return bhpPointerId A unique identifier for the remote StateProverPointer (accumulated hash of route) + /// @param scpPointerReadArgs Contains the route and proofs to read the remote StateProverPointer's storage + /// @param scpCopy The local deployed copy of the StateProver contract + /// @return scpPointerId A unique identifier for the remote StateProverPointer (accumulated hash of route) /// @custom:throws WrongStateProverPointerSlot if the proof doesn't read from the expected slot /// @custom:throws DifferentCodeHash if the local copy's code hash doesn't match the remote pointer's stored hash /// @custom:throws NewerProverVersion if an existing local copy has a version >= the new copy's version - function updateStateProverCopy(RemoteReadArgs calldata bhpPointerReadArgs, IStateProver bhpCopy) + function updateStateProverCopy(RemoteReadArgs calldata scpPointerReadArgs, IStateProver scpCopy) external - returns (bytes32 bhpPointerId) + returns (bytes32 scpPointerId) { uint256 slot; - bytes32 bhpCodeHash; - (bhpPointerId, slot, bhpCodeHash) = _readRemoteSlot(bhpPointerReadArgs); + bytes32 scpCodeHash; + (scpPointerId, slot, scpCodeHash) = _readRemoteSlot(scpPointerReadArgs); if (slot != uint256(BLOCK_HASH_PROVER_POINTER_SLOT)) { revert WrongStateProverPointerSlot(); } - if (address(bhpCopy).codehash != bhpCodeHash) { + if (address(scpCopy).codehash != scpCodeHash) { revert DifferentCodeHash(); } - IStateProver oldProverCopy = _stateProverCopies[bhpPointerId]; + IStateProver oldProverCopy = _stateProverCopies[scpPointerId]; - if (address(oldProverCopy) != address(0) && oldProverCopy.version() >= bhpCopy.version()) { + if (address(oldProverCopy) != address(0) && oldProverCopy.version() >= scpCopy.version()) { revert NewerProverVersion(); } - _stateProverCopies[bhpPointerId] = bhpCopy; + _stateProverCopies[scpPointerId] = scpCopy; } - /// @notice The StateProverCopy on the local chain corresponding to the bhpPointerId + /// @notice The StateProverCopy on the local chain corresponding to the scpPointerId /// MUST return 0 if the StateProverPointer does not exist. - /// @param bhpPointerId The unique identifier of the StateProverPointer. - /// @return bhpCopy The StateProver copy stored on the local chain, or address(0) if not found. - function stateProverCopy(bytes32 bhpPointerId) external view returns (IStateProver bhpCopy) { - bhpCopy = _stateProverCopies[bhpPointerId]; + /// @param scpPointerId The unique identifier of the StateProverPointer. + /// @return scpCopy The StateProver copy stored on the local chain, or address(0) if not found. + function stateProverCopy(bytes32 scpPointerId) external view returns (IStateProver scpCopy) { + scpCopy = _stateProverCopies[scpPointerId]; } function _readRemoteSlot(RemoteReadArgs calldata readArgs) @@ -124,27 +124,27 @@ contract Receiver is IReceiver { } IStateProver prover; - bytes32 blockHash; + bytes32 stateCommitment; for (uint256 i = 0; i < readArgs.route.length; i++) { remoteAccountId = accumulator(remoteAccountId, readArgs.route[i]); if (i == 0) { prover = IStateProver(IStateProverPointer(readArgs.route[0]).implementationAddress()); - blockHash = prover.getTargetStateCommitment(readArgs.scpInputs[0]); + stateCommitment = prover.getTargetStateCommitment(readArgs.scpInputs[0]); } else { prover = _stateProverCopies[remoteAccountId]; if (address(prover) == address(0)) { revert ProverCopyNotFound(); } - blockHash = prover.verifyTargetStateCommitment(blockHash, readArgs.scpInputs[i]); + stateCommitment = prover.verifyTargetStateCommitment(stateCommitment, readArgs.scpInputs[i]); } } address remoteAccount; - (remoteAccount, slot, slotValue) = prover.verifyStorageSlot(blockHash, readArgs.proof); + (remoteAccount, slot, slotValue) = prover.verifyStorageSlot(stateCommitment, readArgs.proof); remoteAccountId = accumulator(remoteAccountId, remoteAccount); } diff --git a/test/Receiver.t.sol b/test/Receiver.t.sol index 9a9827e..5b027c3 100644 --- a/test/Receiver.t.sol +++ b/test/Receiver.t.sol @@ -373,10 +373,10 @@ contract ReceiverTest is Test { ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); - bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 scpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( - bhpPointerId, + scpPointerId, keccak256( abi.encode( keccak256( @@ -509,10 +509,10 @@ contract ReceiverTest is Test { IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); - bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 scpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( - bhpPointerId, + scpPointerId, keccak256( abi.encode( keccak256( @@ -660,10 +660,10 @@ contract ReceiverTest is Test { ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); - bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 scpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( - bhpPointerId, + scpPointerId, keccak256( abi.encode( keccak256( @@ -739,10 +739,10 @@ contract ReceiverTest is Test { IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); - bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 scpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( - bhpPointerId, + scpPointerId, keccak256( abi.encode( keccak256( @@ -888,10 +888,10 @@ contract ReceiverTest is Test { ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); - bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 scpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( - bhpPointerId, + scpPointerId, keccak256( abi.encode( keccak256( @@ -967,10 +967,10 @@ contract ReceiverTest is Test { IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); - bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 scpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( - bhpPointerId, + scpPointerId, keccak256( abi.encode( keccak256( @@ -1116,10 +1116,10 @@ contract ReceiverTest is Test { ArbParentToChildProver arbParentToChildProverCopy = _getOnChainArbProverCopy(); - bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 scpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( - bhpPointerId, + scpPointerId, keccak256( abi.encode( keccak256( @@ -1195,10 +1195,10 @@ contract ReceiverTest is Test { IReceiver.RemoteReadArgs memory remoteReadArgs = IReceiver.RemoteReadArgs({route: route, scpInputs: scpInputs, proof: storageProofToLastProver}); - bytes32 bhpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); + bytes32 scpPointerId = receiver.updateStateProverCopy(remoteReadArgs, arbParentToChildProverCopy); assertEq( - bhpPointerId, + scpPointerId, keccak256( abi.encode( keccak256( diff --git a/test/VerifyBroadcastMessageBenchmark.t.sol b/test/VerifyBroadcastMessageBenchmark.t.sol index 80b83be..01ad5a1 100644 --- a/test/VerifyBroadcastMessageBenchmark.t.sol +++ b/test/VerifyBroadcastMessageBenchmark.t.sol @@ -424,9 +424,9 @@ contract VerifyBroadcastMessageBenchmark is Test { // Register the Scroll prover copy in receiver's mapping bytes32 acc1 = keccak256(abi.encode(bytes32(0), address(opPointer))); - bytes32 bhpPointerId = keccak256(abi.encode(acc1, scrollPointerAddress)); + bytes32 scpPointerId = keccak256(abi.encode(acc1, scrollPointerAddress)); - bytes32 mappingSlot = keccak256(abi.encode(bhpPointerId, uint256(0))); + bytes32 mappingSlot = keccak256(abi.encode(scpPointerId, uint256(0))); vm.store(address(receiver), mappingSlot, bytes32(uint256(uint160(address(scrollP2CProverCopy))))); // Load Ethereum proof for first hop From 320a463f00765036445b4d1fe7b7700916f891ff Mon Sep 17 00:00:00 2001 From: Luiz Date: Mon, 26 Jan 2026 12:23:07 -0300 Subject: [PATCH 11/25] renaming --- README.md | 4 ++-- src/contracts/Receiver.sol | 6 +++--- src/contracts/StateProverPointer.sol | 6 +++--- test/Receiver.ethereum.t.sol | 2 +- test/Receiver.t.sol | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 253b1a6..db3575d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Ethereum reference implementation for [ERC-7888: Crosschain Broadcaster](https:/ - **Broadcast**: `Broadcaster` stores `block.timestamp` in slot `keccak(message, publisher)`, emits `MessageBroadcast`, and prevents duplicates per publisher. - **Prove**: `Receiver` walks a user-specified route of `StateProver` contracts to recover a finalized target block hash, proves a storage slot on a remote `Broadcaster`, checks the slot is non-zero and matches the expected `(message, publisher)` slot, then returns the timestamp. -- **Upgrade safely**: `StateProverPointer` holds the latest prover implementation address and code hash in a fixed slot (`BLOCK_HASH_PROVER_POINTER_SLOT`), enforcing monotonic `version()` upgrades so routes stay stable while provers evolve. +- **Upgrade safely**: `StateProverPointer` holds the latest prover implementation address and code hash in a fixed slot (`STATE_PROVER_POINTER_SLOT`), enforcing monotonic `version()` upgrades so routes stay stable while provers evolve. - **Reusable proving code**: `StateProver` copies can be deployed on any chain; the pointer-stored code hash guarantees the copy matches the canonical implementation. ## Contracts @@ -18,7 +18,7 @@ Ethereum reference implementation for [ERC-7888: Crosschain Broadcaster](https:/ - **Broadcaster**: Singleton per chain that timestamps 32-byte messages in deterministic slots and emits `MessageBroadcast`. - **Receiver**: Trustlessly reads a remote `Broadcaster` slot by following a prover route, checking slot correctness, and returning `(broadcasterId, timestamp)`. - **StateProver**: Chain-specific verifier that proves a target block hash from a home chain state root and verifies arbitrary storage for that block. -- **StateProverPointer**: Stable address that stores the prover implementation address and code hash in `BLOCK_HASH_PROVER_POINTER_SLOT`, enforcing increasing `version()`. +- **StateProverPointer**: Stable address that stores the prover implementation address and code hash in `STATE_PROVER_POINTER_SLOT`, enforcing increasing `version()`. - **StateProverCopy**: Locally deployed prover contract whose `codehash` matches the pointer; used by `Receiver` when proving multi-hop routes. - **Route**: Ordered addresses of prover pointers from the destination back to the origin chain; hashed cumulatively in `Receiver` to produce unique IDs. diff --git a/src/contracts/Receiver.sol b/src/contracts/Receiver.sol index 0a17103..b24d5e6 100644 --- a/src/contracts/Receiver.sol +++ b/src/contracts/Receiver.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.30; import {IReceiver} from "./interfaces/IReceiver.sol"; import {IStateProver} from "./interfaces/IStateProver.sol"; import {IStateProverPointer} from "./interfaces/IStateProverPointer.sol"; -import {BLOCK_HASH_PROVER_POINTER_SLOT} from "./StateProverPointer.sol"; +import {STATE_PROVER_POINTER_SLOT} from "./StateProverPointer.sol"; /// @title Receiver /// @notice Verifies broadcast messages from remote chains using cryptographic storage proofs @@ -66,7 +66,7 @@ contract Receiver is IReceiver { /// @notice Updates the local copy of a StateProver for a specific remote chain /// @dev This function verifies and stores a local copy of a StateProver contract from a remote chain. /// The verification process ensures: - /// 1. The provided proof reads from the correct storage slot (BLOCK_HASH_PROVER_POINTER_SLOT) + /// 1. The provided proof reads from the correct storage slot (STATE_PROVER_POINTER_SLOT) /// 2. The code hash of the local copy matches the code hash stored in the remote pointer /// 3. The new version is newer than any existing local copy (version monotonicity) /// This allows the Receiver to trustlessly obtain and update StateProver implementations @@ -85,7 +85,7 @@ contract Receiver is IReceiver { bytes32 scpCodeHash; (scpPointerId, slot, scpCodeHash) = _readRemoteSlot(scpPointerReadArgs); - if (slot != uint256(BLOCK_HASH_PROVER_POINTER_SLOT)) { + if (slot != uint256(STATE_PROVER_POINTER_SLOT)) { revert WrongStateProverPointerSlot(); } diff --git a/src/contracts/StateProverPointer.sol b/src/contracts/StateProverPointer.sol index 55de0e1..e48368c 100644 --- a/src/contracts/StateProverPointer.sol +++ b/src/contracts/StateProverPointer.sol @@ -6,7 +6,7 @@ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {IStateProver} from "./interfaces/IStateProver.sol"; import {IStateProverPointer} from "./interfaces/IStateProverPointer.sol"; -bytes32 constant BLOCK_HASH_PROVER_POINTER_SLOT = bytes32(uint256(keccak256("eip7888.pointer.slot")) - 1); +bytes32 constant STATE_PROVER_POINTER_SLOT = bytes32(uint256(keccak256("eip7888.pointer.slot")) - 1); /// @title StateProverPointer /// @notice Manages a versioned pointer to the latest StateProver implementation @@ -30,7 +30,7 @@ contract StateProverPointer is IStateProverPointer, Ownable { /// @notice Return the code hash of the latest version of the prover. /// @return codeHash The code hash of the current implementation stored in the pointer slot. function implementationCodeHash() public view returns (bytes32 codeHash) { - codeHash = StorageSlot.getBytes32Slot(BLOCK_HASH_PROVER_POINTER_SLOT).value; + codeHash = StorageSlot.getBytes32Slot(STATE_PROVER_POINTER_SLOT).value; } /// @notice Updates the StateProver implementation to a new version @@ -65,6 +65,6 @@ contract StateProverPointer is IStateProverPointer, Ownable { } function _setCodeHash(bytes32 _codeHash) internal { - StorageSlot.getBytes32Slot(BLOCK_HASH_PROVER_POINTER_SLOT).value = _codeHash; + StorageSlot.getBytes32Slot(STATE_PROVER_POINTER_SLOT).value = _codeHash; } } diff --git a/test/Receiver.ethereum.t.sol b/test/Receiver.ethereum.t.sol index 6c7a356..9b098c0 100644 --- a/test/Receiver.ethereum.t.sol +++ b/test/Receiver.ethereum.t.sol @@ -8,7 +8,7 @@ import {IReceiver} from "../src/contracts/interfaces/IReceiver.sol"; import {IStateProver} from "../src/contracts/interfaces/IStateProver.sol"; import {IOutbox} from "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol"; import {IStateProverPointer} from "../src/contracts/interfaces/IStateProverPointer.sol"; -import {BLOCK_HASH_PROVER_POINTER_SLOT} from "../src/contracts/StateProverPointer.sol"; +import {STATE_PROVER_POINTER_SLOT} from "../src/contracts/StateProverPointer.sol"; import {BlockHeaders} from "./utils/BlockHeaders.sol"; import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {BufferMock} from "./mocks/BufferMock.sol"; diff --git a/test/Receiver.t.sol b/test/Receiver.t.sol index 5b027c3..85a9d73 100644 --- a/test/Receiver.t.sol +++ b/test/Receiver.t.sol @@ -8,7 +8,7 @@ import {IReceiver} from "../src/contracts/interfaces/IReceiver.sol"; import {IStateProver} from "../src/contracts/interfaces/IStateProver.sol"; import {IOutbox} from "@arbitrum/nitro-contracts/src/bridge/IOutbox.sol"; import {IStateProverPointer} from "../src/contracts/interfaces/IStateProverPointer.sol"; -import {BLOCK_HASH_PROVER_POINTER_SLOT} from "../src/contracts/StateProverPointer.sol"; +import {STATE_PROVER_POINTER_SLOT} from "../src/contracts/StateProverPointer.sol"; import {BlockHeaders} from "./utils/BlockHeaders.sol"; import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {BufferMock} from "./mocks/BufferMock.sol"; From 16f6c1a236579d84f9f4bbcb3367e1fdf1ee6b15 Mon Sep 17 00:00:00 2001 From: Luiz Date: Mon, 26 Jan 2026 13:19:36 -0300 Subject: [PATCH 12/25] update deployments --- snapshots/verifyBroadcastMessage.json | 12 ++++++------ test/Receiver.t.sol | 18 +++++++++--------- .../arb_pointer_proof_block_10128554.json | 11 +++++++++++ 3 files changed, 26 insertions(+), 15 deletions(-) create mode 100644 test/payloads/ethereum/arb_pointer_proof_block_10128554.json diff --git a/snapshots/verifyBroadcastMessage.json b/snapshots/verifyBroadcastMessage.json index a5222a6..3d9d274 100644 --- a/snapshots/verifyBroadcastMessage.json +++ b/snapshots/verifyBroadcastMessage.json @@ -1,9 +1,9 @@ { - "EthereumToOptimism": "1642626", - "EthereumToTaikoL2": "1055645", - "LineaL2ToEthereum": "2551772", - "ScrollL2ToEthereum": "1363073", + "EthereumToOptimism": "1642608", + "EthereumToTaikoL2": "1055627", + "LineaL2ToEthereum": "2551776", + "ScrollL2ToEthereum": "1363077", "ScrollToOptimism": "1349825", - "TaikoL2ToEthereum": "1025708", - "ZkSyncL2ToEthereum": "125497" + "TaikoL2ToEthereum": "1025690", + "ZkSyncL2ToEthereum": "125479" } \ No newline at end of file diff --git a/test/Receiver.t.sol b/test/Receiver.t.sol index 85a9d73..a7f1aaf 100644 --- a/test/Receiver.t.sol +++ b/test/Receiver.t.sol @@ -61,7 +61,7 @@ contract ReceiverTest is Test { IOutbox public outbox; // On-chain deployed ArbParentToChildProver on Sepolia - address constant ON_CHAIN_ARB_PROVER = 0x9e8BA3Ce052f2139f824885a78240839749F3370; + address constant ON_CHAIN_ARB_PROVER = 0x2aA03593adf471d6dd7c041984e6D7D6045E373f; address owner = makeAddr("owner"); @@ -334,7 +334,7 @@ contract ReceiverTest is Test { uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; - string memory path = "test/payloads/ethereum/arb_pointer_proof_block_9868604.json"; + string memory path = "test/payloads/ethereum/arb_pointer_proof_block_10128554.json"; string memory json = vm.readFile(path); uint256 blockNumber = json.readUint(".blockNumber"); @@ -469,7 +469,7 @@ contract ReceiverTest is Test { { uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; - string memory path = "test/payloads/ethereum/arb_pointer_proof_block_9868604.json"; + string memory path = "test/payloads/ethereum/arb_pointer_proof_block_10128554.json"; string memory json = vm.readFile(path); uint256 blockNumber = json.readUint(".blockNumber"); @@ -623,7 +623,7 @@ contract ReceiverTest is Test { uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; - string memory path = "test/payloads/ethereum/arb_pointer_proof_block_9868604.json"; + string memory path = "test/payloads/ethereum/arb_pointer_proof_block_10128554.json"; string memory json = vm.readFile(path); uint256 blockNumber = json.readUint(".blockNumber"); @@ -701,7 +701,7 @@ contract ReceiverTest is Test { { uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; - string memory path = "test/payloads/ethereum/arb_pointer_proof_block_9868604.json"; + string memory path = "test/payloads/ethereum/arb_pointer_proof_block_10128554.json"; string memory json = vm.readFile(path); uint256 blockNumber = json.readUint(".blockNumber"); @@ -851,7 +851,7 @@ contract ReceiverTest is Test { uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; - string memory path = "test/payloads/ethereum/arb_pointer_proof_block_9868604.json"; + string memory path = "test/payloads/ethereum/arb_pointer_proof_block_10128554.json"; string memory json = vm.readFile(path); uint256 blockNumber = json.readUint(".blockNumber"); @@ -929,7 +929,7 @@ contract ReceiverTest is Test { { uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; - string memory path = "test/payloads/ethereum/arb_pointer_proof_block_9868604.json"; + string memory path = "test/payloads/ethereum/arb_pointer_proof_block_10128554.json"; string memory json = vm.readFile(path); uint256 blockNumber = json.readUint(".blockNumber"); @@ -1079,7 +1079,7 @@ contract ReceiverTest is Test { uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; - string memory path = "test/payloads/ethereum/arb_pointer_proof_block_9868604.json"; + string memory path = "test/payloads/ethereum/arb_pointer_proof_block_10128554.json"; string memory json = vm.readFile(path); uint256 blockNumber = json.readUint(".blockNumber"); @@ -1157,7 +1157,7 @@ contract ReceiverTest is Test { { uint256 expectedSlot = uint256(keccak256("eip7888.pointer.slot")) - 1; - string memory path = "test/payloads/ethereum/arb_pointer_proof_block_9868604.json"; + string memory path = "test/payloads/ethereum/arb_pointer_proof_block_10128554.json"; string memory json = vm.readFile(path); uint256 blockNumber = json.readUint(".blockNumber"); diff --git a/test/payloads/ethereum/arb_pointer_proof_block_10128554.json b/test/payloads/ethereum/arb_pointer_proof_block_10128554.json new file mode 100644 index 0000000..104fdc6 --- /dev/null +++ b/test/payloads/ethereum/arb_pointer_proof_block_10128554.json @@ -0,0 +1,11 @@ +{ + "blockNumber": "0x9a8caa", + "blockHash": "0x839c3304f266d7ecfc5ea6038a4e873e8fc056405622a3aad7a22030526bc596", + "stateRoot": "0xadd8e77a2d10593dbf937715ff4371d69957bfd534a893808693f9ddba318460", + "account": "0xe2C96c2D3E4b54D4F1E9962b8D6eC5AD96f567b1", + "slot": "0xee72f8a02087d3307bd38f55854a433976910dab504e72b626e32d8d187b5aca", + "slotValue": "0xb0ee67f19114ef2f540e7ca5437c034501fce3d2236f3eb65f2d0550dd62b72a", + "rlpBlockHeader": "0xf90286a09b226edf0d110a499f4721aceebce53519f4d9a4e265088e9d5df7a1e84ebc5da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347943826539cbd8d68dcf119e80b994557b4278cec9fa0add8e77a2d10593dbf937715ff4371d69957bfd534a893808693f9ddba318460a074a432ac7986d1e7ca9fd24d8bb8ed31f2df4688c29af608d222788ba2d4ade1a00c9bd88e4e3ec3adf8cf713004242c4e587e8801ebd8cada198649e7bfd618bcb901000c848164420048bc08b8010584110b810d01124011180588368089004a0314910210220800b06000443427420000000008210186208aa42104010222c46c49301a00000001060248100d0088042884800800024921040020200e05008023a4404a1a0c0832800054000880c002124f02a10210093330004400001231806820300840001843144800a220808242a04280a10005c54a91100040169201040088802a0820011980100a0008190d02032002242066a2880200009a901440082002110810800280017001040307e6090d2062131000428a254031400a2940838260000110930040803200041ad416000000648088041440b80250808462024420820080839a8caa840393870083a99ac384697791c09a626573752032352e31322d646576656c6f702d63663962623765a0e0fdf580b83e231b0b38a8ec2e1534fcb62a851165f76ab1a9935ff77298ec80880000000000000000843ea88b0aa06196940f214be90db993448f21941f6b5bf00fce50ace0136118b42dd0cafffc83140000840c99a0d2a0326ec1f16de36000ec6231e8d8c7aae59e717e805b1230a960753a3605a390c5a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "rlpAccountProof": "0xf90e5eb90214f90211a0d5741b9c8b034f90fb10ffce72932a0292b34018044d4ef1e9a34f0259aeee5ba0d909ddd21f79be2837b3788874b427280bc5969389d2af49edd9032ffab0a6e1a0e772cc66f39a236391b47d20b1e6171952f4f36a7f47268ef67ab9434ad6299ba09ea748226e401e5bad94fc7b6e7cb7d70407fb5f85954de215c14c4a84bbeae7a0dff82757028ebb8bd4c33844dce6478b2a6a389a9ad40630549fdbc18106803fa081328db7d620a07a4cf36a8749692a6b2482d763e23c18fde1237b1e342758c8a0d6b9907ca2e4de29c9e7cff67a9078a4336d704f4644573f8d9176959a5c082da0556e02f736004a9cd156e25dbc1347f45dee830cf8398aba03773b8cf0043130a0a8021cb5871721c1a501736b56faac7ab56093ed3415cb1cc626338aa985d242a01a431fe7110e04a01c3dbca4ad5fd2cd2492b4a9e917c1daba497177b2333a7da0bf8eb8e8256decfa13f7910e1276afc186036a5dc8c2cb0a6fa455bc9b7cd1c3a0f4fc3ebeec71afd19a78b6420f7a83a64404d22f923d5a6a6a227623996b0faaa0b4658c1c568de1059ff5d3c1672126b0a3f14e52dc790a1008778e81e1ac23afa085bdc55dffacf04275199b4557df03d67fea925aafcfe2ba1398aca159c09b7aa05155806df430d951f9d76007b69f4f987bf7ae86c56d5dca491fd21472804eada0171c0a64f56332bedad2c1989f78cb5be6efe056e06e004ac9f6466e87f9819c80b90214f90211a04e086691d2c1c22558fa80552b4a76955c6636f14b667a92191f3cb994805009a0f8167ba35342380d13a0443bd5d1538d8e6a4026e0f7e02a6d95a6c66ee4ccfba0c3898def9d5161a22b427a51d1ebea47f2615bf895bf1d4e493d915b14664277a0c916ab643e13f4de9389323de9d42379c7b3ddf036e9ec8dc539793e1c8e220da0518cb03a9f5a75ccb2582fd2408bbde225a3cc3d97ac24f15f35ac1c2e5fd0dfa083449fbcfdb1f49f9e708c8239bdbaf6ed796b2bd3cbc697acd26b1a02243b4ea039b31c5b1f8184885e7e3e837a6f8e61b00c8c3a0c174649593679ea1477fa5ba0ba154d2eb36e5b71783e8602ad62989da40aa266eaadc3fde36f31ebfb422bcda0ad1f4c00bd0ce3b4be3eac3984042a7dc1dccd547c4c20fc8a2ec34e9467d1a1a01902c1c968504a679617a1b42d53b784e33b65667029765b6eff7b0e7f216531a0ed08cb9b76aeb53b798f19f9c7b3228c42a23d7965954dad795ddf28f9aeaaaca09764f6b49e3ebe1adcc0f9bfc96b268c6212374352fa9ef6c1fb47f57f0492e3a0249547e69d02c6d6d026db0ddab0ab7d91b1c811b1ab802ab6993520bd08bfe1a0e86165ab9f8559f2214773fd3177c6317f4bb6a0fa51c4d95ba8fb0afa303847a0186fa4591f6545b4e2a027226a3ccab424f961cb2ca330215d3e574aa3391e63a00e04c0d6eac25b8b80863e1610e0755adfe20669ce748ca4e71dc85afd7a982f80b90214f90211a05604a692474080a896faac440d193f0505c4661a0338a4848f8249eab6ea201fa0526622ab09ff66238594acd1f73c036aab87146b58f54c5771c351e48f0accf1a011777da9f7db041d52eee9fef87586e18bceddd3bd2a6545c8f12933ee31c842a09cff23ab054afe5ab7cf5b93c0d7ee82ddb6f26620a5977eb85a3e3204e0039ba0b78bcd60e21722ff7940736dff916c9a59af2b232b5b376db51cc2cd4346ecf9a0e9db9460c6e82f9c435d0894604196df2aaa74bcce01ac15d68fb810a4fda5a6a03269e7ea9ce71721e6e10477092afc43f030994535a52f4ca598b15aba944eb4a01cfa67d153c3b920a75832245ca69252761824803d9f11379103933770b72193a0d4485e38acc765a5a34ad072765e04a838e7fb13e65e5cfcdd58a1ac4dfe432fa026f241828adbab8e8b84ffdc56d05a173b33ee020ee36abd834c369e73798227a0be188107d87c2ada84ba6961644ef1267557b964cb6d9f1ac3bf4692fbc3eed6a049093d270c946f9f0d45af9b164918be122e0dcc7e78e6ac4affd14908d2388aa0963c2bdfa9d65e8b3159fed84a56229a44e289391d3b63e21f22104ee6552993a04c57f9a0e6c5180c2bbeca6e8d6465992db6264a5f0ca7c3f04d6aa4e1880095a0910595e5dc577315fe8c87ef83e46612d0599fa38f9a9fdab9b61cd011bc15c0a0c84bbf02d750c3759c83457fa3647eeac0525052313850b65a3557cf2cd7f8f280b90214f90211a0546da58cbe51ed182862d3c022400ee8cf8c079a98d3950ab45837e9ab338b25a0b1f5ed8a4561cf02b23b66fdece36f3773a2eb894bf8782be4a337b91c35b4c2a0da3b0829645312ef53596663595598e3c2e3a6fb90060b39401db5aeb629549ba0bf204de3d280ea5cf78533fea732c9f8d0983990a1f9d85562597a173a92363ba087003c1f6fb5bfd1b7d47fd15f1a45fb3df754649f147412b1dee1467e76bb34a0dd6d3b12ed8a602935be01beef801aa3bb1dfda5a4546e435f30f885229b4ef6a0d8a17ebc6e89ea29533d2cdd220e6313bc11f908616b75053af6e76af0d98957a0091f8574f339c2df4ed3b2c0dd91ab75f93f3afc0c0934ffc71f6c364882972ea0dc78f7ccd5545a9c887b7b9915f94035cacc305e3c454d9a8e9b11de3acc2bcba07f23562cb8d322e4ac861ea7fb827ddf5211e93e6f1fdacdadc6129074ae2069a0548c21cd0beb7c8a014d4684d3b8cbaffc85f844a8429a935b5c866845cf4ecea0533df4189beff2fff03e8f34446067a118cf2dac3eb1a62e6263e1b828329d1fa0969113956dc5c9b47e2851a62faddefa9c2075b6d0be4674197d35efab39fecfa07033185b3fcc9a7dfe2dfe1273b3354aade90b5d7990cf816b368fe3aede9819a047c625d8214e563c2ff50dbeaf8d29243e1a2ac5983588f5ec8f332e07f53bd0a09896cf91c1d8e2cd09c0663174154bb43fec08204a46c97370d8761ecffe442480b90214f90211a0614ea66d4ac800174be8b511bb83238d32534215e4c5e67f99eeeaaac4f0c6c8a0c2f40ce488417b266f6534c4b58e09103407ba3741cfb8048dd9898fbb9b2b28a0799ad3c69b5d58e177c9f29f1040909693f1beaa545dc41aa1687f9a63b55a52a0b5b1e6748289dfbb483c147423854b92cebbbb43facff732adc522178c304f35a03e0578afb47f3578193d10a265b0fa3c1a857e9fd616ced7062931fedda38720a00f9a5173e88e704ab0eef02da091f82d496f6a50e1610ec1213757252a56b605a03b1bf5994e6f57096e1ef6d4b80537d59c1dd08019c8289d5bea947c24e93f9fa0bc8f62a3cc7e0ac7d86e3be570cdf295b5a149371a0c58fbc36e7d5911c476f8a09023fc1d532e29f411647d549488a82a284ba0373a70c92745f8d26f118304bca03d6d4beef071120a8d1dcd4866d6dff1cb3ee0e81d6eaf474f182cae166932e2a0ed7359930a8dbf2c9c73dd849e2f80213d52a5e9aaf8d8981fb353cece19539ea02eb06dfb9009a2962143cd9324c8985b68edb3eb1dfff2f2798d991ee40d2538a0db320e2b273d3fb3cc7b4f7f2524b24488fe8f952563e48bebf5eee94161c71fa02e6ff759bdcd24a91d783b5918262c144b1c6ee3104f131cdf5f8157fb752d8aa0500dfad4066d7db8eb049c226bd70fc0d201b2d1911a3d9b278380fa19f97e6da00a110cd362c39fde78c12ebd1a0af3c3d7f90a74d98753a54fade77d5e48459880b90214f90211a0415697df58127f5489b47b7869f953e596f009ff2820e4e07c3ca964bd0e92cba03a00470d4e85ad8ebf924094f4c136b11045b0320b2b9a181c54e4cdcbc3b3e0a06eb6106433e1ac263d2a561f80b8f81a27c833a65940b5c62d3bc04afbe2a4c5a0a5bc7474d8d7c266e65c9d18e8753c8aabf546c6172cc82a50a6ed5ae54ecccda0c3de33e94fd55c8c5bbed09f5e0005d11e43036657f464721ce9155186284ff1a08ebbdf3e7314e2ae79bd3abadcc506f491fd77a1b07a19fee2d4eb4a68e6696fa08611c6182c89e0e07ad55e023e9bd1e823685f1f8a2ee7542762537025f7fd42a0d642d007b7acc4e33d3b3b06a9e14ec1d61d3cea23b3ab0a47ec8661cd3f3509a042d9257eb39a185b5e7e576903dd26aee04a72af13072b86083f490b35a2f67da03ed7fd323b52935133466884d343cccce36d098552c599ee84deb98a9bd1ddfea0a35e8e4ff8698d1ba110ad85a4ff37581479c8213eec25811b79397f5a8c8731a01c00da91c2c406a37900da538f648b31c434387b500ea058ec866ea90f787583a06b79a55837d70c9b3c1522c07b14febacac92baf697e750989670351720f8063a0a76b0984e61b37186b7b4f43a37bcc5dfee7b6ce6ca9bb617ed6d59dd37166c4a0d0446fb25d970e5e906e89699ad5c5f622c27c4d8770741594f28bcbf599f2c9a0e9bde4aeac3fd5b1af43bb40d0fbae82b75e058f67a2246221fb1ebb5e24ebec80b8d3f8d1808080808080a0c010e06da0f44da6fd1762fb2c490210f5a22baf61478b142e11479f3d4741f2a07ce0f8f2de241635efd262318cb8832a39ade936435eaf077cd87d4e5fdf0674a0facc845ddae31dba0c3c448d6ce413a94a92500944b0a19ec04dabb4ba3e6cfa80a0d60f9cbb1a8a845ee720ffb68937d30ebdd3b2852c65a85ceacbb961e782b1b5a0943ff0d8ad6450b852e582777197bcef2d0f5388463ce6c431c42ae0e11f557e8080a06852d832eada7c7ef7b513b1b794cd586e95a0d9dc610f981e06462581faca1c8080b893f891a0abfd3232342bf0f233bd1b3d96e5ac6577f918939b3c08c8a0adbc2d485a975d80808080808080808080a011a01c20fb36c489c5b8fc67fff6d225dafd9476f3613ce760036fdc53e1d480a098db0456199c4bf7e088d5b74e1759164ec00425d90085e1470bee1a326be23780a055f168672904585f14c83a8770966e707179899901202f64014bca1d9fc7ce908080b868f8669d207eefac74e7cdf442ac370d23a028a12a1bed220ff723241417885234b846f8440180a050d25d32255015c4b33e12e971fed1f1dc6f7a98175df1d38777062a99356be9a06805798ebe44ed998ce93036572c1580000c5206e4461b233323a67eebfd5001", + "rlpStorageProof": "0xf8bcb873f8718080a0fecf31ff05c59132f4f3857913ac1442ca8c30a3ef31aa057e80bef0edc13b6780a096cfcf806ec0baf972c99e2dbb96bd89ce0f3f28ae5e7b1f833293a0d6686ced808080808080a0a63bce3177bdcf2bcdf20593fc382df6829cd820447b8ee8d09a0c72cfb667e48080808080b845f843a0323543e67277ca39e1a40854aa32c04a3801f9748e5b663bc20961794dd54596a1a0b0ee67f19114ef2f540e7ca5437c034501fce3d2236f3eb65f2d0550dd62b72a" +} \ No newline at end of file From 5537d33ebcc925b20a095f40fd913dc4ecfbec7c Mon Sep 17 00:00:00 2001 From: Luiz Date: Mon, 26 Jan 2026 13:25:23 -0300 Subject: [PATCH 13/25] remove docs from .gitignore --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index 56eeffd..0cf4bef 100644 --- a/.gitignore +++ b/.gitignore @@ -7,9 +7,6 @@ out/ /broadcast/*/31337/ /broadcast/**/dry-run/ -# Docs -docs/ - # Dotenv file .env From 472da592c1b1ea6dd8477c07ed6c5789db796a7f Mon Sep 17 00:00:00 2001 From: Luiz Date: Mon, 26 Jan 2026 13:29:31 -0300 Subject: [PATCH 14/25] update docs --- docs/ERC7888.md | 299 ++++++++++++++++++++++++ docs/PROVERS.md | 336 +++++++++++++++++++++++++++ docs/README.md | 56 +++++ docs/TUTORIAL.md | 588 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1279 insertions(+) create mode 100644 docs/ERC7888.md create mode 100644 docs/PROVERS.md create mode 100644 docs/README.md create mode 100644 docs/TUTORIAL.md diff --git a/docs/ERC7888.md b/docs/ERC7888.md new file mode 100644 index 0000000..96d6860 --- /dev/null +++ b/docs/ERC7888.md @@ -0,0 +1,299 @@ +# ERC-7888: Crosschain Broadcaster + +**Reference:** [EIP-7888 Specification](https://eips.ethereum.org/EIPS/eip-7888) + +## Introduction + +ERC-7888 defines a protocol for trustless cross-chain message verification using cryptographic storage proofs. The protocol enables any chain to verify messages broadcast on any other chain that shares a common ancestor, creating a foundation for cross-chain interoperability without trusted intermediaries. + +### Core Components + +| Component | Description | +|-----------|-------------| +| **Broadcaster** | Stores messages in deterministic storage slots, one per (message, publisher) pair | +| **Receiver** | Verifies messages from remote chains using storage proofs | +| **StateProver** | Chain-specific logic for verifying state commitments and storage slots | +| **StateProverPointer** | Upgradeable pointer to the latest StateProver version | + +Each chain deploys singleton `Broadcaster` and `Receiver` contracts, enabling permissionless message broadcasting and verification across the ecosystem. + +### State Commitments + +A **state commitment** is a `bytes32` hash that commits to a chain's state at a particular point in time. The protocol supports different types of state commitments depending on what the rollup commits to its parent chain: + +- **Block hash** (recommended): A hash of the block header +- **State root**: The root of the state tree (e.g., Merkle-Patricia Trie) +- **Batch hash**: A hash of a batch of blocks (for rollups that commit batches) + +--- + +## Broadcasting Messages + +Publishers broadcast messages by calling `broadcastMessage()` on the Broadcaster contract: + +```solidity +interface IBroadcaster { + /// @notice Emitted when a message is broadcast. + event MessageBroadcast(bytes32 indexed message, address indexed publisher); + + /// @notice Broadcasts a message. Callers are called "publishers". + /// @dev MUST revert if the publisher has already broadcast the message. + /// MUST emit MessageBroadcast. + /// MUST store block.timestamp in slot keccak(message, msg.sender). + function broadcastMessage(bytes32 message) external; +} +``` + +### Storage Layout + +The Broadcaster stores `block.timestamp` in storage slot `keccak256(abi.encode(message, publisher))`, creating a unique slot per (message, publisher) pair. + +**Key constraints:** +- Each publisher can only broadcast a specific message **once** +- Applications requiring multiple broadcasts of the same logical message must implement nonce logic at the application layer + +--- + +## Message Verification + +### Routes + +A **route** is a relative path from a Receiver on a local chain to a remote chain. Routes are constructed from StateProverPointer addresses, where each pointer lives on its home chain and references a StateProver that can prove the next chain's state commitment. + +**Route validity rules:** +- Home chain of `route[0]` must equal the local chain +- Target chain of `route[i]` must equal home chain of `route[i+1]` + +### Remote Account Identifiers + +Accounts on remote chains are identified by accumulating the route addresses plus the remote address: + +```solidity +function accumulator(address[] memory elems) pure returns (bytes32 acc) { + for (uint256 i = 0; i < elems.length; i++) { + acc = keccak256(abi.encode(acc, elems[i])); + } +} +``` + +IDs depend on the route and are therefore always **relative** to a local chain. The same account on a given chain will have different IDs depending on the route taken. + +### Verification Process: `verifyBroadcastMessage` + +```solidity +interface IReceiver { + struct RemoteReadArgs { + address[] route; // StateProverPointer addresses along the route + bytes[] scpInputs; // Inputs for each StateProver + bytes proof; // Final storage proof for the message slot + } + + function verifyBroadcastMessage( + RemoteReadArgs calldata broadcasterReadArgs, + bytes32 message, + address publisher + ) external view returns (bytes32 broadcasterId, uint256 timestamp); +} +``` + +**Three-stage verification:** + +1. **Initial State Commitment Retrieval**: For the first hop, the Receiver calls the StateProverPointer at `route[0]` to get the implementation address, then calls `getTargetStateCommitment()`. Since this executes on the home chain, the prover directly accesses the target chain's state commitment. + +2. **State Commitment Chain Verification**: For subsequent hops, the Receiver uses locally stored StateProverCopies to call `verifyTargetStateCommitment()` with the previous chain's state commitment and a proof. This builds a chain: `stateCommitment[0] → stateCommitment[1] → ... → stateCommitment[n]`. + +3. **Storage Slot Verification**: With the target chain's state commitment established, the Receiver calls `verifyStorageSlot()` on the final StateProver, verifying: + - The slot matches `keccak256(abi.encode(message, publisher))` + - The slot value is non-zero (message was broadcast) + +The slot value (`block.timestamp`) is returned as the timestamp. + +--- + +## StateProvers + +A `StateProver` implements chain-specific verification logic. Each rollup stores parent/child state commitments differently, requiring custom prover implementations. + +```solidity +interface IStateProver { + /// @notice Get the state commitment of the target chain when called on the home chain. + /// @dev MUST revert if not called on the home chain. + function getTargetStateCommitment(bytes calldata input) + external view returns (bytes32 targetStateCommitment); + + /// @notice Verify the state commitment of the target chain from a remote chain. + /// @dev MUST revert if called on the home chain. + function verifyTargetStateCommitment(bytes32 homeStateCommitment, bytes calldata input) + external view returns (bytes32 targetStateCommitment); + + /// @notice Verify a storage slot given a target chain state commitment. + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) + external view returns (address account, uint256 slot, bytes32 value); + + /// @notice The version of this prover implementation. + function version() external pure returns (uint256); +} +``` + +### Operating Modes + +| Mode | Function | Context | +|------|----------|---------| +| **Home chain** | `getTargetStateCommitment()` | Directly reads target chain's state commitment from storage | +| **Remote chain** | `verifyTargetStateCommitment()` | Verifies a proof establishing the target chain's state commitment | + +### Prover Requirements + +- **Code hash consistency**: StateProvers MUST ensure they have the same deployed code hash on all chains +- **Pure functions**: `verifyTargetStateCommitment()`, `verifyStorageSlot()`, and `version()` MUST be pure (with exception: MAY read `address(this).code`) +- **Chain-specific logic**: Each prover is fixed to a specific (home chain, target chain) pair + +--- + +## StateProverPointers + +Rollup storage layouts may change over time, requiring prover updates. However, routes reference provers by address, and changing addresses would break existing routes. `StateProverPointers` provide indirection to enable upgrades without breaking routes. + +```solidity +// Fixed storage slot for the code hash +uint256 constant STATE_PROVER_POINTER_SLOT = uint256(keccak256("eip7888.pointer.slot")) - 1; + +interface IStateProverPointer { + /// @notice Return the code hash of the latest version of the prover. + function implementationCodeHash() external view returns (bytes32); + + /// @notice Return the address of the latest version of the prover on the home chain. + function implementationAddress() external view returns (address); +} +``` + +### Upgrade Process + +1. Deploy a new `StateProver` with a higher `version()` number +2. Pointer owner calls `setImplementationAddress()` to point to the new prover +3. Pointer stores the new prover's code hash in `STATE_PROVER_POINTER_SLOT` +4. Receivers update local copies via `updateStateProverCopy()`, which verifies the code hash matches + +**Upgrade constraints:** +- The new StateProver MUST have the same home and target chains +- The new StateProver MUST have a higher `version()` than the previous one + +### Security Considerations for Pointer Ownership + +The StateProverPointer owner can DoS or forge messages. Therefore: + +| Target Chain | Expected Owner | +|--------------|----------------| +| Parent chain | Home chain owner | +| Child chain | Target chain owner | + +--- + +## StateProverCopies + +Receivers cannot call contracts on remote chains directly. To verify proofs from remote chains, Receivers maintain local copies of StateProvers with matching code. + +### Copy Registration + +```solidity +function updateStateProverCopy( + RemoteReadArgs calldata scpPointerReadArgs, + IStateProver scpCopy +) external returns (bytes32 scpPointerId); +``` + +The Receiver verifies: +1. The proof reads from `STATE_PROVER_POINTER_SLOT` +2. The copy's code hash matches the Pointer's stored code hash +3. The copy's version is higher than any existing copy (if updating) + +Copies are stored keyed by `scpPointerId`, calculated by accumulating hashes of addresses in the route to the Pointer. + +--- + +## Complete Interface Reference + +### IBroadcaster + +```solidity +interface IBroadcaster { + event MessageBroadcast(bytes32 indexed message, address indexed publisher); + + function broadcastMessage(bytes32 message) external; +} +``` + +### IReceiver + +```solidity +interface IReceiver { + struct RemoteReadArgs { + address[] route; + bytes[] scpInputs; + bytes proof; + } + + function verifyBroadcastMessage( + RemoteReadArgs calldata broadcasterReadArgs, + bytes32 message, + address publisher + ) external view returns (bytes32 broadcasterId, uint256 timestamp); + + function updateStateProverCopy( + RemoteReadArgs calldata scpPointerReadArgs, + IStateProver scpCopy + ) external returns (bytes32 scpPointerId); + + function stateProverCopy(bytes32 scpPointerId) + external view returns (IStateProver scpCopy); +} +``` + +### IStateProver + +```solidity +interface IStateProver { + function verifyTargetStateCommitment(bytes32 homeStateCommitment, bytes calldata input) + external view returns (bytes32 targetStateCommitment); + + function getTargetStateCommitment(bytes calldata input) + external view returns (bytes32 targetStateCommitment); + + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) + external view returns (address account, uint256 slot, bytes32 value); + + function version() external pure returns (uint256); +} +``` + +### IStateProverPointer + +```solidity +interface IStateProverPointer { + function implementationCodeHash() external view returns (bytes32); + function implementationAddress() external view returns (address); +} +``` + +--- + +## Security Considerations + +### Chain Upgrades + +If a chain upgrades such that a StateProver's verification functions might return data besides a finalized target state commitment, invalid messages could be read. Either: +- The StateProver should detect such changes +- The chain owner responsible for storage layout changes should also own the StateProverPointer + +### Message Guarantees + +This protocol ensures messages **CAN** be read, not that they **WILL** be read. It is the Receiver caller's responsibility to choose which messages to read. + +Since the protocol only uses finalized blocks, messages may take time to propagate. Finalization occurs sequentially in the route, so total propagation time equals the sum of finalization times at each step. + +--- + +## Links + +- **EIP Specification**: [EIP-7888](https://eips.ethereum.org/EIPS/eip-7888) +- **Discussion**: [Ethereum Magicians Forum](https://ethereum-magicians.org/t/new-erc-cross-chain-broadcaster/22927) diff --git a/docs/PROVERS.md b/docs/PROVERS.md new file mode 100644 index 0000000..d37c726 --- /dev/null +++ b/docs/PROVERS.md @@ -0,0 +1,336 @@ +# StateProvers Reference + +This document details the chain-specific `StateProver` implementations available in this repository. Each prover handles the unique way its rollup commits state to parent chains. + +## Overview + +Each rollup requires **two provers** for bidirectional communication: + +| Prover Type | Direction | Home Chain | Target Chain | +|-------------|-----------|------------|--------------| +| **ChildToParentProver** | L2 → L1 | Child (L2) | Parent (L1) | +| **ParentToChildProver** | L1 → L2 | Parent (L1) | Child (L2) | + +--- + +## Arbitrum + +### ChildToParentProver + +**Location:** `src/contracts/provers/arbitrum/ChildToParentProver.sol` + +Proves Ethereum (L1) block hashes from Arbitrum (L2). + +**Mechanism:** +- Uses the `ArbSys` precompile at `0x0000000000000000000000000000000000000064` +- Accesses the `l2ToL1Block()` function which returns L1 block numbers +- Uses a `Buffer` contract that stores historical L1 block hashes + +**Key addresses:** +- `ArbSys`: `0x0000000000000000000000000000000000000064` +- `Buffer`: `0x0000000048C4Ed10cF14A02B9E0AbDDA5227b071` + +**Input format for `getTargetStateCommitment`:** +```solidity +abi.encode(uint256 targetBlockNumber) +``` + +**Input format for `verifyTargetStateCommitment`:** +```solidity +abi.encode( + bytes rlpBlockHeader, + uint256 targetBlockNumber, + bytes accountProof, + bytes storageProof +) +``` + +### ParentToChildProver + +**Location:** `src/contracts/provers/arbitrum/ParentToChildProver.sol` + +Proves Arbitrum (L2) block hashes from Ethereum (L1). + +**Mechanism:** +- Uses the `Outbox` contract on L1 which stores Arbitrum's `sendRoot` +- The `sendRoot` maps to confirmed L2 block hashes via `SendRootUpdated` events +- Proves storage in the Outbox's `roots` mapping + +**Key components:** +- `outbox`: Arbitrum's Outbox contract address (chain-specific) +- `rootsSlot`: Storage slot for the roots mapping + +**Input format for `getTargetStateCommitment`:** +```solidity +abi.encode(bytes32 sendRoot) +``` + +**Input format for `verifyTargetStateCommitment`:** +```solidity +abi.encode( + bytes rlpBlockHeader, + bytes32 sendRoot, + bytes accountProof, + bytes storageProof +) +``` + +--- + +## Optimism + +### ChildToParentProver + +**Location:** `src/contracts/provers/optimism/ChildToParentProver.sol` + +Proves Ethereum (L1) block hashes from OP Stack chains. + +**Mechanism:** +- Uses the `L1Block` predeploy at `0x4200000000000000000000000000000000000015` +- The predeploy stores the **latest** L1 block hash only (not historical) +- Proofs must be generated just-in-time as they become stale when L1Block updates (~5 minutes) + +**Key addresses:** +- `L1Block`: `0x4200000000000000000000000000000000000015` +- `l1BlockHashSlot`: `2` + +**Important operational note:** +Pre-generated proofs become stale when L1Block updates. Failed calls may need to be retried with fresh proofs. + +**Input format for `getTargetStateCommitment`:** +```solidity +// bytes argument is ignored - returns latest L1 block hash +``` + +**Input format for `verifyTargetStateCommitment`:** +```solidity +abi.encode( + bytes rlpBlockHeader, + bytes accountProof, + bytes storageProof +) +``` + +### ParentToChildProver + +**Location:** `src/contracts/provers/optimism/ParentToChildProver.sol` + +Proves OP Stack (L2) block hashes from Ethereum (L1). + +**Mechanism:** +- Uses the `L2OutputOracle` on L1 which stores L2 output proposals +- Output proposals contain state roots that commit to L2 state +- Requires finding the latest finalized output proposal + +--- + +## Linea + +### ChildToParentProver + +**Location:** `src/contracts/provers/linea/ChildToParentProver.sol` + +Proves Ethereum (L1) block hashes from Linea (L2). + +**Mechanism:** +- Uses Linea's `L1MessageService` which stores L1 block hashes +- Linea uses a sparse Merkle tree (different from standard MPT) + +**Libraries used:** +- `SparseMerkleProof.sol`: Linea's sparse Merkle proof verification +- `Mimc.sol`: MiMC hash function used in Linea's state tree + +### ParentToChildProver + +**Location:** `src/contracts/provers/linea/ParentToChildProver.sol` + +Proves Linea (L2) block hashes from Ethereum (L1). + +**Mechanism:** +- Uses the `LineaRollup` contract on L1 +- Proves state roots from finalized Linea batches + +--- + +## Scroll + +### ChildToParentProver + +**Location:** `src/contracts/provers/scroll/ChildToParentProver.sol` + +Proves Ethereum (L1) block hashes from Scroll (L2). + +**Mechanism:** +- Uses a `Buffer` contract that stores historical L1 block hashes +- Similar architecture to Arbitrum's ChildToParentProver + +**Key addresses:** +- `Buffer`: Chain-specific buffer address + +### ParentToChildProver + +**Location:** `src/contracts/provers/scroll/ParentToChildProver.sol` + +Proves Scroll (L2) block hashes from Ethereum (L1). + +**Mechanism:** +- Uses the `ScrollChain` contract on L1 +- Proves finalized batch state roots + +--- + +## zkSync + +### ChildToParentProver + +**Location:** `src/contracts/provers/zksync/ChildToParentProver.sol` + +Proves Ethereum (L1) block hashes from zkSync Era (L2). + +**Mechanism:** +- Uses zkSync's system contracts for L1 block hash access +- Different storage/proof structure than EVM-equivalent chains + +**Libraries used:** +- `Merkle.sol`: zkSync's Merkle proof verification +- `MessageHashing.sol`: zkSync-specific message hashing + +### ParentToChildProver + +**Location:** `src/contracts/provers/zksync/ParentToChildProver.sol` + +Proves zkSync Era (L2) block hashes from Ethereum (L1). + +**Mechanism:** +- Uses the zkSync Diamond Proxy on L1 +- Proves state roots from finalized batches + +--- + +## Taiko + +### ChildToParentProver + +**Location:** `src/contracts/provers/taiko/ChildToParentProver.sol` + +Proves Ethereum (L1) block hashes from Taiko (L2). + +### ParentToChildProver + +**Location:** `src/contracts/provers/taiko/ParentToChildProver.sol` + +Proves Taiko (L2) block hashes from Ethereum (L1). + +--- + +## Common Storage Proof Input + +All provers use a common format for `verifyStorageSlot`: + +```solidity +abi.encode( + bytes rlpBlockHeader, // RLP-encoded block header + address account, // Target account address + uint256 slot, // Storage slot to prove + bytes accountProof, // Merkle proof for the account + bytes storageProof // Merkle proof for the storage slot +) +``` + +**Output:** +```solidity +returns ( + address account, // The proven account address + uint256 slot, // The proven storage slot + bytes32 value // The value at the storage slot +) +``` + +--- + +## Implementing a New Prover + +To add support for a new rollup: + +1. **Create the directory structure:** + ``` + src/contracts/provers/{chain-name}/ + ├── ChildToParentProver.sol + └── ParentToChildProver.sol + ``` + +2. **Implement `IStateProver` interface** for both directions + +3. **Identify the state commitment source:** + - For ChildToParentProver: Where does the L2 store L1 block hashes? + - For ParentToChildProver: Where does L1 store finalized L2 state roots? + +4. **Implement the three core functions:** + - `getTargetStateCommitment()`: Direct state access on home chain + - `verifyTargetStateCommitment()`: Proof verification on remote chain + - `verifyStorageSlot()`: Standard MPT proof verification (usually reusable) + +5. **Ensure code hash consistency:** + - Use immutable values or compile-time constants + - Avoid chain-specific storage reads in verification functions + +6. **Add TypeScript helpers** in `src/ts/` for proof generation + +--- + +## ProverUtils Library + +**Location:** `src/contracts/libraries/ProverUtils.sol` + +Shared utilities for all provers: + +```solidity +library ProverUtils { + /// @notice Verify block header hash and extract state root + function getStateRoot(bytes32 blockHash, bytes memory rlpBlockHeader) + internal pure returns (bytes32 stateRoot); + + /// @notice Verify account proof and get account data + function getAccountData( + bytes32 stateRoot, + address account, + bytes memory accountProof + ) internal pure returns (bytes32 storageRoot, ...); + + /// @notice Verify storage proof and get slot value + function getStorageValue( + bytes32 storageRoot, + uint256 slot, + bytes memory storageProof + ) internal pure returns (bytes32 value); + + /// @notice Combined helper: block hash → storage value + function getSlotFromBlockHeader( + bytes32 blockHash, + bytes memory rlpBlockHeader, + address account, + uint256 slot, + bytes memory accountProof, + bytes memory storageProof + ) internal pure returns (bytes32 value); +} +``` + +--- + +## Testing Provers + +Each prover has corresponding tests in `test/provers/{chain-name}/`: + +```bash +# Run all prover tests +forge test --match-path "test/provers/**" + +# Run specific chain tests +forge test --match-path "test/provers/arbitrum/**" + +# Run with fork testing (requires RPC URLs) +forge test --match-path "test/provers/**" --fork-url $ETHEREUM_RPC_URL +``` + +Test payloads are stored in `test/payloads/{chain-name}/` as JSON files containing pre-generated proofs for reproducible testing. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..43ecf1a --- /dev/null +++ b/docs/README.md @@ -0,0 +1,56 @@ +# Documentation + +## ERC-7888 Crosschain Broadcaster + +This repository implements [ERC-7888](https://eips.ethereum.org/EIPS/eip-7888), a protocol for trustless cross-chain message verification using cryptographic storage proofs. + +### Documentation Index + +| Document | Description | +|----------|-------------| +| [ERC7888.md](ERC7888.md) | Complete specification overview, interfaces, and protocol mechanics | +| [PROVERS.md](PROVERS.md) | Chain-specific StateProver implementations and how to add new ones | +| [TUTORIAL.md](TUTORIAL.md) | Step-by-step guide to broadcasting and verifying messages | + +### Quick Links + +- **Specification**: [EIP-7888](https://eips.ethereum.org/EIPS/eip-7888) +- **Discussion**: [Ethereum Magicians](https://ethereum-magicians.org/t/new-erc-cross-chain-broadcaster/22927) + +### Getting Started + +1. Read [ERC7888.md](ERC7888.md) for protocol fundamentals +2. Follow [TUTORIAL.md](TUTORIAL.md) to implement your first cross-chain message +3. Reference [PROVERS.md](PROVERS.md) for chain-specific details + +### Supported Chains + +| Chain | ChildToParent | ParentToChild | +|-------|---------------|---------------| +| Arbitrum | ✅ | ✅ | +| Optimism | ✅ | ✅ | +| Linea | ✅ | ✅ | +| Scroll | ✅ | ✅ | +| zkSync Era | ✅ | ✅ | +| Taiko | ✅ | ✅ | + +### Core Contracts + +``` +src/contracts/ +├── Broadcaster.sol # Message broadcasting +├── Receiver.sol # Message verification +├── StateProverPointer.sol # Upgradeable prover reference +├── interfaces/ +│ ├── IBroadcaster.sol +│ ├── IReceiver.sol +│ ├── IStateProver.sol +│ └── IStateProverPointer.sol +└── provers/ + ├── arbitrum/ + ├── optimism/ + ├── linea/ + ├── scroll/ + ├── zksync/ + └── taiko/ +``` diff --git a/docs/TUTORIAL.md b/docs/TUTORIAL.md new file mode 100644 index 0000000..bb4a9cf --- /dev/null +++ b/docs/TUTORIAL.md @@ -0,0 +1,588 @@ +# ERC-7888 Tutorial: Cross-Chain Message Broadcasting + +This tutorial walks through implementing cross-chain messaging using ERC-7888. We'll cover broadcasting messages, verifying them on remote chains, and building applications on top of the protocol. + +## Table of Contents + +1. [Prerequisites](#prerequisites) +2. [Architecture Overview](#architecture-overview) +3. [Broadcasting Messages](#broadcasting-messages) +4. [Verifying Messages](#verifying-messages) +5. [Setting Up StateProverCopies](#setting-up-stateprovercopies) +6. [Building a Cross-Chain Application](#building-a-cross-chain-application) +7. [Generating Proofs with TypeScript](#generating-proofs-with-typescript) + +--- + +## Prerequisites + +**Required:** +- Node.js 18+ +- Foundry toolkit (forge, cast) +- Access to RPC endpoints for source and destination chains + +**Install dependencies:** +```bash +yarn install +forge install +``` + +**Environment setup:** +```bash +cp .env.example .env +# Configure RPC URLs for the chains you're working with +``` + +--- + +## Architecture Overview + +### System Components + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Source Chain (L2-A) │ +│ ┌─────────────┐ ┌──────────────────────────┐ │ +│ │ Publisher │───────▶│ Broadcaster │ │ +│ └─────────────┘ │ stores: timestamp @ slot │ │ +│ └──────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + State Commitment + (block hash) + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Parent Chain (Ethereum) │ +│ ┌──────────────────────────────────┐ │ +│ │ Rollup Contract │ │ +│ │ (stores L2 state commitments) │ │ +│ └──────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + State Commitment + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Destination Chain (L2-B) │ +│ ┌──────────────────────────────┐ ┌─────────────┐ │ +│ │ Receiver │◀─────│ Subscriber │ │ +│ │ - StateProverCopies │ └─────────────┘ │ +│ │ - verifyBroadcastMessage() │ │ +│ └──────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Message Flow + +1. **Publisher** broadcasts a 32-byte message on Source Chain +2. **Broadcaster** stores `block.timestamp` at slot `keccak256(message, publisher)` +3. Source chain's state is committed to Parent Chain +4. **Subscriber** on Destination Chain calls **Receiver** with: + - Route of StateProverPointers + - Proofs for each hop + - Storage proof for the message slot +5. **Receiver** verifies the proof chain and returns `(broadcasterId, timestamp)` + +--- + +## Broadcasting Messages + +### Step 1: Deploy or Locate the Broadcaster + +The Broadcaster is a singleton per chain. If not deployed, deploy it: + +```solidity +// Deploy.s.sol +import {Broadcaster} from "../src/contracts/Broadcaster.sol"; + +contract DeployBroadcaster is Script { + function run() external { + vm.startBroadcast(); + Broadcaster broadcaster = new Broadcaster(); + vm.stopBroadcast(); + + console.log("Broadcaster deployed at:", address(broadcaster)); + } +} +``` + +```bash +forge script scripts/DeployBroadcaster.s.sol --rpc-url $SOURCE_RPC --broadcast +``` + +### Step 2: Broadcast a Message + +```solidity +// Your publisher contract +import {IBroadcaster} from "src/contracts/interfaces/IBroadcaster.sol"; + +contract MyPublisher { + IBroadcaster public broadcaster; + uint256 public nonce; + + event MessagePublished(bytes32 indexed message, uint256 nonce); + + constructor(IBroadcaster _broadcaster) { + broadcaster = _broadcaster; + } + + function publish(bytes memory data) external { + // Create unique message with nonce + bytes32 message = keccak256(abi.encode(data, nonce++)); + + // Broadcast + broadcaster.broadcastMessage(message); + + emit MessagePublished(message, nonce - 1); + } +} +``` + +**Direct broadcast via cast:** +```bash +# Encode a message (example: "hello world" padded to 32 bytes) +MESSAGE=$(cast keccak "hello world") + +cast send $BROADCASTER_ADDRESS "broadcastMessage(bytes32)" $MESSAGE \ + --rpc-url $SOURCE_RPC \ + --private-key $PRIVATE_KEY +``` + +### Step 3: Calculate the Storage Slot + +The message is stored at a deterministic slot: + +```solidity +bytes32 slot = keccak256(abi.encode(message, publisher)); +``` + +```bash +# Calculate slot off-chain +PUBLISHER="0xYourPublisherAddress" +cast keccak $(cast abi-encode "encode(bytes32,address)" $MESSAGE $PUBLISHER) +``` + +--- + +## Verifying Messages + +### Step 1: Determine the Route + +A route consists of StateProverPointer addresses from destination to source: + +``` +Destination Chain → Parent Chain → Source Chain + route[0] route[1] +``` + +**Example: Arbitrum → Ethereum → Optimism** +```solidity +address[] memory route = new address[](2); +route[0] = 0x...; // Arbitrum ChildToParent StateProverPointer (on Arbitrum) +route[1] = 0x...; // Ethereum ParentToChild StateProverPointer for Optimism (on Ethereum) +``` + +### Step 2: Build Proof Inputs + +For each hop in the route, you need prover-specific inputs. Use the TypeScript helpers: + +```typescript +import { + ChildToParentProverHelper, + ParentToChildProverHelper +} from './src/ts'; +import { createPublicClient, http } from 'viem'; +import { arbitrum, mainnet } from 'viem/chains'; + +// Setup clients +const arbitrumClient = createPublicClient({ + chain: arbitrum, + transport: http(process.env.ARBITRUM_RPC_URL) +}); + +const mainnetClient = createPublicClient({ + chain: mainnet, + transport: http(process.env.ETHEREUM_RPC_URL) +}); + +// Build proof for first hop (Arbitrum → Ethereum) +const arbHelper = new ChildToParentProverHelper( + arbitrumClient, + mainnetClient +); + +const { input: scpInput0, targetBlockHash: ethBlockHash } = + await arbHelper.buildInputForGetTargetBlockHash(); +``` + +### Step 3: Call verifyBroadcastMessage + +```solidity +import {IReceiver} from "src/contracts/interfaces/IReceiver.sol"; + +contract MySubscriber { + IReceiver public receiver; + bytes32 public trustedBroadcasterId; + + mapping(bytes32 => bool) public processedMessages; + + constructor(IReceiver _receiver, bytes32 _trustedBroadcasterId) { + receiver = _receiver; + trustedBroadcasterId = _trustedBroadcasterId; + } + + function processMessage( + IReceiver.RemoteReadArgs calldata readArgs, + bytes32 message, + address publisher, + bytes calldata applicationData + ) external { + // Verify the message was broadcast + (bytes32 broadcasterId, uint256 timestamp) = + receiver.verifyBroadcastMessage(readArgs, message, publisher); + + // Verify it's from the trusted broadcaster + require(broadcasterId == trustedBroadcasterId, "Untrusted broadcaster"); + + // Prevent replay + require(!processedMessages[message], "Already processed"); + processedMessages[message] = true; + + // Process the application data + _handleMessage(message, timestamp, applicationData); + } + + function _handleMessage( + bytes32 message, + uint256 timestamp, + bytes calldata data + ) internal { + // Application-specific logic + } +} +``` + +--- + +## Setting Up StateProverCopies + +Before verifying messages through multi-hop routes, you must register StateProverCopies on the destination chain. + +### Step 1: Deploy the StateProverCopy + +Deploy an exact copy of the StateProver on the destination chain: + +```bash +# Get the bytecode from the home chain +BYTECODE=$(cast code $STATE_PROVER_ADDRESS --rpc-url $HOME_CHAIN_RPC) + +# Deploy on destination chain +cast send --create $BYTECODE \ + --rpc-url $DEST_CHAIN_RPC \ + --private-key $PRIVATE_KEY +``` + +### Step 2: Generate Pointer Proof + +You need a proof that reads the StateProverPointer's code hash from `STATE_PROVER_POINTER_SLOT`: + +```typescript +import { keccak256, encodeAbiParameters } from 'viem'; + +// STATE_PROVER_POINTER_SLOT +const SLOT = BigInt(keccak256(encodeAbiParameters( + [{ type: 'string' }], + ['eip7888.pointer.slot'] +))) - 1n; + +// Build proof for the pointer's storage +const { input: pointerProof } = await helper.buildInputForVerifyStorageSlot( + blockHash, + POINTER_ADDRESS, + SLOT +); +``` + +### Step 3: Register the Copy + +```solidity +// Route to the StateProverPointer's home chain +address[] memory route = new address[](1); +route[0] = localPointerAddress; // Pointer that can prove the remote chain + +bytes[] memory scpInputs = new bytes[](1); +scpInputs[0] = /* proof input for the hop */; + +bytes memory pointerStorageProof = /* storage proof for SLOT */; + +IReceiver.RemoteReadArgs memory readArgs = IReceiver.RemoteReadArgs({ + route: route, + scpInputs: scpInputs, + proof: pointerStorageProof +}); + +receiver.updateStateProverCopy(readArgs, IStateProver(copyAddress)); +``` + +--- + +## Building a Cross-Chain Application + +### Example: One-Way Token Bridge + +This example demonstrates a burn-and-mint token bridge using ERC-7888. + +**Burn Side (Source Chain):** + +```solidity +// Burner.sol +import {IBroadcaster} from "src/contracts/interfaces/IBroadcaster.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +struct BurnMessage { + address recipient; + uint256 amount; + uint256 nonce; +} + +contract Burner { + IERC20 public token; + IBroadcaster public broadcaster; + uint256 public burnCount; + + event Burned(bytes32 indexed message, BurnMessage data); + + constructor(IERC20 _token, IBroadcaster _broadcaster) { + token = _token; + broadcaster = _broadcaster; + } + + function burn(address recipient, uint256 amount) external { + // Transfer and burn tokens + token.transferFrom(msg.sender, address(this), amount); + // Assume token has burn function, or send to dead address + + // Create unique message + BurnMessage memory data = BurnMessage({ + recipient: recipient, + amount: amount, + nonce: burnCount++ + }); + bytes32 message = keccak256(abi.encode(data)); + + // Broadcast + broadcaster.broadcastMessage(message); + + emit Burned(message, data); + } +} +``` + +**Mint Side (Destination Chain):** + +```solidity +// Minter.sol +import {IReceiver} from "src/contracts/interfaces/IReceiver.sol"; +import {IERC20Mintable} from "./interfaces/IERC20Mintable.sol"; + +contract Minter { + IReceiver public receiver; + IERC20Mintable public token; + address public trustedBurner; + bytes32 public trustedBroadcasterId; + + mapping(bytes32 => bool) public claimed; + + constructor( + IReceiver _receiver, + IERC20Mintable _token, + address _trustedBurner, + bytes32 _trustedBroadcasterId + ) { + receiver = _receiver; + token = _token; + trustedBurner = _trustedBurner; + trustedBroadcasterId = _trustedBroadcasterId; + } + + function mint( + IReceiver.RemoteReadArgs calldata readArgs, + BurnMessage calldata burnData + ) external { + bytes32 message = keccak256(abi.encode(burnData)); + + require(!claimed[message], "Already claimed"); + + (bytes32 broadcasterId,) = receiver.verifyBroadcastMessage( + readArgs, + message, + trustedBurner + ); + + require(broadcasterId == trustedBroadcasterId, "Wrong broadcaster"); + + claimed[message] = true; + + token.mint(burnData.recipient, burnData.amount); + } +} +``` + +--- + +## Generating Proofs with TypeScript + +### Complete Proof Generation Example + +```typescript +import { + ChildToParentProverHelper, + ParentToChildProverHelper, +} from './src/ts'; +import { createPublicClient, http, keccak256, encodeAbiParameters } from 'viem'; +import { arbitrum, mainnet, optimism } from 'viem/chains'; + +async function generateProofs( + message: `0x${string}`, + publisher: `0x${string}`, + broadcasterAddress: `0x${string}` +) { + // Setup clients + const arbitrumClient = createPublicClient({ + chain: arbitrum, + transport: http(process.env.ARBITRUM_RPC_URL) + }); + + const mainnetClient = createPublicClient({ + chain: mainnet, + transport: http(process.env.ETHEREUM_RPC_URL) + }); + + const optimismClient = createPublicClient({ + chain: optimism, + transport: http(process.env.OPTIMISM_RPC_URL) + }); + + // Route: Optimism → Ethereum → Arbitrum + // Step 1: Get Ethereum block hash from Optimism + const opToEthHelper = new ChildToParentProverHelper( + optimismClient, // home + mainnetClient // target + ); + + const { input: scpInput0, targetBlockHash: ethBlockHash } = + await opToEthHelper.buildInputForGetTargetBlockHash(); + + // Step 2: Get Arbitrum block hash from Ethereum + const ethToArbHelper = new ParentToChildProverHelper( + PROVER_ADDRESS, + mainnetClient, // home + arbitrumClient // target + ); + + const { input: scpInput1, targetBlockHash: arbBlockHash } = + await ethToArbHelper.buildInputForVerifyTargetBlockHash(ethBlockHash); + + // Step 3: Generate storage proof for the broadcaster slot + const messageSlot = BigInt(keccak256(encodeAbiParameters( + [{ type: 'bytes32' }, { type: 'address' }], + [message, publisher] + ))); + + const { input: storageProof, slotValue } = + await ethToArbHelper.buildInputForVerifyStorageSlot( + arbBlockHash, + broadcasterAddress, + messageSlot + ); + + return { + route: [OP_TO_ETH_POINTER, ETH_TO_ARB_POINTER], + scpInputs: [scpInput0, scpInput1], + proof: storageProof, + timestamp: slotValue + }; +} +``` + +### Using the Generated Proof + +```typescript +import { encodeFunctionData } from 'viem'; +import { receiverAbi } from './wagmi/abi'; + +const { route, scpInputs, proof } = await generateProofs(message, publisher, broadcaster); + +const calldata = encodeFunctionData({ + abi: receiverAbi, + functionName: 'verifyBroadcastMessage', + args: [ + { route, scpInputs, proof }, + message, + publisher + ] +}); + +// Send transaction or simulate +const result = await client.simulateContract({ + address: RECEIVER_ADDRESS, + abi: receiverAbi, + functionName: 'verifyBroadcastMessage', + args: [{ route, scpInputs, proof }, message, publisher] +}); + +console.log('Broadcaster ID:', result.result[0]); +console.log('Timestamp:', result.result[1]); +``` + +--- + +## Best Practices + +### 1. Message Design + +- Include nonces for uniqueness +- Use structured data that can be reconstructed from events +- Keep messages to 32 bytes (hash larger payloads) + +### 2. Replay Protection + +- Always track processed messages in subscriber contracts +- Use the `(message, publisher)` pair as the unique key + +### 3. Broadcaster ID Verification + +- Store trusted `broadcasterId` values at deployment +- The `broadcasterId` is deterministic based on the route and broadcaster address + +### 4. Proof Freshness + +- Some chains (e.g., OP Stack) have short-lived state commitments +- Generate proofs just-in-time when possible +- Implement retry logic for stale proof failures + +### 5. Gas Optimization + +- Cache proof results when verifying multiple messages +- Use batch verification patterns for high-throughput applications + +--- + +## Troubleshooting + +| Error | Cause | Solution | +|-------|-------|----------| +| `MessageNotFound` | Slot value is zero | Message not yet broadcast or wrong slot | +| `WrongMessageSlot` | Slot doesn't match expected | Check message/publisher encoding | +| `ProverCopyNotFound` | Missing StateProverCopy | Register copy via `updateStateProverCopy` | +| `DifferentCodeHash` | Copy bytecode mismatch | Deploy exact copy from home chain | +| `NewerProverVersion` | Trying to downgrade | Use a higher version prover | + +--- + +## Links + +- [ERC-7888 Specification](ERC7888.md) +- [StateProvers Reference](PROVERS.md) +- [EIP-7888 on ethereum.org](https://eips.ethereum.org/EIPS/eip-7888) From 3b4b69d56e3ec2a69bf59ebbcc1b5c6cf6c7aa44 Mon Sep 17 00:00:00 2001 From: Luiz Date: Tue, 27 Jan 2026 12:10:12 -0300 Subject: [PATCH 15/25] rename targetBlockHash --- docs/TUTORIAL.md | 6 ++-- scripts/generate-optimism-test-payloads.ts | 26 +++++++------- .../provers/arbitrum/ChildToParentProver.sol | 14 ++++---- .../provers/arbitrum/ParentToChildProver.sol | 18 +++++----- .../provers/linea/ChildToParentProver.sol | 14 ++++---- .../provers/linea/ParentToChildProver.sol | 24 ++++++------- .../provers/optimism/ChildToParentProver.sol | 12 +++---- .../provers/optimism/ParentToChildProver.sol | 10 +++--- .../provers/scroll/ChildToParentProver.sol | 14 ++++---- .../provers/scroll/ParentToChildProver.sol | 26 +++++++------- .../provers/taiko/ChildToParentProver.sol | 22 ++++++------ .../provers/taiko/ParentToChildProver.sol | 22 ++++++------ .../provers/zksync/ChildToParentProver.sol | 14 ++++---- src/ts/ChildToParentProverHelper.ts | 28 +++++++-------- src/ts/IProverHelper.ts | 10 +++--- src/ts/ParentToChildProverHelper.ts | 28 +++++++-------- src/ts/optimism/ChildToParentProverHelper.ts | 18 +++++----- test/mocks/MockProver.sol | 8 ++--- .../arbitrum/ChildToParentProver.t.sol | 36 +++++++++---------- .../arbitrum/ParentToChildProver.t.sol | 10 +++--- .../optimism/ChildToParentProver.t.sol | 12 +++---- test/provers/scroll/ParentToChildProver.t.sol | 2 +- test/provers/taiko/ChildToParentProver.t.sol | 4 +-- test/provers/taiko/ParentToChildProver.t.sol | 4 +-- 24 files changed, 191 insertions(+), 191 deletions(-) diff --git a/docs/TUTORIAL.md b/docs/TUTORIAL.md index bb4a9cf..dee394d 100644 --- a/docs/TUTORIAL.md +++ b/docs/TUTORIAL.md @@ -212,7 +212,7 @@ const arbHelper = new ChildToParentProverHelper( mainnetClient ); -const { input: scpInput0, targetBlockHash: ethBlockHash } = +const { input: scpInput0, targetStateCommitment: ethBlockHash } = await arbHelper.buildInputForGetTargetBlockHash(); ``` @@ -471,7 +471,7 @@ async function generateProofs( mainnetClient // target ); - const { input: scpInput0, targetBlockHash: ethBlockHash } = + const { input: scpInput0, targetStateCommitment: ethBlockHash } = await opToEthHelper.buildInputForGetTargetBlockHash(); // Step 2: Get Arbitrum block hash from Ethereum @@ -481,7 +481,7 @@ async function generateProofs( arbitrumClient // target ); - const { input: scpInput1, targetBlockHash: arbBlockHash } = + const { input: scpInput1, targetStateCommitment: arbBlockHash } = await ethToArbHelper.buildInputForVerifyTargetBlockHash(ethBlockHash); // Step 3: Generate storage proof for the broadcaster slot diff --git a/scripts/generate-optimism-test-payloads.ts b/scripts/generate-optimism-test-payloads.ts index d0765e0..f94cc25 100644 --- a/scripts/generate-optimism-test-payloads.ts +++ b/scripts/generate-optimism-test-payloads.ts @@ -52,17 +52,17 @@ async function main() { // 1. Generate calldata_get.hex console.log('1️⃣ Generating calldata_get.hex...') try { - const { input, targetBlockHash } = await helper.buildInputForGetTargetBlockHash() + const { input, targetStateCommitment } = await helper.buildInputForGetTargetBlockHash() - // Format: [input (32 bytes), targetBlockHash (32 bytes)] + // Format: [input (32 bytes), targetStateCommitment (32 bytes)] const payload = encodeAbiParameters( [{ type: 'bytes32' }, { type: 'bytes32' }], - [input.padEnd(66, '0') as Hash, targetBlockHash] + [input.padEnd(66, '0') as Hash, targetStateCommitment] ) fs.writeFileSync(path.join(outputDir, 'calldata_get.hex'), payload) console.log(` ✅ Input: ${input}`) - console.log(` ✅ Target block hash: ${targetBlockHash}\n`) + console.log(` ✅ Target block hash: ${targetStateCommitment}\n`) } catch (error) { console.error(` ❌ Error: ${error}\n`) } @@ -70,17 +70,17 @@ async function main() { // 2. Generate calldata_verify_target.hex console.log('2️⃣ Generating calldata_verify_target.hex...') try { - const { input, targetBlockHash } = await helper.buildInputForVerifyTargetBlockHash(optimismBlockHash) + const { input, targetStateCommitment } = await helper.buildInputForVerifyTargetBlockHash(optimismBlockHash) - // Format: [homeBlockHash (32 bytes), targetBlockHash (32 bytes), input (variable)] + // Format: [homeBlockHash (32 bytes), targetStateCommitment (32 bytes), input (variable)] const payload = encodeAbiParameters( [{ type: 'bytes32' }, { type: 'bytes32' }, { type: 'bytes' }], - [optimismBlockHash, targetBlockHash, input] + [optimismBlockHash, targetStateCommitment, input] ) fs.writeFileSync(path.join(outputDir, 'calldata_verify_target.hex'), payload) console.log(` ✅ Home block hash: ${optimismBlockHash}`) - console.log(` ✅ Target block hash: ${targetBlockHash}`) + console.log(` ✅ Target block hash: ${targetStateCommitment}`) console.log(` ✅ Input length: ${input.length / 2 - 1} bytes\n`) } catch (error) { console.error(` ❌ Error: ${error}\n`) @@ -95,22 +95,22 @@ async function main() { // Use a RECENT L1 block instead of the one from L1Block (which might be too old for Infura) const recentL1Block = await sepoliaClient.getBlock({ blockTag: 'latest' }) - const targetBlockHash = recentL1Block.hash + const targetStateCommitment = recentL1Block.hash const { input, slotValue } = await helper.buildInputForVerifyStorageSlot( - targetBlockHash, + targetStateCommitment, knownAccount, knownSlot ) - // Format: [targetBlockHash (32 bytes), slotValue (32 bytes), input (variable)] + // Format: [targetStateCommitment (32 bytes), slotValue (32 bytes), input (variable)] const payload = encodeAbiParameters( [{ type: 'bytes32' }, { type: 'bytes32' }, { type: 'bytes' }], - [targetBlockHash, slotValue, input] + [targetStateCommitment, slotValue, input] ) fs.writeFileSync(path.join(outputDir, 'calldata_verify_slot.hex'), payload) - console.log(` ✅ Target block hash: ${targetBlockHash}`) + console.log(` ✅ Target block hash: ${targetStateCommitment}`) console.log(` ✅ Account: ${knownAccount}`) console.log(` ✅ Slot: ${knownSlot}`) console.log(` ✅ Slot value: ${slotValue}`) diff --git a/src/contracts/provers/arbitrum/ChildToParentProver.sol b/src/contracts/provers/arbitrum/ChildToParentProver.sol index 3681013..bf3e39b 100644 --- a/src/contracts/provers/arbitrum/ChildToParentProver.sol +++ b/src/contracts/provers/arbitrum/ChildToParentProver.sol @@ -33,7 +33,7 @@ contract ChildToParentProver is IStateProver { function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view - returns (bytes32 targetBlockHash) + returns (bytes32 targetStateCommitment) { if (block.chainid == homeChainId) { revert CallOnHomeChain(); @@ -47,14 +47,14 @@ contract ChildToParentProver is IStateProver { uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(blockHashMappingSlot), targetBlockNumber)); // verify proofs and get the block hash - targetBlockHash = ProverUtils.getSlotFromBlockHeader( + targetStateCommitment = ProverUtils.getSlotFromBlockHeader( homeBlockHash, rlpBlockHeader, blockHashBuffer, slot, accountProof, storageProof ); } /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer`. /// @param input ABI encoded (uint256 targetBlockNumber) - function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } @@ -62,13 +62,13 @@ contract ChildToParentProver is IStateProver { uint256 targetBlockNumber = abi.decode(input, (uint256)); // get the block hash from the buffer - targetBlockHash = IBuffer(blockHashBuffer).parentChainBlockHash(targetBlockNumber); + targetStateCommitment = IBuffer(blockHashBuffer).parentChainBlockHash(targetBlockNumber); } /// @notice Verify a storage slot given a target chain block hash and a proof. - /// @param targetBlockHash The block hash of the target chain. + /// @param targetStateCommitment The block hash of the target chain. /// @param input ABI encoded (bytes blockHeader, address account, uint256 slot, bytes accountProof, bytes storageProof) - function verifyStorageSlot(bytes32 targetBlockHash, bytes calldata input) + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) external pure returns (address account, uint256 slot, bytes32 value) @@ -82,7 +82,7 @@ contract ChildToParentProver is IStateProver { // verify proofs and get the value value = ProverUtils.getSlotFromBlockHeader( - targetBlockHash, rlpBlockHeader, account, slot, accountProof, storageProof + targetStateCommitment, rlpBlockHeader, account, slot, accountProof, storageProof ); } diff --git a/src/contracts/provers/arbitrum/ParentToChildProver.sol b/src/contracts/provers/arbitrum/ParentToChildProver.sol index 9f8fb98..66caaf2 100644 --- a/src/contracts/provers/arbitrum/ParentToChildProver.sol +++ b/src/contracts/provers/arbitrum/ParentToChildProver.sol @@ -36,7 +36,7 @@ contract ParentToChildProver is IStateProver { function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view - returns (bytes32 targetBlockHash) + returns (bytes32 targetStateCommitment) { if (block.chainid == homeChainId) { revert CallOnHomeChain(); @@ -51,17 +51,17 @@ contract ParentToChildProver is IStateProver { uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(rootsSlot), sendRoot)); // verify proofs and get the block hash - targetBlockHash = + targetStateCommitment = ProverUtils.getSlotFromBlockHeader(homeBlockHash, rlpBlockHeader, outbox, slot, accountProof, storageProof); - if (targetBlockHash == bytes32(0)) { + if (targetStateCommitment == bytes32(0)) { revert TargetBlockHashNotFound(); } } /// @notice Get a target chain block hash given a target chain sendRoot /// @param input ABI encoded (bytes32 sendRoot) - function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } @@ -69,17 +69,17 @@ contract ParentToChildProver is IStateProver { // decode the input bytes32 sendRoot = abi.decode(input, (bytes32)); // get the target block hash from the outbox - targetBlockHash = IOutbox(outbox).roots(sendRoot); + targetStateCommitment = IOutbox(outbox).roots(sendRoot); - if (targetBlockHash == bytes32(0)) { + if (targetStateCommitment == bytes32(0)) { revert TargetBlockHashNotFound(); } } /// @notice Verify a storage slot given a target chain block hash and a proof. - /// @param targetBlockHash The block hash of the target chain. + /// @param targetStateCommitment The block hash of the target chain. /// @param input ABI encoded (bytes blockHeader, address account, uint256 slot, bytes accountProof, bytes storageProof) - function verifyStorageSlot(bytes32 targetBlockHash, bytes calldata input) + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) external pure returns (address account, uint256 slot, bytes32 value) @@ -93,7 +93,7 @@ contract ParentToChildProver is IStateProver { // verify proofs and get the value value = ProverUtils.getSlotFromBlockHeader( - targetBlockHash, rlpBlockHeader, account, slot, accountProof, storageProof + targetStateCommitment, rlpBlockHeader, account, slot, accountProof, storageProof ); } diff --git a/src/contracts/provers/linea/ChildToParentProver.sol b/src/contracts/provers/linea/ChildToParentProver.sol index c3a8eca..80229e6 100644 --- a/src/contracts/provers/linea/ChildToParentProver.sol +++ b/src/contracts/provers/linea/ChildToParentProver.sol @@ -28,7 +28,7 @@ contract ChildToParentProver is IStateProver { function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view - returns (bytes32 targetBlockHash) + returns (bytes32 targetStateCommitment) { if (block.chainid == homeChainId) { revert CallOnHomeChain(); @@ -42,14 +42,14 @@ contract ChildToParentProver is IStateProver { uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(blockHashMappingSlot), targetBlockNumber)); // verify proofs and get the block hash - targetBlockHash = ProverUtils.getSlotFromBlockHeader( + targetStateCommitment = ProverUtils.getSlotFromBlockHeader( homeBlockHash, rlpBlockHeader, blockHashBuffer, slot, accountProof, storageProof ); } /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer`. /// @param input ABI encoded (uint256 targetBlockNumber) - function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } @@ -57,13 +57,13 @@ contract ChildToParentProver is IStateProver { uint256 targetBlockNumber = abi.decode(input, (uint256)); // get the block hash from the buffer - targetBlockHash = IBuffer(blockHashBuffer).parentChainBlockHash(targetBlockNumber); + targetStateCommitment = IBuffer(blockHashBuffer).parentChainBlockHash(targetBlockNumber); } /// @notice Verify a storage slot given a target chain block hash and a proof. - /// @param targetBlockHash The block hash of the target chain. + /// @param targetStateCommitment The block hash of the target chain. /// @param input ABI encoded (bytes blockHeader, address account, uint256 slot, bytes accountProof, bytes storageProof) - function verifyStorageSlot(bytes32 targetBlockHash, bytes calldata input) + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) external pure returns (address account, uint256 slot, bytes32 value) @@ -77,7 +77,7 @@ contract ChildToParentProver is IStateProver { // verify proofs and get the value value = ProverUtils.getSlotFromBlockHeader( - targetBlockHash, rlpBlockHeader, account, slot, accountProof, storageProof + targetStateCommitment, rlpBlockHeader, account, slot, accountProof, storageProof ); } diff --git a/src/contracts/provers/linea/ParentToChildProver.sol b/src/contracts/provers/linea/ParentToChildProver.sol index b0ebe78..a9a51b5 100644 --- a/src/contracts/provers/linea/ParentToChildProver.sol +++ b/src/contracts/provers/linea/ParentToChildProver.sol @@ -54,11 +54,11 @@ contract ParentToChildProver is IStateProver { /// Uses standard MPT proof for L1 state (Ethereum uses MPT) /// @param homeBlockHash The L1 block hash /// @param input ABI encoded (bytes rlpBlockHeader, uint256 l2BlockNumber, bytes accountProof, bytes storageProof) - /// @return targetBlockHash The L2 state root (named "blockHash" for interface compatibility) + /// @return targetStateCommitment The L2 state root (named "blockHash" for interface compatibility) function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view - returns (bytes32 targetBlockHash) + returns (bytes32 targetStateCommitment) { if (block.chainid == homeChainId) { revert CallOnHomeChain(); @@ -73,11 +73,11 @@ contract ParentToChildProver is IStateProver { // Verify proofs and get the L2 state root from L1's LineaRollup // Note: L1 (Ethereum) uses MPT, so we use ProverUtils here - targetBlockHash = ProverUtils.getSlotFromBlockHeader( + targetStateCommitment = ProverUtils.getSlotFromBlockHeader( homeBlockHash, rlpBlockHeader, lineaRollup, slot, accountProof, storageProof ); - if (targetBlockHash == bytes32(0)) { + if (targetStateCommitment == bytes32(0)) { revert TargetStateRootNotFound(); } } @@ -85,8 +85,8 @@ contract ParentToChildProver is IStateProver { /// @notice Get L2 state root directly from L1 LineaRollup /// @dev Called on home chain (L1) /// @param input ABI encoded (uint256 l2BlockNumber) - /// @return targetBlockHash The L2 state root - function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { + /// @return targetStateCommitment The L2 state root + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } @@ -95,16 +95,16 @@ contract ParentToChildProver is IStateProver { uint256 l2BlockNumber = abi.decode(input, (uint256)); // Get the state root from LineaRollup - targetBlockHash = ILineaRollup(lineaRollup).stateRootHashes(l2BlockNumber); + targetStateCommitment = ILineaRollup(lineaRollup).stateRootHashes(l2BlockNumber); - if (targetBlockHash == bytes32(0)) { + if (targetStateCommitment == bytes32(0)) { revert TargetStateRootNotFound(); } } /// @notice Verify a storage slot given a target chain state root and a Sparse Merkle Tree proof /// @dev Works on any chain. Uses Linea's SMT verification with MiMC hashing. - /// IMPORTANT: For Linea, targetBlockHash is the L2 SMT STATE ROOT (not block hash) + /// IMPORTANT: For Linea, targetStateCommitment is the L2 SMT STATE ROOT (not block hash) /// Proofs must be generated using linea_getProof RPC method. /// /// Input format from linea_getProof: @@ -123,12 +123,12 @@ contract ParentToChildProver is IStateProver { /// 5. The storage proof corresponds to the claimed slot (hKey check) /// 6. The storage value matches the proof's hValue /// - /// @param targetBlockHash The L2 SMT state root (from getTargetStateCommitment or verifyTargetStateCommitment) + /// @param targetStateCommitment The L2 SMT state root (from getTargetStateCommitment or verifyTargetStateCommitment) /// @param input ABI encoded proof data from linea_getProof /// @return account The address of the account on L2 /// @return slot The storage slot /// @return value The value at the storage slot - function verifyStorageSlot(bytes32 targetBlockHash, bytes calldata input) + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) external pure returns (address account, uint256 slot, bytes32 value) @@ -153,7 +153,7 @@ contract ParentToChildProver is IStateProver { ) = abi.decode(input, (address, uint256, uint256, bytes[], bytes, uint256, bytes[], bytes32)); // Step 1: Verify account proof against L2 state root (SMT) - bool accountValid = SparseMerkleProof.verifyProof(accountProof, accountLeafIndex, targetBlockHash); + bool accountValid = SparseMerkleProof.verifyProof(accountProof, accountLeafIndex, targetStateCommitment); if (!accountValid) { revert InvalidAccountProof(); } diff --git a/src/contracts/provers/optimism/ChildToParentProver.sol b/src/contracts/provers/optimism/ChildToParentProver.sol index 82dc39a..acef4fc 100644 --- a/src/contracts/provers/optimism/ChildToParentProver.sol +++ b/src/contracts/provers/optimism/ChildToParentProver.sol @@ -36,7 +36,7 @@ contract ChildToParentProver is IStateProver { function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view - returns (bytes32 targetBlockHash) + returns (bytes32 targetStateCommitment) { if (block.chainid == homeChainId) { revert CallOnHomeChain(); @@ -49,7 +49,7 @@ contract ChildToParentProver is IStateProver { (rlpBlockHeader, accountProof, storageProof) = abi.decode(input, (bytes, bytes, bytes)); // verify proofs and get the value - targetBlockHash = ProverUtils.getSlotFromBlockHeader( + targetStateCommitment = ProverUtils.getSlotFromBlockHeader( homeBlockHash, rlpBlockHeader, l1BlockPredeploy, l1BlockHashSlot, accountProof, storageProof ); } @@ -63,7 +63,7 @@ contract ChildToParentProver is IStateProver { /// If the L1Block is consistently updated too frequently, calls to the Receiver may be DoS'd. /// In this case, this prover contract may need to be modified to use a different source of block hashes, /// such as a backup contract that calls the L1Block predeploy and caches the latest block hash. - function getTargetStateCommitment(bytes calldata) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata) external view returns (bytes32 targetStateCommitment) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } @@ -71,9 +71,9 @@ contract ChildToParentProver is IStateProver { } /// @notice Verify a storage slot given a target chain block hash and a proof. - /// @param targetBlockHash The block hash of the target chain. + /// @param targetStateCommitment The block hash of the target chain. /// @param input ABI encoded (bytes blockHeader, address account, uint256 slot, bytes accountProof, bytes storageProof) - function verifyStorageSlot(bytes32 targetBlockHash, bytes calldata input) + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) external pure returns (address account, uint256 slot, bytes32 value) @@ -87,7 +87,7 @@ contract ChildToParentProver is IStateProver { // verify proofs and get the value value = ProverUtils.getSlotFromBlockHeader( - targetBlockHash, rlpBlockHeader, account, slot, accountProof, storageProof + targetStateCommitment, rlpBlockHeader, account, slot, accountProof, storageProof ); } diff --git a/src/contracts/provers/optimism/ParentToChildProver.sol b/src/contracts/provers/optimism/ParentToChildProver.sol index 4d50855..97c276d 100644 --- a/src/contracts/provers/optimism/ParentToChildProver.sol +++ b/src/contracts/provers/optimism/ParentToChildProver.sol @@ -62,7 +62,7 @@ contract ParentToChildProver is IStateProver { function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view - returns (bytes32 targetBlockHash) + returns (bytes32 targetStateCommitment) { if (block.chainid == homeChainId) { revert CallOnHomeChain(); @@ -117,7 +117,7 @@ contract ParentToChildProver is IStateProver { /// 2. Verify the root claim preimage against the game's root claim. /// 3. Return the latest block hash from the root claim preimage. /// @param input ABI encoded (address gameProxy, OutputRootProof rootClaimPreimage) - function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } @@ -135,9 +135,9 @@ contract ParentToChildProver is IStateProver { } /// @notice Verify a storage slot given a target chain block hash and a proof. - /// @param targetBlockHash The block hash of the target chain. + /// @param targetStateCommitment The block hash of the target chain. /// @param input ABI encoded (bytes blockHeader, address account, uint256 slot, bytes accountProof, bytes storageProof) - function verifyStorageSlot(bytes32 targetBlockHash, bytes calldata input) + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) external pure returns (address account, uint256 slot, bytes32 value) @@ -151,7 +151,7 @@ contract ParentToChildProver is IStateProver { // verify proofs and get the value value = ProverUtils.getSlotFromBlockHeader( - targetBlockHash, rlpBlockHeader, account, slot, accountProof, storageProof + targetStateCommitment, rlpBlockHeader, account, slot, accountProof, storageProof ); } diff --git a/src/contracts/provers/scroll/ChildToParentProver.sol b/src/contracts/provers/scroll/ChildToParentProver.sol index 6c92309..fea1fbd 100644 --- a/src/contracts/provers/scroll/ChildToParentProver.sol +++ b/src/contracts/provers/scroll/ChildToParentProver.sol @@ -32,7 +32,7 @@ contract ChildToParentProver is IStateProver { function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view - returns (bytes32 targetBlockHash) + returns (bytes32 targetStateCommitment) { if (block.chainid == homeChainId) { revert CallOnHomeChain(); @@ -46,14 +46,14 @@ contract ChildToParentProver is IStateProver { uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(blockHashMappingSlot), targetBlockNumber)); // verify proofs and get the block hash - targetBlockHash = ProverUtils.getSlotFromBlockHeader( + targetStateCommitment = ProverUtils.getSlotFromBlockHeader( homeBlockHash, rlpBlockHeader, blockHashBuffer, slot, accountProof, storageProof ); } /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer`. /// @param input ABI encoded (uint256 targetBlockNumber) - function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } @@ -61,13 +61,13 @@ contract ChildToParentProver is IStateProver { uint256 targetBlockNumber = abi.decode(input, (uint256)); // get the block hash from the buffer - targetBlockHash = IBuffer(blockHashBuffer).parentChainBlockHash(targetBlockNumber); + targetStateCommitment = IBuffer(blockHashBuffer).parentChainBlockHash(targetBlockNumber); } /// @notice Verify a storage slot given a target chain block hash and a proof. - /// @param targetBlockHash The block hash of the target chain. + /// @param targetStateCommitment The block hash of the target chain. /// @param input ABI encoded (bytes blockHeader, address account, uint256 slot, bytes accountProof, bytes storageProof) - function verifyStorageSlot(bytes32 targetBlockHash, bytes calldata input) + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) external pure returns (address account, uint256 slot, bytes32 value) @@ -81,7 +81,7 @@ contract ChildToParentProver is IStateProver { // verify proofs and get the value value = ProverUtils.getSlotFromBlockHeader( - targetBlockHash, rlpBlockHeader, account, slot, accountProof, storageProof + targetStateCommitment, rlpBlockHeader, account, slot, accountProof, storageProof ); } diff --git a/src/contracts/provers/scroll/ParentToChildProver.sol b/src/contracts/provers/scroll/ParentToChildProver.sol index 0362097..6494eb6 100644 --- a/src/contracts/provers/scroll/ParentToChildProver.sol +++ b/src/contracts/provers/scroll/ParentToChildProver.sol @@ -25,7 +25,7 @@ interface IScrollChain { /// verifyStorageSlot verifies storage against the L2 state root using standard MPT proofs. /// /// NOTE: Unlike other provers that return block hashes, Scroll stores STATE ROOTS directly -/// in the ScrollChain contract. The "targetBlockHash" returned by this prover is actually +/// in the ScrollChain contract. The "targetStateCommitment" returned by this prover is actually /// the L2 state root, which can be used directly for MPT verification without needing /// the L2 block header. contract ParentToChildProver is IStateProver { @@ -58,11 +58,11 @@ contract ParentToChildProver is IStateProver { /// @dev Called on non-home chains (e.g., another L2 that has L1 block hashes) /// @param homeBlockHash The L1 block hash /// @param input ABI encoded (bytes rlpBlockHeader, uint256 batchIndex, bytes accountProof, bytes storageProof) - /// @return targetBlockHash The L2 state root stored in L1's ScrollChain (NOTE: this is a state root, not a block hash) + /// @return targetStateCommitment The L2 state root stored in L1's ScrollChain (NOTE: this is a state root, not a block hash) function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view - returns (bytes32 targetBlockHash) + returns (bytes32 targetStateCommitment) { if (block.chainid == homeChainId) { revert CallOnHomeChain(); @@ -77,11 +77,11 @@ contract ParentToChildProver is IStateProver { uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(finalizedStateRootsSlot), batchIndex)); // Verify proofs and get the L2 state root from L1's ScrollChain - targetBlockHash = ProverUtils.getSlotFromBlockHeader( + targetStateCommitment = ProverUtils.getSlotFromBlockHeader( homeBlockHash, rlpBlockHeader, scrollChain, slot, accountProof, storageProof ); - if (targetBlockHash == bytes32(0)) { + if (targetStateCommitment == bytes32(0)) { revert StateRootNotFound(); } } @@ -89,8 +89,8 @@ contract ParentToChildProver is IStateProver { /// @notice Get L2 state root directly from L1 ScrollChain /// @dev Called on home chain (L1) /// @param input ABI encoded (uint256 batchIndex) - /// @return targetBlockHash The L2 state root (NOTE: this is a state root, not a block hash) - function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { + /// @return targetStateCommitment The L2 state root (NOTE: this is a state root, not a block hash) + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } @@ -99,9 +99,9 @@ contract ParentToChildProver is IStateProver { uint256 batchIndex = abi.decode(input, (uint256)); // Get the state root from ScrollChain - targetBlockHash = IScrollChain(scrollChain).finalizedStateRoots(batchIndex); + targetStateCommitment = IScrollChain(scrollChain).finalizedStateRoots(batchIndex); - if (targetBlockHash == bytes32(0)) { + if (targetStateCommitment == bytes32(0)) { revert StateRootNotFound(); } } @@ -109,17 +109,17 @@ contract ParentToChildProver is IStateProver { /// @notice Verify a storage slot given an L2 state root and a proof /// @dev Since Scroll stores state roots directly (not block hashes), we can verify /// the storage proof directly against the state root without needing the block header. - /// @param targetBlockHash The L2 state root (NOTE: despite the name, this is a state root) + /// @param targetStateCommitment The L2 state root (NOTE: despite the name, this is a state root) /// @param input ABI encoded (address account, uint256 slot, bytes accountProof, bytes storageProof) /// @return account The address of the account on L2 /// @return slot The storage slot /// @return value The value of the storage slot - function verifyStorageSlot(bytes32 targetBlockHash, bytes calldata input) + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) external pure returns (address account, uint256 slot, bytes32 value) { - // Decode the input - note: no block header needed since targetBlockHash IS the state root + // Decode the input - note: no block header needed since targetStateCommitment IS the state root bytes memory accountProof; bytes memory storageProof; (account, slot, accountProof, storageProof) = abi.decode(input, (address, uint256, bytes, bytes)); @@ -127,7 +127,7 @@ contract ParentToChildProver is IStateProver { // Verify proofs directly against the state root // This works because ScrollChain stores state roots, not block hashes value = ProverUtils.getStorageSlotFromStateRoot( - targetBlockHash, // This is actually the state root + targetStateCommitment, // This is actually the state root accountProof, storageProof, account, diff --git a/src/contracts/provers/taiko/ChildToParentProver.sol b/src/contracts/provers/taiko/ChildToParentProver.sol index c147767..bdc15a0 100644 --- a/src/contracts/provers/taiko/ChildToParentProver.sol +++ b/src/contracts/provers/taiko/ChildToParentProver.sol @@ -46,11 +46,11 @@ contract ChildToParentProver is IStateProver { /// @dev Called on non-home chains (e.g., Ethereum L1) /// @param homeBlockHash The L2 block hash /// @param input ABI encoded (bytes rlpBlockHeader, uint48 l1BlockNumber, bytes accountProof, bytes storageProof) - /// @return targetBlockHash The L1 block hash stored in L2's SignalService + /// @return targetStateCommitment The L1 block hash stored in L2's SignalService function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view - returns (bytes32 targetBlockHash) + returns (bytes32 targetStateCommitment) { if (block.chainid == homeChainId) { revert CallOnHomeChain(); @@ -66,11 +66,11 @@ contract ChildToParentProver is IStateProver { // Verify proofs and get the L1 block hash from L2's SignalService // CheckpointRecord.blockHash is stored at the base slot - targetBlockHash = ProverUtils.getSlotFromBlockHeader( + targetStateCommitment = ProverUtils.getSlotFromBlockHeader( homeBlockHash, rlpBlockHeader, signalService, slot, accountProof, storageProof ); - if (targetBlockHash == bytes32(0)) { + if (targetStateCommitment == bytes32(0)) { revert TargetBlockHashNotFound(); } } @@ -78,8 +78,8 @@ contract ChildToParentProver is IStateProver { /// @notice Get L1 block hash directly from L2 SignalService /// @dev Called on home chain (L2) /// @param input ABI encoded (uint48 l1BlockNumber) - /// @return targetBlockHash The L1 block hash - function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { + /// @return targetStateCommitment The L1 block hash + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } @@ -90,20 +90,20 @@ contract ChildToParentProver is IStateProver { // Get the checkpoint from SignalService ICheckpointStore.Checkpoint memory checkpoint = ICheckpointStore(signalService).getCheckpoint(l1BlockNumber); - targetBlockHash = checkpoint.blockHash; + targetStateCommitment = checkpoint.blockHash; - if (targetBlockHash == bytes32(0)) { + if (targetStateCommitment == bytes32(0)) { revert TargetBlockHashNotFound(); } } /// @notice Verify a storage slot given a target chain block hash and a proof - /// @param targetBlockHash The block hash of the target chain (L1) + /// @param targetStateCommitment The block hash of the target chain (L1) /// @param input ABI encoded (bytes blockHeader, address account, uint256 slot, bytes accountProof, bytes storageProof) /// @return account The address of the account on the target chain /// @return slot The storage slot of the account on the target chain /// @return value The value of the storage slot - function verifyStorageSlot(bytes32 targetBlockHash, bytes calldata input) + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) external pure returns (address account, uint256 slot, bytes32 value) @@ -117,7 +117,7 @@ contract ChildToParentProver is IStateProver { // Verify proofs and get the value value = ProverUtils.getSlotFromBlockHeader( - targetBlockHash, rlpBlockHeader, account, slot, accountProof, storageProof + targetStateCommitment, rlpBlockHeader, account, slot, accountProof, storageProof ); } diff --git a/src/contracts/provers/taiko/ParentToChildProver.sol b/src/contracts/provers/taiko/ParentToChildProver.sol index aa86227..13699af 100644 --- a/src/contracts/provers/taiko/ParentToChildProver.sol +++ b/src/contracts/provers/taiko/ParentToChildProver.sol @@ -46,11 +46,11 @@ contract ParentToChildProver is IStateProver { /// @dev Called on non-home chains (e.g., Taiko L2) /// @param homeBlockHash The L1 block hash /// @param input ABI encoded (bytes rlpBlockHeader, uint48 l2BlockNumber, bytes accountProof, bytes storageProof) - /// @return targetBlockHash The L2 block hash stored in L1's SignalService + /// @return targetStateCommitment The L2 block hash stored in L1's SignalService function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view - returns (bytes32 targetBlockHash) + returns (bytes32 targetStateCommitment) { if (block.chainid == homeChainId) { revert CallOnHomeChain(); @@ -66,11 +66,11 @@ contract ParentToChildProver is IStateProver { // Verify proofs and get the L2 block hash from L1's SignalService // CheckpointRecord.blockHash is stored at the base slot - targetBlockHash = ProverUtils.getSlotFromBlockHeader( + targetStateCommitment = ProverUtils.getSlotFromBlockHeader( homeBlockHash, rlpBlockHeader, signalService, slot, accountProof, storageProof ); - if (targetBlockHash == bytes32(0)) { + if (targetStateCommitment == bytes32(0)) { revert TargetBlockHashNotFound(); } } @@ -78,8 +78,8 @@ contract ParentToChildProver is IStateProver { /// @notice Get L2 block hash directly from L1 SignalService /// @dev Called on home chain (L1) /// @param input ABI encoded (uint48 l2BlockNumber) - /// @return targetBlockHash The L2 block hash - function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { + /// @return targetStateCommitment The L2 block hash + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } @@ -90,20 +90,20 @@ contract ParentToChildProver is IStateProver { // Get the checkpoint from SignalService ICheckpointStore.Checkpoint memory checkpoint = ICheckpointStore(signalService).getCheckpoint(l2BlockNumber); - targetBlockHash = checkpoint.blockHash; + targetStateCommitment = checkpoint.blockHash; - if (targetBlockHash == bytes32(0)) { + if (targetStateCommitment == bytes32(0)) { revert TargetBlockHashNotFound(); } } /// @notice Verify a storage slot given a target chain block hash and a proof - /// @param targetBlockHash The block hash of the target chain (L2) + /// @param targetStateCommitment The block hash of the target chain (L2) /// @param input ABI encoded (bytes blockHeader, address account, uint256 slot, bytes accountProof, bytes storageProof) /// @return account The address of the account on the target chain /// @return slot The storage slot of the account on the target chain /// @return value The value of the storage slot - function verifyStorageSlot(bytes32 targetBlockHash, bytes calldata input) + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) external pure returns (address account, uint256 slot, bytes32 value) @@ -117,7 +117,7 @@ contract ParentToChildProver is IStateProver { // Verify proofs and get the value value = ProverUtils.getSlotFromBlockHeader( - targetBlockHash, rlpBlockHeader, account, slot, accountProof, storageProof + targetStateCommitment, rlpBlockHeader, account, slot, accountProof, storageProof ); } diff --git a/src/contracts/provers/zksync/ChildToParentProver.sol b/src/contracts/provers/zksync/ChildToParentProver.sol index b05a5d6..9a94bcc 100644 --- a/src/contracts/provers/zksync/ChildToParentProver.sol +++ b/src/contracts/provers/zksync/ChildToParentProver.sol @@ -32,7 +32,7 @@ contract ChildToParentProver is IStateProver { function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) external view - returns (bytes32 targetBlockHash) + returns (bytes32 targetStateCommitment) { if (block.chainid == homeChainId) { revert CallOnHomeChain(); @@ -46,14 +46,14 @@ contract ChildToParentProver is IStateProver { uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(blockHashMappingSlot), targetBlockNumber)); // verify proofs and get the block hash - targetBlockHash = ProverUtils.getSlotFromBlockHeader( + targetStateCommitment = ProverUtils.getSlotFromBlockHeader( homeBlockHash, rlpBlockHeader, blockHashBuffer, slot, accountProof, storageProof ); } /// @notice Get a parent chain block hash from the buffer at `blockHashBuffer`. /// @param input ABI encoded (uint256 targetBlockNumber) - function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetBlockHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } @@ -61,13 +61,13 @@ contract ChildToParentProver is IStateProver { uint256 targetBlockNumber = abi.decode(input, (uint256)); // get the block hash from the buffer - targetBlockHash = IBuffer(blockHashBuffer).parentChainBlockHash(targetBlockNumber); + targetStateCommitment = IBuffer(blockHashBuffer).parentChainBlockHash(targetBlockNumber); } /// @notice Verify a storage slot given a target chain block hash and a proof. - /// @param targetBlockHash The block hash of the target chain. + /// @param targetStateCommitment The block hash of the target chain. /// @param input ABI encoded (bytes blockHeader, address account, uint256 slot, bytes accountProof, bytes storageProof) - function verifyStorageSlot(bytes32 targetBlockHash, bytes calldata input) + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) external pure returns (address account, uint256 slot, bytes32 value) @@ -81,7 +81,7 @@ contract ChildToParentProver is IStateProver { // verify proofs and get the value value = ProverUtils.getSlotFromBlockHeader( - targetBlockHash, rlpBlockHeader, account, slot, accountProof, storageProof + targetStateCommitment, rlpBlockHeader, account, slot, accountProof, storageProof ); } diff --git a/src/ts/ChildToParentProverHelper.ts b/src/ts/ChildToParentProverHelper.ts index 9c9c623..dbc7051 100644 --- a/src/ts/ChildToParentProverHelper.ts +++ b/src/ts/ChildToParentProverHelper.ts @@ -38,27 +38,27 @@ export class ChildToParentProverHelper */ async buildInputForGetTargetBlockHash(): Promise<{ input: Hex - targetBlockHash: Hash + targetStateCommitment: Hash }> { - const { targetBlockHash, targetBlockNumber } = + const { targetStateCommitment, targetBlockNumber } = await this._findLatestAvailableTargetChainBlock( await this.homeChainClient.getBlockNumber() ) return { input: encodeAbiParameters([{ type: 'uint256' }], [targetBlockNumber]), - targetBlockHash, + targetStateCommitment, } } async buildInputForGetTargetBlockHashByBlockNumber(blockNumber: bigint): Promise<{ input: Hex - targetBlockHash: Hash + targetStateCommitment: Hash }> { //// TODO return { input: encodeAbiParameters([{ type: 'uint256' }], [blockNumber]), - targetBlockHash: '0x' as `0x${string}`, + targetStateCommitment: '0x' as `0x${string}`, } } @@ -67,11 +67,11 @@ export class ChildToParentProverHelper */ async buildInputForVerifyTargetBlockHash( homeBlockHash: Hash - ): Promise<{ input: Hex; targetBlockHash: Hash }> { + ): Promise<{ input: Hex; targetStateCommitment: Hash }> { const homeBlockNumber = ( await this.homeChainClient.getBlock({ blockHash: homeBlockHash }) ).number - const { targetBlockHash, targetBlockNumber } = + const { targetStateCommitment, targetBlockNumber } = await this._findLatestAvailableTargetChainBlock(homeBlockNumber) const slot = hexToBigInt( @@ -104,7 +104,7 @@ export class ChildToParentProverHelper return { input, - targetBlockHash, + targetStateCommitment, } } @@ -112,18 +112,18 @@ export class ChildToParentProverHelper * @see IProverHelper.buildInputForVerifyStorageSlot */ async buildInputForVerifyStorageSlot( - targetBlockHash: Hash, + targetStateCommitment: Hash, account: Address, slot: bigint ): Promise<{ input: Hex; slotValue: Hash }> { const rlpBlockHeader = await this._getRlpBlockHeader( 'target', - targetBlockHash + targetStateCommitment ) const { rlpAccountProof, rlpStorageProof, slotValue } = await this._getRlpStorageAndAccountProof( 'target', - targetBlockHash, + targetStateCommitment, account, slot ) @@ -146,20 +146,20 @@ export class ChildToParentProverHelper async _findLatestAvailableTargetChainBlock(homeBlockNumber: bigint): Promise<{ targetBlockNumber: bigint - targetBlockHash: Hash + targetStateCommitment: Hash }> { const bufferContract = this._bufferContract() const targetBlockNumber = await bufferContract.read.newestBlockNumber({ blockNumber: homeBlockNumber, }) - const targetBlockHash = await bufferContract.read.parentChainBlockHash( + const targetStateCommitment = await bufferContract.read.parentChainBlockHash( [targetBlockNumber], { blockNumber: homeBlockNumber } ) return { targetBlockNumber, - targetBlockHash, + targetStateCommitment, } } diff --git a/src/ts/IProverHelper.ts b/src/ts/IProverHelper.ts index 8ce8a8a..5806668 100644 --- a/src/ts/IProverHelper.ts +++ b/src/ts/IProverHelper.ts @@ -13,7 +13,7 @@ export interface IProverHelper { */ buildInputForGetTargetBlockHash(): Promise<{ input: Hex - targetBlockHash: Hash + targetStateCommitment: Hash }> /** @@ -23,23 +23,23 @@ export interface IProverHelper { */ buildInputForVerifyTargetBlockHash( homeBlockHash: Hash - ): Promise<{ input: Hex; targetBlockHash: Hash }> + ): Promise<{ input: Hex; targetStateCommitment: Hash }> /** * Build the bytes input argument for the IStateProver::verifyStorageSlot function. - * @param targetBlockHash Target chain block hash that will be passed to the prover and proven against + * @param targetStateCommitment Target chain block hash that will be passed to the prover and proven against * @param account The account to prove the storage slot for * @param slot The storage slot to prove * @returns The input bytes and the slot value */ buildInputForVerifyStorageSlot( - targetBlockHash: Hash, + targetStateCommitment: Hash, account: Address, slot: bigint ): Promise<{ input: Hex; slotValue: Hash }> buildInputForGetTargetBlockHashByBlockNumber(blockNumber: bigint): Promise<{ input: Hex - targetBlockHash: Hash + targetStateCommitment: Hash }> } diff --git a/src/ts/ParentToChildProverHelper.ts b/src/ts/ParentToChildProverHelper.ts index 48aca5e..6a14d92 100644 --- a/src/ts/ParentToChildProverHelper.ts +++ b/src/ts/ParentToChildProverHelper.ts @@ -35,21 +35,21 @@ export class ParentToChildProverHelper */ async buildInputForGetTargetBlockHash(): Promise<{ input: Hex - targetBlockHash: Hash + targetStateCommitment: Hash }> { - const { targetBlockHash, sendRoot } = + const { targetStateCommitment, sendRoot } = await this._findLatestAvailableTargetChainBlock( await this.homeChainClient.getBlockNumber() ) return { input: encodeAbiParameters([{ type: 'bytes32' }], [sendRoot]), - targetBlockHash, + targetStateCommitment, } } async buildInputForGetTargetBlockHashByBlockNumber(blockNumber: bigint): Promise<{ input: Hex - targetBlockHash: Hash + targetStateCommitment: Hash }> { console.log("blockNumber", blockNumber); @@ -58,12 +58,12 @@ export class ParentToChildProverHelper // // @ts-ignore // console.log("sendRoot", targetBlock.sendRoot); - const { targetBlockHash, sendRoot } = await this._findLatestAvailableTargetChainBlock(blockNumber); + const { targetStateCommitment, sendRoot } = await this._findLatestAvailableTargetChainBlock(blockNumber); return { // @ts-ignore input: encodeAbiParameters([{ type: 'bytes32' }], [sendRoot]), - targetBlockHash: targetBlockHash, + targetStateCommitment: targetStateCommitment, } } @@ -72,8 +72,8 @@ export class ParentToChildProverHelper */ async buildInputForVerifyTargetBlockHash( homeBlockHash: Hash - ): Promise<{ input: Hex; targetBlockHash: Hash }> { - const { targetBlockHash, sendRoot } = + ): Promise<{ input: Hex; targetStateCommitment: Hash }> { + const { targetStateCommitment, sendRoot } = await this._findLatestAvailableTargetChainBlock( (await this.homeChainClient.getBlock({ blockHash: homeBlockHash })) .number @@ -111,7 +111,7 @@ export class ParentToChildProverHelper return { input, - targetBlockHash, + targetStateCommitment, } } @@ -119,18 +119,18 @@ export class ParentToChildProverHelper * @see IProverHelper.buildInputForVerifyStorageSlot */ async buildInputForVerifyStorageSlot( - targetBlockHash: Hash, + targetStateCommitment: Hash, account: Address, slot: bigint ): Promise<{ input: Hex; slotValue: Hash }> { const rlpBlockHeader = await this._getRlpBlockHeader( 'target', - targetBlockHash + targetStateCommitment ) const { rlpAccountProof, rlpStorageProof, slotValue } = await this._getRlpStorageAndAccountProof( 'target', - targetBlockHash, + targetStateCommitment, account, slot ) @@ -162,7 +162,7 @@ export class ParentToChildProverHelper overrides?: { logBlockRangeSize?: bigint; maxLogLookback?: bigint } ): Promise<{ sendRoot: Hash - targetBlockHash: Hash + targetStateCommitment: Hash }> { const logBlockRangeSize = overrides?.logBlockRangeSize ?? this.defaultLogBlockRangeSize @@ -207,7 +207,7 @@ export class ParentToChildProverHelper return { sendRoot: latestEvent.args.outputRoot!, - targetBlockHash: latestEvent.args.l2BlockHash!, + targetStateCommitment: latestEvent.args.l2BlockHash!, } } diff --git a/src/ts/optimism/ChildToParentProverHelper.ts b/src/ts/optimism/ChildToParentProverHelper.ts index 7db8969..8dde1ec 100644 --- a/src/ts/optimism/ChildToParentProverHelper.ts +++ b/src/ts/optimism/ChildToParentProverHelper.ts @@ -29,10 +29,10 @@ export class OptimismChildToParentProverHelper */ async buildInputForGetTargetBlockHash(): Promise<{ input: Hex - targetBlockHash: Hash + targetStateCommitment: Hash }> { // Read the L1 block hash directly from the L1Block predeploy - const targetBlockHash = await this.homeChainClient.getStorageAt({ + const targetStateCommitment = await this.homeChainClient.getStorageAt({ address: this.l1BlockPredeploy, slot: `0x${this.l1BlockHashSlot.toString(16)}` as Hex, }) as Hash @@ -41,7 +41,7 @@ export class OptimismChildToParentProverHelper // It reads the predeploy directly return { input: '0x' as Hex, - targetBlockHash, + targetStateCommitment, } } @@ -51,13 +51,13 @@ export class OptimismChildToParentProverHelper */ async buildInputForVerifyTargetBlockHash( homeBlockHash: Hash - ): Promise<{ input: Hex; targetBlockHash: Hash }> { + ): Promise<{ input: Hex; targetStateCommitment: Hash }> { const homeBlockNumber = ( await this.homeChainClient.getBlock({ blockHash: homeBlockHash }) ).number // Read the L1 block hash from the predeploy at this specific block - const targetBlockHash = await this.homeChainClient.getStorageAt({ + const targetStateCommitment = await this.homeChainClient.getStorageAt({ address: this.l1BlockPredeploy, slot: `0x${this.l1BlockHashSlot.toString(16)}` as Hex, blockNumber: homeBlockNumber, @@ -87,7 +87,7 @@ export class OptimismChildToParentProverHelper return { input, - targetBlockHash, + targetStateCommitment, } } @@ -96,18 +96,18 @@ export class OptimismChildToParentProverHelper * This verifies a storage slot on the target chain (Ethereum L1) */ async buildInputForVerifyStorageSlot( - targetBlockHash: Hash, + targetStateCommitment: Hash, account: Address, slot: bigint ): Promise<{ input: Hex; slotValue: Hash }> { const rlpBlockHeader = await this._getRlpBlockHeader( 'target', - targetBlockHash + targetStateCommitment ) const { rlpAccountProof, rlpStorageProof, slotValue } = await this._getRlpStorageAndAccountProof( 'target', - targetBlockHash, + targetStateCommitment, account, slot ) diff --git a/test/mocks/MockProver.sol b/test/mocks/MockProver.sol index ae6ab86..7cc7801 100644 --- a/test/mocks/MockProver.sol +++ b/test/mocks/MockProver.sol @@ -10,18 +10,18 @@ contract MockProver is IStateProver { ) external pure - returns (bytes32 targetBlockHash) + returns (bytes32 targetStateCommitment) { return homeBlockHash; } - function getTargetStateCommitment(bytes calldata input) external pure returns (bytes32 targetBlockHash) { - targetBlockHash = abi.decode(input, (bytes32)); + function getTargetStateCommitment(bytes calldata input) external pure returns (bytes32 targetStateCommitment) { + targetStateCommitment = abi.decode(input, (bytes32)); } function verifyStorageSlot( bytes32, - /*targetBlockHash*/ + /*targetStateCommitment*/ bytes calldata input ) external diff --git a/test/provers/arbitrum/ChildToParentProver.t.sol b/test/provers/arbitrum/ChildToParentProver.t.sol index 5f09a02..e8d0113 100644 --- a/test/provers/arbitrum/ChildToParentProver.t.sol +++ b/test/provers/arbitrum/ChildToParentProver.t.sol @@ -88,27 +88,27 @@ contract BroadcasterTest is Test { assertEq(payload.length, 64); uint256 input; - bytes32 targetBlockHash; + bytes32 targetStateCommitment; assembly { input := mload(add(payload, 0x20)) - targetBlockHash := mload(add(payload, 0x40)) + targetStateCommitment := mload(add(payload, 0x40)) } bytes32 result = childToParentProver.getTargetStateCommitment(abi.encode(input)); - assertEq(result, targetBlockHash); + assertEq(result, targetStateCommitment); } function test_getTargetStateCommitment_broadcast() public { vm.selectFork(childForkId); - bytes32 targetBlockHash = 0x57845b0a97194c2869580ed8857fee67c91f2bb9cdf54368685c0ea5bf25f6c2; + bytes32 targetStateCommitment = 0x57845b0a97194c2869580ed8857fee67c91f2bb9cdf54368685c0ea5bf25f6c2; uint256 blockNumber = 9043658; bytes32 result = childToParentProver.getTargetStateCommitment(abi.encode(blockNumber)); - assertEq(result, targetBlockHash); + assertEq(result, targetStateCommitment); } function test_getTargetStateCommitment_broadcaster() public { @@ -118,16 +118,16 @@ contract BroadcasterTest is Test { assertEq(payload.length, 64); bytes32 input; - bytes32 targetBlockHash; + bytes32 targetStateCommitment; assembly { input := mload(add(payload, 0x20)) - targetBlockHash := mload(add(payload, 0x40)) + targetStateCommitment := mload(add(payload, 0x40)) } bytes32 result = childToParentProver.getTargetStateCommitment(abi.encode(input)); - assertEq(result, targetBlockHash); + assertEq(result, targetStateCommitment); } function test_reverts_getTargetStateCommitment_on_target_chain() public { @@ -139,11 +139,11 @@ contract BroadcasterTest is Test { assertEq(payload.length, 64); bytes32 input; - bytes32 targetBlockHash; + bytes32 targetStateCommitment; assembly { input := mload(add(payload, 0x20)) - targetBlockHash := mload(add(payload, 0x40)) + targetStateCommitment := mload(add(payload, 0x40)) } vm.expectRevert(ChildToParentProver.CallNotOnHomeChain.selector); @@ -169,18 +169,18 @@ contract BroadcasterTest is Test { assertGt(payload.length, 64); bytes32 homeBlockHash; - bytes32 targetBlockHash; + bytes32 targetStateCommitment; bytes memory input = Bytes.slice(payload, 64); assembly { homeBlockHash := mload(add(payload, 0x20)) - targetBlockHash := mload(add(payload, 0x40)) + targetStateCommitment := mload(add(payload, 0x40)) } bytes32 result = childToParentProverCopy.verifyTargetStateCommitment(homeBlockHash, input); - assertEq(result, targetBlockHash); + assertEq(result, targetStateCommitment); } function test_verifyTargetStateCommitment_reverts_on_home_chain() public { @@ -193,13 +193,13 @@ contract BroadcasterTest is Test { assertGt(payload.length, 64); bytes32 homeBlockHash; - bytes32 targetBlockHash; + bytes32 targetStateCommitment; bytes memory input = Bytes.slice(payload, 64); assembly { homeBlockHash := mload(add(payload, 0x20)) - targetBlockHash := mload(add(payload, 0x40)) + targetStateCommitment := mload(add(payload, 0x40)) } vm.expectRevert(ChildToParentProver.CallOnHomeChain.selector); @@ -218,17 +218,17 @@ contract BroadcasterTest is Test { assertGt(payload.length, 64); - bytes32 targetBlockHash; + bytes32 targetStateCommitment; bytes32 storageSlotValue; bytes memory input = Bytes.slice(payload, 64); assembly { - targetBlockHash := mload(add(payload, 0x20)) + targetStateCommitment := mload(add(payload, 0x20)) storageSlotValue := mload(add(payload, 0x40)) } (address account, uint256 slot, bytes32 value) = - childToParentProverCopy.verifyStorageSlot(targetBlockHash, input); + childToParentProverCopy.verifyStorageSlot(targetStateCommitment, input); assertEq(account, knownAccount); assertEq(slot, knownSlot); diff --git a/test/provers/arbitrum/ParentToChildProver.t.sol b/test/provers/arbitrum/ParentToChildProver.t.sol index abd5c1b..c26f26a 100644 --- a/test/provers/arbitrum/ParentToChildProver.t.sol +++ b/test/provers/arbitrum/ParentToChildProver.t.sol @@ -77,11 +77,11 @@ contract ArbitrumParentToChildProverTest is Test { parentForkId = vm.createFork(vm.envString("ETHEREUM_RPC_URL")); vm.selectFork(parentForkId); - // Mock Outbox holds the expected sendRoot -> targetBlockHash mapping for stability + // Mock Outbox holds the expected sendRoot -> targetStateCommitment mapping for stability mockOutbox = new ArbitrumOutputMock(); bytes32 sendRoot = 0x7995a5be000a0212a46f7f128e5ffd6f6a99fa9c72046d9e9b0668bd080712cd; - bytes32 targetBlockHashFromProof = 0xa97ce065a04d2abfec36a459db323721847718d3159d51c4256d271ee3b37e42; - mockOutbox.updateSendRoot(sendRoot, targetBlockHashFromProof); + bytes32 targetStateCommitmentFromProof = 0xa97ce065a04d2abfec36a459db323721847718d3159d51c4256d271ee3b37e42; + mockOutbox.updateSendRoot(sendRoot, targetStateCommitmentFromProof); } function test_getTargetStateCommitment() public { @@ -137,7 +137,7 @@ contract ArbitrumParentToChildProverTest is Test { RLP.Encoder memory enc = RLP.encoder().push(bytes32(0)).push(bytes32(0)).push(bytes32(0)).push(stateRoot); bytes memory rlpBlockHeader = enc.encode(); - bytes32 targetBlockHash = keccak256(rlpBlockHeader); + bytes32 targetStateCommitment = keccak256(rlpBlockHeader); // Outbox contract and storage slot from proof.json address outboxAddress = 0x65f07C7D521164a4d5DaC6eB8Fac8DA067A3B78F; @@ -146,7 +146,7 @@ contract ArbitrumParentToChildProverTest is Test { bytes memory rlpStorageProof = _getStorageProof(); bytes memory input = abi.encode(rlpBlockHeader, outboxAddress, storageSlot, rlpAccountProof, rlpStorageProof); - (address account, uint256 slot, bytes32 value) = prover.verifyStorageSlot(targetBlockHash, input); + (address account, uint256 slot, bytes32 value) = prover.verifyStorageSlot(targetStateCommitment, input); assertEq(account, outboxAddress, "Account should match Outbox address"); assertEq(slot, storageSlot, "Slot should match roots mapping slot"); diff --git a/test/provers/optimism/ChildToParentProver.t.sol b/test/provers/optimism/ChildToParentProver.t.sol index 93584e2..53e0e63 100644 --- a/test/provers/optimism/ChildToParentProver.t.sol +++ b/test/provers/optimism/ChildToParentProver.t.sol @@ -93,17 +93,17 @@ contract OptimismChildToParentProverTest is Test { assertGt(payload.length, 64, "Payload should be > 64 bytes"); bytes32 homeBlockHash; - bytes32 targetBlockHash; + bytes32 targetStateCommitment; bytes memory input = Bytes.slice(payload, 64); assembly { homeBlockHash := mload(add(payload, 0x20)) - targetBlockHash := mload(add(payload, 0x40)) + targetStateCommitment := mload(add(payload, 0x40)) } bytes32 result = childToParentProverCopy.verifyTargetStateCommitment(homeBlockHash, input); - assertEq(result, targetBlockHash, "Target block hash should match"); + assertEq(result, targetStateCommitment, "Target block hash should match"); } /// @notice Test verifyTargetStateCommitment() reverts when called on home chain (Optimism) @@ -146,17 +146,17 @@ contract OptimismChildToParentProverTest is Test { assertGt(payload.length, 64, "Payload should be > 64 bytes"); - bytes32 targetBlockHash; + bytes32 targetStateCommitment; bytes32 storageSlotValue; bytes memory input = Bytes.slice(payload, 64); assembly { - targetBlockHash := mload(add(payload, 0x20)) + targetStateCommitment := mload(add(payload, 0x20)) storageSlotValue := mload(add(payload, 0x40)) } (address account, uint256 slot, bytes32 value) = - childToParentProverCopy.verifyStorageSlot(targetBlockHash, input); + childToParentProverCopy.verifyStorageSlot(targetStateCommitment, input); assertEq(account, knownAccount, "Account should match"); assertEq(slot, knownSlot, "Slot should match"); diff --git a/test/provers/scroll/ParentToChildProver.t.sol b/test/provers/scroll/ParentToChildProver.t.sol index dc0df58..3a63393 100644 --- a/test/provers/scroll/ParentToChildProver.t.sol +++ b/test/provers/scroll/ParentToChildProver.t.sol @@ -126,7 +126,7 @@ contract ScrollChainMock is IScrollChain { // Input: abi.encode(address account, uint256 slot, bytes accountProof, bytes storageProof) bytes memory input = abi.encode(account, slot, rlpAccountProof, rlpStorageProof); - // The "targetBlockHash" for Scroll is actually the state root + // The "targetStateCommitment" for Scroll is actually the state root (address actualAccount, uint256 actualSlot, bytes32 actualValue) = parentToChildProver.verifyStorageSlot(stateRoot, input); diff --git a/test/provers/taiko/ChildToParentProver.t.sol b/test/provers/taiko/ChildToParentProver.t.sol index 806bc36..06629c1 100644 --- a/test/provers/taiko/ChildToParentProver.t.sol +++ b/test/provers/taiko/ChildToParentProver.t.sol @@ -109,9 +109,9 @@ contract TaikoChildToParentProverTest is Test { mockSignalService.setCheckpoint(uint48(L1_BLOCK_NUMBER), L1_BLOCK_HASH, L1_STATE_ROOT); bytes memory input = abi.encode(uint48(L1_BLOCK_NUMBER)); - bytes32 targetBlockHash = prover.getTargetStateCommitment(input); + bytes32 targetStateCommitment = prover.getTargetStateCommitment(input); - assertEq(targetBlockHash, L1_BLOCK_HASH, "targetBlockHash mismatch"); + assertEq(targetStateCommitment, L1_BLOCK_HASH, "targetStateCommitment mismatch"); } function test_getTargetStateCommitment_revertsWhenNotFound() public { diff --git a/test/provers/taiko/ParentToChildProver.t.sol b/test/provers/taiko/ParentToChildProver.t.sol index 116b943..a18e8f8 100644 --- a/test/provers/taiko/ParentToChildProver.t.sol +++ b/test/provers/taiko/ParentToChildProver.t.sol @@ -109,9 +109,9 @@ contract TaikoParentToChildProverTest is Test { mockSignalService.setCheckpoint(uint48(L2_BLOCK_NUMBER), L2_BLOCK_HASH, L2_STATE_ROOT); bytes memory input = abi.encode(uint48(L2_BLOCK_NUMBER)); - bytes32 targetBlockHash = prover.getTargetStateCommitment(input); + bytes32 targetStateCommitment = prover.getTargetStateCommitment(input); - assertEq(targetBlockHash, L2_BLOCK_HASH, "targetBlockHash mismatch"); + assertEq(targetStateCommitment, L2_BLOCK_HASH, "targetStateCommitment mismatch"); } function test_getTargetStateCommitment_revertsWhenNotFound() public { From 0dda275b3806341a6283618b4134c34d4440352c Mon Sep 17 00:00:00 2001 From: Luiz Date: Wed, 28 Jan 2026 09:13:44 -0300 Subject: [PATCH 16/25] remove files --- docs/PROVERS.md | 336 --------------------------- docs/TUTORIAL.md | 588 ----------------------------------------------- 2 files changed, 924 deletions(-) delete mode 100644 docs/PROVERS.md delete mode 100644 docs/TUTORIAL.md diff --git a/docs/PROVERS.md b/docs/PROVERS.md deleted file mode 100644 index d37c726..0000000 --- a/docs/PROVERS.md +++ /dev/null @@ -1,336 +0,0 @@ -# StateProvers Reference - -This document details the chain-specific `StateProver` implementations available in this repository. Each prover handles the unique way its rollup commits state to parent chains. - -## Overview - -Each rollup requires **two provers** for bidirectional communication: - -| Prover Type | Direction | Home Chain | Target Chain | -|-------------|-----------|------------|--------------| -| **ChildToParentProver** | L2 → L1 | Child (L2) | Parent (L1) | -| **ParentToChildProver** | L1 → L2 | Parent (L1) | Child (L2) | - ---- - -## Arbitrum - -### ChildToParentProver - -**Location:** `src/contracts/provers/arbitrum/ChildToParentProver.sol` - -Proves Ethereum (L1) block hashes from Arbitrum (L2). - -**Mechanism:** -- Uses the `ArbSys` precompile at `0x0000000000000000000000000000000000000064` -- Accesses the `l2ToL1Block()` function which returns L1 block numbers -- Uses a `Buffer` contract that stores historical L1 block hashes - -**Key addresses:** -- `ArbSys`: `0x0000000000000000000000000000000000000064` -- `Buffer`: `0x0000000048C4Ed10cF14A02B9E0AbDDA5227b071` - -**Input format for `getTargetStateCommitment`:** -```solidity -abi.encode(uint256 targetBlockNumber) -``` - -**Input format for `verifyTargetStateCommitment`:** -```solidity -abi.encode( - bytes rlpBlockHeader, - uint256 targetBlockNumber, - bytes accountProof, - bytes storageProof -) -``` - -### ParentToChildProver - -**Location:** `src/contracts/provers/arbitrum/ParentToChildProver.sol` - -Proves Arbitrum (L2) block hashes from Ethereum (L1). - -**Mechanism:** -- Uses the `Outbox` contract on L1 which stores Arbitrum's `sendRoot` -- The `sendRoot` maps to confirmed L2 block hashes via `SendRootUpdated` events -- Proves storage in the Outbox's `roots` mapping - -**Key components:** -- `outbox`: Arbitrum's Outbox contract address (chain-specific) -- `rootsSlot`: Storage slot for the roots mapping - -**Input format for `getTargetStateCommitment`:** -```solidity -abi.encode(bytes32 sendRoot) -``` - -**Input format for `verifyTargetStateCommitment`:** -```solidity -abi.encode( - bytes rlpBlockHeader, - bytes32 sendRoot, - bytes accountProof, - bytes storageProof -) -``` - ---- - -## Optimism - -### ChildToParentProver - -**Location:** `src/contracts/provers/optimism/ChildToParentProver.sol` - -Proves Ethereum (L1) block hashes from OP Stack chains. - -**Mechanism:** -- Uses the `L1Block` predeploy at `0x4200000000000000000000000000000000000015` -- The predeploy stores the **latest** L1 block hash only (not historical) -- Proofs must be generated just-in-time as they become stale when L1Block updates (~5 minutes) - -**Key addresses:** -- `L1Block`: `0x4200000000000000000000000000000000000015` -- `l1BlockHashSlot`: `2` - -**Important operational note:** -Pre-generated proofs become stale when L1Block updates. Failed calls may need to be retried with fresh proofs. - -**Input format for `getTargetStateCommitment`:** -```solidity -// bytes argument is ignored - returns latest L1 block hash -``` - -**Input format for `verifyTargetStateCommitment`:** -```solidity -abi.encode( - bytes rlpBlockHeader, - bytes accountProof, - bytes storageProof -) -``` - -### ParentToChildProver - -**Location:** `src/contracts/provers/optimism/ParentToChildProver.sol` - -Proves OP Stack (L2) block hashes from Ethereum (L1). - -**Mechanism:** -- Uses the `L2OutputOracle` on L1 which stores L2 output proposals -- Output proposals contain state roots that commit to L2 state -- Requires finding the latest finalized output proposal - ---- - -## Linea - -### ChildToParentProver - -**Location:** `src/contracts/provers/linea/ChildToParentProver.sol` - -Proves Ethereum (L1) block hashes from Linea (L2). - -**Mechanism:** -- Uses Linea's `L1MessageService` which stores L1 block hashes -- Linea uses a sparse Merkle tree (different from standard MPT) - -**Libraries used:** -- `SparseMerkleProof.sol`: Linea's sparse Merkle proof verification -- `Mimc.sol`: MiMC hash function used in Linea's state tree - -### ParentToChildProver - -**Location:** `src/contracts/provers/linea/ParentToChildProver.sol` - -Proves Linea (L2) block hashes from Ethereum (L1). - -**Mechanism:** -- Uses the `LineaRollup` contract on L1 -- Proves state roots from finalized Linea batches - ---- - -## Scroll - -### ChildToParentProver - -**Location:** `src/contracts/provers/scroll/ChildToParentProver.sol` - -Proves Ethereum (L1) block hashes from Scroll (L2). - -**Mechanism:** -- Uses a `Buffer` contract that stores historical L1 block hashes -- Similar architecture to Arbitrum's ChildToParentProver - -**Key addresses:** -- `Buffer`: Chain-specific buffer address - -### ParentToChildProver - -**Location:** `src/contracts/provers/scroll/ParentToChildProver.sol` - -Proves Scroll (L2) block hashes from Ethereum (L1). - -**Mechanism:** -- Uses the `ScrollChain` contract on L1 -- Proves finalized batch state roots - ---- - -## zkSync - -### ChildToParentProver - -**Location:** `src/contracts/provers/zksync/ChildToParentProver.sol` - -Proves Ethereum (L1) block hashes from zkSync Era (L2). - -**Mechanism:** -- Uses zkSync's system contracts for L1 block hash access -- Different storage/proof structure than EVM-equivalent chains - -**Libraries used:** -- `Merkle.sol`: zkSync's Merkle proof verification -- `MessageHashing.sol`: zkSync-specific message hashing - -### ParentToChildProver - -**Location:** `src/contracts/provers/zksync/ParentToChildProver.sol` - -Proves zkSync Era (L2) block hashes from Ethereum (L1). - -**Mechanism:** -- Uses the zkSync Diamond Proxy on L1 -- Proves state roots from finalized batches - ---- - -## Taiko - -### ChildToParentProver - -**Location:** `src/contracts/provers/taiko/ChildToParentProver.sol` - -Proves Ethereum (L1) block hashes from Taiko (L2). - -### ParentToChildProver - -**Location:** `src/contracts/provers/taiko/ParentToChildProver.sol` - -Proves Taiko (L2) block hashes from Ethereum (L1). - ---- - -## Common Storage Proof Input - -All provers use a common format for `verifyStorageSlot`: - -```solidity -abi.encode( - bytes rlpBlockHeader, // RLP-encoded block header - address account, // Target account address - uint256 slot, // Storage slot to prove - bytes accountProof, // Merkle proof for the account - bytes storageProof // Merkle proof for the storage slot -) -``` - -**Output:** -```solidity -returns ( - address account, // The proven account address - uint256 slot, // The proven storage slot - bytes32 value // The value at the storage slot -) -``` - ---- - -## Implementing a New Prover - -To add support for a new rollup: - -1. **Create the directory structure:** - ``` - src/contracts/provers/{chain-name}/ - ├── ChildToParentProver.sol - └── ParentToChildProver.sol - ``` - -2. **Implement `IStateProver` interface** for both directions - -3. **Identify the state commitment source:** - - For ChildToParentProver: Where does the L2 store L1 block hashes? - - For ParentToChildProver: Where does L1 store finalized L2 state roots? - -4. **Implement the three core functions:** - - `getTargetStateCommitment()`: Direct state access on home chain - - `verifyTargetStateCommitment()`: Proof verification on remote chain - - `verifyStorageSlot()`: Standard MPT proof verification (usually reusable) - -5. **Ensure code hash consistency:** - - Use immutable values or compile-time constants - - Avoid chain-specific storage reads in verification functions - -6. **Add TypeScript helpers** in `src/ts/` for proof generation - ---- - -## ProverUtils Library - -**Location:** `src/contracts/libraries/ProverUtils.sol` - -Shared utilities for all provers: - -```solidity -library ProverUtils { - /// @notice Verify block header hash and extract state root - function getStateRoot(bytes32 blockHash, bytes memory rlpBlockHeader) - internal pure returns (bytes32 stateRoot); - - /// @notice Verify account proof and get account data - function getAccountData( - bytes32 stateRoot, - address account, - bytes memory accountProof - ) internal pure returns (bytes32 storageRoot, ...); - - /// @notice Verify storage proof and get slot value - function getStorageValue( - bytes32 storageRoot, - uint256 slot, - bytes memory storageProof - ) internal pure returns (bytes32 value); - - /// @notice Combined helper: block hash → storage value - function getSlotFromBlockHeader( - bytes32 blockHash, - bytes memory rlpBlockHeader, - address account, - uint256 slot, - bytes memory accountProof, - bytes memory storageProof - ) internal pure returns (bytes32 value); -} -``` - ---- - -## Testing Provers - -Each prover has corresponding tests in `test/provers/{chain-name}/`: - -```bash -# Run all prover tests -forge test --match-path "test/provers/**" - -# Run specific chain tests -forge test --match-path "test/provers/arbitrum/**" - -# Run with fork testing (requires RPC URLs) -forge test --match-path "test/provers/**" --fork-url $ETHEREUM_RPC_URL -``` - -Test payloads are stored in `test/payloads/{chain-name}/` as JSON files containing pre-generated proofs for reproducible testing. diff --git a/docs/TUTORIAL.md b/docs/TUTORIAL.md deleted file mode 100644 index dee394d..0000000 --- a/docs/TUTORIAL.md +++ /dev/null @@ -1,588 +0,0 @@ -# ERC-7888 Tutorial: Cross-Chain Message Broadcasting - -This tutorial walks through implementing cross-chain messaging using ERC-7888. We'll cover broadcasting messages, verifying them on remote chains, and building applications on top of the protocol. - -## Table of Contents - -1. [Prerequisites](#prerequisites) -2. [Architecture Overview](#architecture-overview) -3. [Broadcasting Messages](#broadcasting-messages) -4. [Verifying Messages](#verifying-messages) -5. [Setting Up StateProverCopies](#setting-up-stateprovercopies) -6. [Building a Cross-Chain Application](#building-a-cross-chain-application) -7. [Generating Proofs with TypeScript](#generating-proofs-with-typescript) - ---- - -## Prerequisites - -**Required:** -- Node.js 18+ -- Foundry toolkit (forge, cast) -- Access to RPC endpoints for source and destination chains - -**Install dependencies:** -```bash -yarn install -forge install -``` - -**Environment setup:** -```bash -cp .env.example .env -# Configure RPC URLs for the chains you're working with -``` - ---- - -## Architecture Overview - -### System Components - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ Source Chain (L2-A) │ -│ ┌─────────────┐ ┌──────────────────────────┐ │ -│ │ Publisher │───────▶│ Broadcaster │ │ -│ └─────────────┘ │ stores: timestamp @ slot │ │ -│ └──────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────┘ - │ - State Commitment - (block hash) - │ - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ Parent Chain (Ethereum) │ -│ ┌──────────────────────────────────┐ │ -│ │ Rollup Contract │ │ -│ │ (stores L2 state commitments) │ │ -│ └──────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────┘ - │ - State Commitment - │ - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ Destination Chain (L2-B) │ -│ ┌──────────────────────────────┐ ┌─────────────┐ │ -│ │ Receiver │◀─────│ Subscriber │ │ -│ │ - StateProverCopies │ └─────────────┘ │ -│ │ - verifyBroadcastMessage() │ │ -│ └──────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────┘ -``` - -### Message Flow - -1. **Publisher** broadcasts a 32-byte message on Source Chain -2. **Broadcaster** stores `block.timestamp` at slot `keccak256(message, publisher)` -3. Source chain's state is committed to Parent Chain -4. **Subscriber** on Destination Chain calls **Receiver** with: - - Route of StateProverPointers - - Proofs for each hop - - Storage proof for the message slot -5. **Receiver** verifies the proof chain and returns `(broadcasterId, timestamp)` - ---- - -## Broadcasting Messages - -### Step 1: Deploy or Locate the Broadcaster - -The Broadcaster is a singleton per chain. If not deployed, deploy it: - -```solidity -// Deploy.s.sol -import {Broadcaster} from "../src/contracts/Broadcaster.sol"; - -contract DeployBroadcaster is Script { - function run() external { - vm.startBroadcast(); - Broadcaster broadcaster = new Broadcaster(); - vm.stopBroadcast(); - - console.log("Broadcaster deployed at:", address(broadcaster)); - } -} -``` - -```bash -forge script scripts/DeployBroadcaster.s.sol --rpc-url $SOURCE_RPC --broadcast -``` - -### Step 2: Broadcast a Message - -```solidity -// Your publisher contract -import {IBroadcaster} from "src/contracts/interfaces/IBroadcaster.sol"; - -contract MyPublisher { - IBroadcaster public broadcaster; - uint256 public nonce; - - event MessagePublished(bytes32 indexed message, uint256 nonce); - - constructor(IBroadcaster _broadcaster) { - broadcaster = _broadcaster; - } - - function publish(bytes memory data) external { - // Create unique message with nonce - bytes32 message = keccak256(abi.encode(data, nonce++)); - - // Broadcast - broadcaster.broadcastMessage(message); - - emit MessagePublished(message, nonce - 1); - } -} -``` - -**Direct broadcast via cast:** -```bash -# Encode a message (example: "hello world" padded to 32 bytes) -MESSAGE=$(cast keccak "hello world") - -cast send $BROADCASTER_ADDRESS "broadcastMessage(bytes32)" $MESSAGE \ - --rpc-url $SOURCE_RPC \ - --private-key $PRIVATE_KEY -``` - -### Step 3: Calculate the Storage Slot - -The message is stored at a deterministic slot: - -```solidity -bytes32 slot = keccak256(abi.encode(message, publisher)); -``` - -```bash -# Calculate slot off-chain -PUBLISHER="0xYourPublisherAddress" -cast keccak $(cast abi-encode "encode(bytes32,address)" $MESSAGE $PUBLISHER) -``` - ---- - -## Verifying Messages - -### Step 1: Determine the Route - -A route consists of StateProverPointer addresses from destination to source: - -``` -Destination Chain → Parent Chain → Source Chain - route[0] route[1] -``` - -**Example: Arbitrum → Ethereum → Optimism** -```solidity -address[] memory route = new address[](2); -route[0] = 0x...; // Arbitrum ChildToParent StateProverPointer (on Arbitrum) -route[1] = 0x...; // Ethereum ParentToChild StateProverPointer for Optimism (on Ethereum) -``` - -### Step 2: Build Proof Inputs - -For each hop in the route, you need prover-specific inputs. Use the TypeScript helpers: - -```typescript -import { - ChildToParentProverHelper, - ParentToChildProverHelper -} from './src/ts'; -import { createPublicClient, http } from 'viem'; -import { arbitrum, mainnet } from 'viem/chains'; - -// Setup clients -const arbitrumClient = createPublicClient({ - chain: arbitrum, - transport: http(process.env.ARBITRUM_RPC_URL) -}); - -const mainnetClient = createPublicClient({ - chain: mainnet, - transport: http(process.env.ETHEREUM_RPC_URL) -}); - -// Build proof for first hop (Arbitrum → Ethereum) -const arbHelper = new ChildToParentProverHelper( - arbitrumClient, - mainnetClient -); - -const { input: scpInput0, targetStateCommitment: ethBlockHash } = - await arbHelper.buildInputForGetTargetBlockHash(); -``` - -### Step 3: Call verifyBroadcastMessage - -```solidity -import {IReceiver} from "src/contracts/interfaces/IReceiver.sol"; - -contract MySubscriber { - IReceiver public receiver; - bytes32 public trustedBroadcasterId; - - mapping(bytes32 => bool) public processedMessages; - - constructor(IReceiver _receiver, bytes32 _trustedBroadcasterId) { - receiver = _receiver; - trustedBroadcasterId = _trustedBroadcasterId; - } - - function processMessage( - IReceiver.RemoteReadArgs calldata readArgs, - bytes32 message, - address publisher, - bytes calldata applicationData - ) external { - // Verify the message was broadcast - (bytes32 broadcasterId, uint256 timestamp) = - receiver.verifyBroadcastMessage(readArgs, message, publisher); - - // Verify it's from the trusted broadcaster - require(broadcasterId == trustedBroadcasterId, "Untrusted broadcaster"); - - // Prevent replay - require(!processedMessages[message], "Already processed"); - processedMessages[message] = true; - - // Process the application data - _handleMessage(message, timestamp, applicationData); - } - - function _handleMessage( - bytes32 message, - uint256 timestamp, - bytes calldata data - ) internal { - // Application-specific logic - } -} -``` - ---- - -## Setting Up StateProverCopies - -Before verifying messages through multi-hop routes, you must register StateProverCopies on the destination chain. - -### Step 1: Deploy the StateProverCopy - -Deploy an exact copy of the StateProver on the destination chain: - -```bash -# Get the bytecode from the home chain -BYTECODE=$(cast code $STATE_PROVER_ADDRESS --rpc-url $HOME_CHAIN_RPC) - -# Deploy on destination chain -cast send --create $BYTECODE \ - --rpc-url $DEST_CHAIN_RPC \ - --private-key $PRIVATE_KEY -``` - -### Step 2: Generate Pointer Proof - -You need a proof that reads the StateProverPointer's code hash from `STATE_PROVER_POINTER_SLOT`: - -```typescript -import { keccak256, encodeAbiParameters } from 'viem'; - -// STATE_PROVER_POINTER_SLOT -const SLOT = BigInt(keccak256(encodeAbiParameters( - [{ type: 'string' }], - ['eip7888.pointer.slot'] -))) - 1n; - -// Build proof for the pointer's storage -const { input: pointerProof } = await helper.buildInputForVerifyStorageSlot( - blockHash, - POINTER_ADDRESS, - SLOT -); -``` - -### Step 3: Register the Copy - -```solidity -// Route to the StateProverPointer's home chain -address[] memory route = new address[](1); -route[0] = localPointerAddress; // Pointer that can prove the remote chain - -bytes[] memory scpInputs = new bytes[](1); -scpInputs[0] = /* proof input for the hop */; - -bytes memory pointerStorageProof = /* storage proof for SLOT */; - -IReceiver.RemoteReadArgs memory readArgs = IReceiver.RemoteReadArgs({ - route: route, - scpInputs: scpInputs, - proof: pointerStorageProof -}); - -receiver.updateStateProverCopy(readArgs, IStateProver(copyAddress)); -``` - ---- - -## Building a Cross-Chain Application - -### Example: One-Way Token Bridge - -This example demonstrates a burn-and-mint token bridge using ERC-7888. - -**Burn Side (Source Chain):** - -```solidity -// Burner.sol -import {IBroadcaster} from "src/contracts/interfaces/IBroadcaster.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -struct BurnMessage { - address recipient; - uint256 amount; - uint256 nonce; -} - -contract Burner { - IERC20 public token; - IBroadcaster public broadcaster; - uint256 public burnCount; - - event Burned(bytes32 indexed message, BurnMessage data); - - constructor(IERC20 _token, IBroadcaster _broadcaster) { - token = _token; - broadcaster = _broadcaster; - } - - function burn(address recipient, uint256 amount) external { - // Transfer and burn tokens - token.transferFrom(msg.sender, address(this), amount); - // Assume token has burn function, or send to dead address - - // Create unique message - BurnMessage memory data = BurnMessage({ - recipient: recipient, - amount: amount, - nonce: burnCount++ - }); - bytes32 message = keccak256(abi.encode(data)); - - // Broadcast - broadcaster.broadcastMessage(message); - - emit Burned(message, data); - } -} -``` - -**Mint Side (Destination Chain):** - -```solidity -// Minter.sol -import {IReceiver} from "src/contracts/interfaces/IReceiver.sol"; -import {IERC20Mintable} from "./interfaces/IERC20Mintable.sol"; - -contract Minter { - IReceiver public receiver; - IERC20Mintable public token; - address public trustedBurner; - bytes32 public trustedBroadcasterId; - - mapping(bytes32 => bool) public claimed; - - constructor( - IReceiver _receiver, - IERC20Mintable _token, - address _trustedBurner, - bytes32 _trustedBroadcasterId - ) { - receiver = _receiver; - token = _token; - trustedBurner = _trustedBurner; - trustedBroadcasterId = _trustedBroadcasterId; - } - - function mint( - IReceiver.RemoteReadArgs calldata readArgs, - BurnMessage calldata burnData - ) external { - bytes32 message = keccak256(abi.encode(burnData)); - - require(!claimed[message], "Already claimed"); - - (bytes32 broadcasterId,) = receiver.verifyBroadcastMessage( - readArgs, - message, - trustedBurner - ); - - require(broadcasterId == trustedBroadcasterId, "Wrong broadcaster"); - - claimed[message] = true; - - token.mint(burnData.recipient, burnData.amount); - } -} -``` - ---- - -## Generating Proofs with TypeScript - -### Complete Proof Generation Example - -```typescript -import { - ChildToParentProverHelper, - ParentToChildProverHelper, -} from './src/ts'; -import { createPublicClient, http, keccak256, encodeAbiParameters } from 'viem'; -import { arbitrum, mainnet, optimism } from 'viem/chains'; - -async function generateProofs( - message: `0x${string}`, - publisher: `0x${string}`, - broadcasterAddress: `0x${string}` -) { - // Setup clients - const arbitrumClient = createPublicClient({ - chain: arbitrum, - transport: http(process.env.ARBITRUM_RPC_URL) - }); - - const mainnetClient = createPublicClient({ - chain: mainnet, - transport: http(process.env.ETHEREUM_RPC_URL) - }); - - const optimismClient = createPublicClient({ - chain: optimism, - transport: http(process.env.OPTIMISM_RPC_URL) - }); - - // Route: Optimism → Ethereum → Arbitrum - // Step 1: Get Ethereum block hash from Optimism - const opToEthHelper = new ChildToParentProverHelper( - optimismClient, // home - mainnetClient // target - ); - - const { input: scpInput0, targetStateCommitment: ethBlockHash } = - await opToEthHelper.buildInputForGetTargetBlockHash(); - - // Step 2: Get Arbitrum block hash from Ethereum - const ethToArbHelper = new ParentToChildProverHelper( - PROVER_ADDRESS, - mainnetClient, // home - arbitrumClient // target - ); - - const { input: scpInput1, targetStateCommitment: arbBlockHash } = - await ethToArbHelper.buildInputForVerifyTargetBlockHash(ethBlockHash); - - // Step 3: Generate storage proof for the broadcaster slot - const messageSlot = BigInt(keccak256(encodeAbiParameters( - [{ type: 'bytes32' }, { type: 'address' }], - [message, publisher] - ))); - - const { input: storageProof, slotValue } = - await ethToArbHelper.buildInputForVerifyStorageSlot( - arbBlockHash, - broadcasterAddress, - messageSlot - ); - - return { - route: [OP_TO_ETH_POINTER, ETH_TO_ARB_POINTER], - scpInputs: [scpInput0, scpInput1], - proof: storageProof, - timestamp: slotValue - }; -} -``` - -### Using the Generated Proof - -```typescript -import { encodeFunctionData } from 'viem'; -import { receiverAbi } from './wagmi/abi'; - -const { route, scpInputs, proof } = await generateProofs(message, publisher, broadcaster); - -const calldata = encodeFunctionData({ - abi: receiverAbi, - functionName: 'verifyBroadcastMessage', - args: [ - { route, scpInputs, proof }, - message, - publisher - ] -}); - -// Send transaction or simulate -const result = await client.simulateContract({ - address: RECEIVER_ADDRESS, - abi: receiverAbi, - functionName: 'verifyBroadcastMessage', - args: [{ route, scpInputs, proof }, message, publisher] -}); - -console.log('Broadcaster ID:', result.result[0]); -console.log('Timestamp:', result.result[1]); -``` - ---- - -## Best Practices - -### 1. Message Design - -- Include nonces for uniqueness -- Use structured data that can be reconstructed from events -- Keep messages to 32 bytes (hash larger payloads) - -### 2. Replay Protection - -- Always track processed messages in subscriber contracts -- Use the `(message, publisher)` pair as the unique key - -### 3. Broadcaster ID Verification - -- Store trusted `broadcasterId` values at deployment -- The `broadcasterId` is deterministic based on the route and broadcaster address - -### 4. Proof Freshness - -- Some chains (e.g., OP Stack) have short-lived state commitments -- Generate proofs just-in-time when possible -- Implement retry logic for stale proof failures - -### 5. Gas Optimization - -- Cache proof results when verifying multiple messages -- Use batch verification patterns for high-throughput applications - ---- - -## Troubleshooting - -| Error | Cause | Solution | -|-------|-------|----------| -| `MessageNotFound` | Slot value is zero | Message not yet broadcast or wrong slot | -| `WrongMessageSlot` | Slot doesn't match expected | Check message/publisher encoding | -| `ProverCopyNotFound` | Missing StateProverCopy | Register copy via `updateStateProverCopy` | -| `DifferentCodeHash` | Copy bytecode mismatch | Deploy exact copy from home chain | -| `NewerProverVersion` | Trying to downgrade | Use a higher version prover | - ---- - -## Links - -- [ERC-7888 Specification](ERC7888.md) -- [StateProvers Reference](PROVERS.md) -- [EIP-7888 on ethereum.org](https://eips.ethereum.org/EIPS/eip-7888) From 3242b769250cfab1f6bfbb1f915272c64b3924d6 Mon Sep 17 00:00:00 2001 From: Luiz Date: Wed, 28 Jan 2026 09:16:50 -0300 Subject: [PATCH 17/25] up --- src/contracts/provers/arbitrum/ChildToParentProver.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/contracts/provers/arbitrum/ChildToParentProver.sol b/src/contracts/provers/arbitrum/ChildToParentProver.sol index bf3e39b..3151193 100644 --- a/src/contracts/provers/arbitrum/ChildToParentProver.sol +++ b/src/contracts/provers/arbitrum/ChildToParentProver.sol @@ -18,9 +18,12 @@ contract ChildToParentProver is IStateProver { /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/contracts/Buffer.sol#L32 uint256 public constant blockHashMappingSlot = 51; + /// @dev The chain Id of the home chain, i.e., the child chain. uint256 public immutable homeChainId; + /// @dev Error thrown when the function is called on the home chain. error CallNotOnHomeChain(); + /// @dev Error thrown when the function is called on a non-home chain. error CallOnHomeChain(); constructor(uint256 _homeChainId) { From 43cfcef196d677bbb66550de3bbcc8d4a7f91217 Mon Sep 17 00:00:00 2001 From: Luiz Date: Wed, 28 Jan 2026 09:22:37 -0300 Subject: [PATCH 18/25] update pragma --- src/contracts/libraries/linea/SparseMerkleProof.sol | 2 +- src/contracts/provers/linea/ChildToParentProver.sol | 2 +- src/contracts/provers/linea/ParentToChildProver.sol | 2 +- src/contracts/provers/scroll/ChildToParentProver.sol | 2 +- src/contracts/provers/taiko/ChildToParentProver.sol | 2 +- src/contracts/provers/taiko/ParentToChildProver.sol | 2 +- src/contracts/provers/zksync/ChildToParentProver.sol | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/contracts/libraries/linea/SparseMerkleProof.sol b/src/contracts/libraries/linea/SparseMerkleProof.sol index 5622fa9..3c588ac 100644 --- a/src/contracts/libraries/linea/SparseMerkleProof.sol +++ b/src/contracts/libraries/linea/SparseMerkleProof.sol @@ -2,7 +2,7 @@ // Copyright 2023 Consensys Software Inc. // Adapted for use in ERC-7888 provers -pragma solidity ^0.8.28; +pragma solidity 0.8.30; import {Mimc} from "./Mimc.sol"; diff --git a/src/contracts/provers/linea/ChildToParentProver.sol b/src/contracts/provers/linea/ChildToParentProver.sol index 80229e6..82d9854 100644 --- a/src/contracts/provers/linea/ChildToParentProver.sol +++ b/src/contracts/provers/linea/ChildToParentProver.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.28; +pragma solidity 0.8.30; import {ProverUtils} from "../../libraries/ProverUtils.sol"; import {IStateProver} from "../../interfaces/IStateProver.sol"; diff --git a/src/contracts/provers/linea/ParentToChildProver.sol b/src/contracts/provers/linea/ParentToChildProver.sol index a9a51b5..312dfed 100644 --- a/src/contracts/provers/linea/ParentToChildProver.sol +++ b/src/contracts/provers/linea/ParentToChildProver.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.28; +pragma solidity 0.8.30; import {SparseMerkleProof} from "../../libraries/linea/SparseMerkleProof.sol"; import {ProverUtils} from "../../libraries/ProverUtils.sol"; diff --git a/src/contracts/provers/scroll/ChildToParentProver.sol b/src/contracts/provers/scroll/ChildToParentProver.sol index fea1fbd..1989805 100644 --- a/src/contracts/provers/scroll/ChildToParentProver.sol +++ b/src/contracts/provers/scroll/ChildToParentProver.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.28; +pragma solidity 0.8.30; import {ProverUtils} from "../../libraries/ProverUtils.sol"; import {IStateProver} from "../../interfaces/IStateProver.sol"; diff --git a/src/contracts/provers/taiko/ChildToParentProver.sol b/src/contracts/provers/taiko/ChildToParentProver.sol index bdc15a0..b3ab4d8 100644 --- a/src/contracts/provers/taiko/ChildToParentProver.sol +++ b/src/contracts/provers/taiko/ChildToParentProver.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.28; +pragma solidity 0.8.30; import {ProverUtils} from "../../libraries/ProverUtils.sol"; import {IStateProver} from "../../interfaces/IStateProver.sol"; diff --git a/src/contracts/provers/taiko/ParentToChildProver.sol b/src/contracts/provers/taiko/ParentToChildProver.sol index 13699af..228b3e5 100644 --- a/src/contracts/provers/taiko/ParentToChildProver.sol +++ b/src/contracts/provers/taiko/ParentToChildProver.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.28; +pragma solidity 0.8.30; import {ProverUtils} from "../../libraries/ProverUtils.sol"; import {IStateProver} from "../../interfaces/IStateProver.sol"; diff --git a/src/contracts/provers/zksync/ChildToParentProver.sol b/src/contracts/provers/zksync/ChildToParentProver.sol index 9a94bcc..aa7c5de 100644 --- a/src/contracts/provers/zksync/ChildToParentProver.sol +++ b/src/contracts/provers/zksync/ChildToParentProver.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.28; +pragma solidity 0.8.30; import {ProverUtils} from "../../libraries/ProverUtils.sol"; import {IStateProver} from "../../interfaces/IStateProver.sol"; From 189d2ba7b9ca3989ea68752f12791b33c8fb04d8 Mon Sep 17 00:00:00 2001 From: Luiz Date: Wed, 28 Jan 2026 09:50:28 -0300 Subject: [PATCH 19/25] up --- src/contracts/ZkSyncBroadcaster.sol | 4 +-- src/contracts/interfaces/IBroadcaster.sol | 1 + .../provers/linea/ChildToParentProver.sol | 5 ++- .../provers/linea/ParentToChildProver.sol | 8 ++--- .../provers/scroll/ChildToParentProver.sol | 2 +- .../provers/zksync/ChildToParentProver.sol | 2 +- .../provers/zksync/ParentToChildProver.sol | 32 +++++++++---------- test/provers/zksync/ParentChildToProver.t.sol | 2 +- 8 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/contracts/ZkSyncBroadcaster.sol b/src/contracts/ZkSyncBroadcaster.sol index 9fa3fc8..40b8c43 100644 --- a/src/contracts/ZkSyncBroadcaster.sol +++ b/src/contracts/ZkSyncBroadcaster.sol @@ -37,8 +37,8 @@ contract ZkSyncBroadcaster is IBroadcaster { /// @dev The broadcast timestamp is stored in a deterministic storage slot calculated from hash(message, msg.sender). /// This ensures that each (message, publisher) pair can only be broadcast once. /// A MessageBroadcast event is emitted for off-chain indexing. Additionally, this ZkSync-specific - /// implementation sends an L2->L1 message via the L1Messenger containing the original message and - /// timestamp ABI encoded together (bytes32 message, bytes32 timestamp). + /// implementation sends an L2->L1 message via the L1Messenger containing the message slot and + /// timestamp ABI encoded together (bytes32 slot, uint256 timestamp). /// @param message The 32-byte message to broadcast. /// @custom:throws MessageAlreadyBroadcasted if this exact message has already been broadcast by the sender. function broadcastMessage(bytes32 message) external { diff --git a/src/contracts/interfaces/IBroadcaster.sol b/src/contracts/interfaces/IBroadcaster.sol index 56cadc8..ea7b615 100644 --- a/src/contracts/interfaces/IBroadcaster.sol +++ b/src/contracts/interfaces/IBroadcaster.sol @@ -12,6 +12,7 @@ interface IBroadcaster { /// @dev MUST revert if the publisher has already broadcast the message. /// MUST emit MessageBroadcast. /// MUST store block.timestamp in slot keccak(message, msg.sender). + /// MAY use additional transmission mechanisms (e.g., child-to-parent native bridges) to make messages visible. /// @param message The message to broadcast. function broadcastMessage(bytes32 message) external; } diff --git a/src/contracts/provers/linea/ChildToParentProver.sol b/src/contracts/provers/linea/ChildToParentProver.sol index 82d9854..4754790 100644 --- a/src/contracts/provers/linea/ChildToParentProver.sol +++ b/src/contracts/provers/linea/ChildToParentProver.sol @@ -6,6 +6,9 @@ import {IStateProver} from "../../interfaces/IStateProver.sol"; import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; +/// @notice Linea implementation of a child to parent IStateProver. +/// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the block hash buffer. +/// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. contract ChildToParentProver is IStateProver { address public immutable blockHashBuffer; /// @dev Storage slot the buffer contract uses to store block hashes. @@ -53,7 +56,7 @@ contract ChildToParentProver is IStateProver { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } - //decode the input + // decode the input uint256 targetBlockNumber = abi.decode(input, (uint256)); // get the block hash from the buffer diff --git a/src/contracts/provers/linea/ParentToChildProver.sol b/src/contracts/provers/linea/ParentToChildProver.sol index 312dfed..5df7dcf 100644 --- a/src/contracts/provers/linea/ParentToChildProver.sol +++ b/src/contracts/provers/linea/ParentToChildProver.sol @@ -52,10 +52,10 @@ contract ParentToChildProver is IStateProver { /// @notice Verify L2 state root using L1 LineaRollup storage proof /// @dev Called on non-home chains (e.g., for two-hop L2→L2 verification) /// Uses standard MPT proof for L1 state (Ethereum uses MPT) - /// @param homeBlockHash The L1 block hash + /// @param homeStateCommitment The L1 block hash /// @param input ABI encoded (bytes rlpBlockHeader, uint256 l2BlockNumber, bytes accountProof, bytes storageProof) - /// @return targetStateCommitment The L2 state root (named "blockHash" for interface compatibility) - function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) + /// @return targetStateCommitment The L2 state root + function verifyTargetStateCommitment(bytes32 homeStateCommitment, bytes calldata input) external view returns (bytes32 targetStateCommitment) @@ -74,7 +74,7 @@ contract ParentToChildProver is IStateProver { // Verify proofs and get the L2 state root from L1's LineaRollup // Note: L1 (Ethereum) uses MPT, so we use ProverUtils here targetStateCommitment = ProverUtils.getSlotFromBlockHeader( - homeBlockHash, rlpBlockHeader, lineaRollup, slot, accountProof, storageProof + homeStateCommitment, rlpBlockHeader, lineaRollup, slot, accountProof, storageProof ); if (targetStateCommitment == bytes32(0)) { diff --git a/src/contracts/provers/scroll/ChildToParentProver.sol b/src/contracts/provers/scroll/ChildToParentProver.sol index 1989805..469fbae 100644 --- a/src/contracts/provers/scroll/ChildToParentProver.sol +++ b/src/contracts/provers/scroll/ChildToParentProver.sol @@ -57,7 +57,7 @@ contract ChildToParentProver is IStateProver { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } - //decode the input + // decode the input uint256 targetBlockNumber = abi.decode(input, (uint256)); // get the block hash from the buffer diff --git a/src/contracts/provers/zksync/ChildToParentProver.sol b/src/contracts/provers/zksync/ChildToParentProver.sol index aa7c5de..b3709e9 100644 --- a/src/contracts/provers/zksync/ChildToParentProver.sol +++ b/src/contracts/provers/zksync/ChildToParentProver.sol @@ -57,7 +57,7 @@ contract ChildToParentProver is IStateProver { if (block.chainid != homeChainId) { revert CallNotOnHomeChain(); } - //decode the input + // decode the input uint256 targetBlockNumber = abi.decode(input, (uint256)); // get the block hash from the buffer diff --git a/src/contracts/provers/zksync/ParentToChildProver.sol b/src/contracts/provers/zksync/ParentToChildProver.sol index ca5ab76..317c71d 100644 --- a/src/contracts/provers/zksync/ParentToChildProver.sol +++ b/src/contracts/provers/zksync/ParentToChildProver.sol @@ -81,7 +81,7 @@ contract ParentToChildProver is IStateProver { error L2LogsRootHashNotFound(); /// @notice Error thrown when an operation is attempted on a chain that is not the home chain. - error NotInHomeChain(); + error CallNotOnHomeChain(); /// @notice Error thrown when the batch settlement root does not match the expected target batch root. error BatchSettlementRootMismatch(); @@ -112,16 +112,16 @@ contract ParentToChildProver is IStateProver { /// @notice Verify a target chain L2 logs root hash given a home chain block hash and a proof. /// @dev Verifies that the L2 logs root hash for a specific batch is stored in the gateway ZkChain contract /// by checking the storage slot using storage proofs against the home chain block header. - /// @param homeBlockHash The block hash of the home chain (L1) containing the gateway ZkChain state. + /// @param homeStateCommitment The block hash of the home chain (L1) containing the gateway ZkChain state. /// @param input ABI encoded tuple: (bytes rlpBlockHeader, uint256 batchNumber, bytes storageProof). /// - rlpBlockHeader: RLP-encoded block header of the home chain. /// - batchNumber: The batch number for which to retrieve the L2 logs root hash. /// - proof: Storage proof for the storage slot containing the L2 logs root hash. - /// @return targetL2LogsRootHash The L2 logs root hash for the specified batch number. - function verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input) + /// @return targetStateCommitment The L2 logs root hash for the specified batch number. + function verifyTargetStateCommitment(bytes32 homeStateCommitment, bytes calldata input) external view - returns (bytes32 targetL2LogsRootHash) + returns (bytes32 targetStateCommitment) { if (block.chainid == homeChainId) { revert CallOnHomeChain(); @@ -132,9 +132,9 @@ contract ParentToChildProver is IStateProver { uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(l2LogsRootHashSlot), batchNumber)); - // verify proofs and get the block hash - targetL2LogsRootHash = ProverUtils.getSlotFromBlockHeader( - homeBlockHash, rlpBlockHeader, address(gatewayZkChain), slot, accountProof, storageProof + // verify proofs and get the L2 logs root hash + targetStateCommitment = ProverUtils.getSlotFromBlockHeader( + homeStateCommitment, rlpBlockHeader, address(gatewayZkChain), slot, accountProof, storageProof ); } @@ -142,17 +142,17 @@ contract ParentToChildProver is IStateProver { /// @dev Directly queries the gateway ZkChain contract on the home chain to retrieve the L2 logs root hash. /// This function must be called on the home chain where the gateway ZkChain contract is deployed. /// @param input ABI encoded uint256 batchNumber - the batch number for which to retrieve the L2 logs root hash. - /// @return l2LogsRootHash The L2 logs root hash for the specified batch number. + /// @return targetStateCommitment The L2 logs root hash for the specified batch number. /// @custom:reverts L2LogsRootHashNotFound if the L2 logs root hash is not found (returns zero). - function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 l2LogsRootHash) { + function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) { if (block.chainid != homeChainId) { - revert NotInHomeChain(); + revert CallNotOnHomeChain(); } uint256 batchNumber = abi.decode(input, (uint256)); - l2LogsRootHash = gatewayZkChain.l2LogsRootHash(batchNumber); + targetStateCommitment = gatewayZkChain.l2LogsRootHash(batchNumber); - if (l2LogsRootHash == bytes32(0)) { + if (targetStateCommitment == bytes32(0)) { revert L2LogsRootHashNotFound(); } } @@ -161,7 +161,7 @@ contract ParentToChildProver is IStateProver { /// @dev Verifies that an L2 message is included in a batch by checking its inclusion in the L2 logs Merkle tree. /// The message data is expected to contain a message hash and timestamp, which are used to derive /// the storage slot and value on the target chain. - /// @param targetL2LogRootHash The L2 logs root hash of the target chain batch to verify against. + /// @param targetStateCommitment The L2 logs root hash of the target chain batch to verify against. /// @param input ABI encoded ZkSyncProof containing: /// - batchNumber: The batch number containing the message. /// - index: The leaf proof mask for the message in the Merkle tree. @@ -171,7 +171,7 @@ contract ParentToChildProver is IStateProver { /// @return slot The storage slot derived from the account address and message hash. /// @return value The timestamp value stored in the message data. /// @custom:reverts BatchSettlementRootMismatch if the message is not included in the batch. - function verifyStorageSlot(bytes32 targetL2LogRootHash, bytes calldata input) + function verifyStorageSlot(bytes32 targetStateCommitment, bytes calldata input) external view returns (address account, uint256 slot, bytes32 value) @@ -194,7 +194,7 @@ contract ParentToChildProver is IStateProver { _leafProofMask: proof.index, _leaf: hashedLog, _proof: proof.proof, - _targetBatchRoot: targetL2LogRootHash + _targetBatchRoot: targetStateCommitment })) { revert BatchSettlementRootMismatch(); } diff --git a/test/provers/zksync/ParentChildToProver.t.sol b/test/provers/zksync/ParentChildToProver.t.sol index f91ba06..d7c2d2d 100644 --- a/test/provers/zksync/ParentChildToProver.t.sol +++ b/test/provers/zksync/ParentChildToProver.t.sol @@ -153,7 +153,7 @@ contract ZkSyncParentToChildProverTest is Test { ParentToChildProver prover = new ParentToChildProver(address(mockZkChain), 0, 300, 32657, parentChainId); - vm.expectRevert(ParentToChildProver.NotInHomeChain.selector); + vm.expectRevert(ParentToChildProver.CallNotOnHomeChain.selector); prover.getTargetStateCommitment(abi.encode(43985)); } } From 07da4308a80f994cd21b14a12da088da0d04b11d Mon Sep 17 00:00:00 2001 From: Luiz Date: Wed, 28 Jan 2026 11:11:00 -0300 Subject: [PATCH 20/25] up --- src/contracts/ZkSyncBroadcaster.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contracts/ZkSyncBroadcaster.sol b/src/contracts/ZkSyncBroadcaster.sol index 40b8c43..95081cf 100644 --- a/src/contracts/ZkSyncBroadcaster.sol +++ b/src/contracts/ZkSyncBroadcaster.sol @@ -53,7 +53,7 @@ contract ZkSyncBroadcaster is IBroadcaster { // store the message and its timestamp _writeStorageSlot(slot, block.timestamp); - // send the message and timestamp to L1 via ZkSync's L1Messenger + // send the slot and timestamp to L1 via ZkSync's L1Messenger _l1Messenger.sendToL1(abi.encode(slot, uint256(block.timestamp))); // emit the event From 1c3176461f75a0e18333e49da82fe599feee28c7 Mon Sep 17 00:00:00 2001 From: Luiz Date: Wed, 28 Jan 2026 11:18:57 -0300 Subject: [PATCH 21/25] update natspecs --- src/contracts/provers/arbitrum/ChildToParentProver.sol | 2 -- src/contracts/provers/linea/ChildToParentProver.sol | 2 ++ src/contracts/provers/scroll/ChildToParentProver.sol | 6 ++++-- src/contracts/provers/zksync/ChildToParentProver.sol | 6 ++++-- src/contracts/provers/zksync/ParentToChildProver.sol | 2 -- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/contracts/provers/arbitrum/ChildToParentProver.sol b/src/contracts/provers/arbitrum/ChildToParentProver.sol index 3151193..cf848e9 100644 --- a/src/contracts/provers/arbitrum/ChildToParentProver.sol +++ b/src/contracts/provers/arbitrum/ChildToParentProver.sol @@ -21,9 +21,7 @@ contract ChildToParentProver is IStateProver { /// @dev The chain Id of the home chain, i.e., the child chain. uint256 public immutable homeChainId; - /// @dev Error thrown when the function is called on the home chain. error CallNotOnHomeChain(); - /// @dev Error thrown when the function is called on a non-home chain. error CallOnHomeChain(); constructor(uint256 _homeChainId) { diff --git a/src/contracts/provers/linea/ChildToParentProver.sol b/src/contracts/provers/linea/ChildToParentProver.sol index 4754790..b26deba 100644 --- a/src/contracts/provers/linea/ChildToParentProver.sol +++ b/src/contracts/provers/linea/ChildToParentProver.sol @@ -10,11 +10,13 @@ import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; /// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the block hash buffer. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. contract ChildToParentProver is IStateProver { + /// @dev Address of the block hash buffer contract. address public immutable blockHashBuffer; /// @dev Storage slot the buffer contract uses to store block hashes. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/contracts/Buffer.sol#L32 uint256 public constant blockHashMappingSlot = 51; + /// @dev The chain ID of the home chain (child chain). uint256 public immutable homeChainId; error CallNotOnHomeChain(); diff --git a/src/contracts/provers/scroll/ChildToParentProver.sol b/src/contracts/provers/scroll/ChildToParentProver.sol index 469fbae..974fa5e 100644 --- a/src/contracts/provers/scroll/ChildToParentProver.sol +++ b/src/contracts/provers/scroll/ChildToParentProver.sol @@ -6,16 +6,18 @@ import {IStateProver} from "../../interfaces/IStateProver.sol"; import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; -/// @notice implementation of a child to parent IStateProver. -/// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the block hash buffer on Scroll. +/// @notice Scroll implementation of a child to parent IStateProver. +/// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the block hash buffer. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12 for more details. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. contract ChildToParentProver is IStateProver { + /// @dev Address of the block hash buffer contract. address public immutable blockHashBuffer; /// @dev Storage slot the buffer contract uses to store block hashes. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/contracts/Buffer.sol#L32 uint256 public constant blockHashMappingSlot = 51; + /// @dev The chain ID of the home chain (child chain). uint256 public immutable homeChainId; error CallNotOnHomeChain(); diff --git a/src/contracts/provers/zksync/ChildToParentProver.sol b/src/contracts/provers/zksync/ChildToParentProver.sol index b3709e9..d3ac10e 100644 --- a/src/contracts/provers/zksync/ChildToParentProver.sol +++ b/src/contracts/provers/zksync/ChildToParentProver.sol @@ -6,16 +6,18 @@ import {IStateProver} from "../../interfaces/IStateProver.sol"; import {IBuffer} from "block-hash-pusher/contracts/interfaces/IBuffer.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; -/// @notice implementation of a child to parent IStateProver. -/// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the block hash buffer on ZkSync. +/// @notice ZkSync implementation of a child to parent IStateProver. +/// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the block hash buffer. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12 for more details. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. contract ChildToParentProver is IStateProver { + /// @dev Address of the block hash buffer contract. address public immutable blockHashBuffer; /// @dev Storage slot the buffer contract uses to store block hashes. /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/contracts/Buffer.sol#L32 uint256 public constant blockHashMappingSlot = 51; + /// @dev The chain ID of the home chain (child chain). uint256 public immutable homeChainId; error CallNotOnHomeChain(); diff --git a/src/contracts/provers/zksync/ParentToChildProver.sol b/src/contracts/provers/zksync/ParentToChildProver.sol index 317c71d..fa1d509 100644 --- a/src/contracts/provers/zksync/ParentToChildProver.sol +++ b/src/contracts/provers/zksync/ParentToChildProver.sol @@ -275,9 +275,7 @@ contract ParentToChildProver is IStateProver { }); } - /// @notice Returns the version of this block hash prover implementation. /// @inheritdoc IStateProver - /// @return The version number (currently 1). function version() external pure returns (uint256) { return 1; } From bb5b7f4538b2828a4da2f2d24c79ec018c0a9a88 Mon Sep 17 00:00:00 2001 From: Luiz Date: Wed, 28 Jan 2026 11:37:49 -0300 Subject: [PATCH 22/25] update import to external library --- .../provers/scroll/ParentToChildProver.sol | 14 +------ .../provers/zksync/ParentToChildProver.sol | 1 - test/provers/scroll/ParentToChildProver.t.sol | 40 ++++++++++++++++++- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/contracts/provers/scroll/ParentToChildProver.sol b/src/contracts/provers/scroll/ParentToChildProver.sol index 6494eb6..c974ead 100644 --- a/src/contracts/provers/scroll/ParentToChildProver.sol +++ b/src/contracts/provers/scroll/ParentToChildProver.sol @@ -4,19 +4,7 @@ pragma solidity 0.8.30; import {ProverUtils} from "../../libraries/ProverUtils.sol"; import {IStateProver} from "../../interfaces/IStateProver.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; - -/// @notice Interface for Scroll's ScrollChain contract on L1 -interface IScrollChain { - /// @notice Returns the finalized state root for a given batch index - /// @param batchIndex The index of the batch - /// @return The state root of the finalized batch - function finalizedStateRoots(uint256 batchIndex) external view returns (bytes32); - - /// @notice Returns whether a batch is finalized - /// @param batchIndex The index of the batch - /// @return Whether the batch is finalized - function isBatchFinalized(uint256 batchIndex) external view returns (bool); -} +import {IScrollChain} from "@scroll-tech/scroll-contracts/L1/rollup/IScrollChain.sol"; /// @notice Scroll implementation of a parent to child IStateProver. /// @dev Home chain: L1 (Ethereum). Target chain: L2 (Scroll). diff --git a/src/contracts/provers/zksync/ParentToChildProver.sol b/src/contracts/provers/zksync/ParentToChildProver.sol index fa1d509..da08949 100644 --- a/src/contracts/provers/zksync/ParentToChildProver.sol +++ b/src/contracts/provers/zksync/ParentToChildProver.sol @@ -4,7 +4,6 @@ pragma solidity 0.8.30; import {ProverUtils} from "../../libraries/ProverUtils.sol"; import {IStateProver} from "../../interfaces/IStateProver.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; - import {MessageHashing, ProofData} from "./libraries/MessageHashing.sol"; /// @notice Interface for interacting with ZkChain contracts to retrieve L2 logs root hashes. diff --git a/test/provers/scroll/ParentToChildProver.t.sol b/test/provers/scroll/ParentToChildProver.t.sol index 3a63393..17ee513 100644 --- a/test/provers/scroll/ParentToChildProver.t.sol +++ b/test/provers/scroll/ParentToChildProver.t.sol @@ -3,7 +3,8 @@ pragma solidity ^0.8.27; import {console, Test} from "forge-std/Test.sol"; import {stdJson} from "forge-std/StdJson.sol"; -import {ParentToChildProver, IScrollChain} from "../../../src/contracts/provers/scroll/ParentToChildProver.sol"; +import {ParentToChildProver} from "../../../src/contracts/provers/scroll/ParentToChildProver.sol"; +import {IScrollChain} from "@scroll-tech/scroll-contracts/L1/rollup/IScrollChain.sol"; import {Bytes} from "@openzeppelin/contracts/utils/Bytes.sol"; import {RLP} from "@openzeppelin/contracts/utils/RLP.sol"; @@ -20,6 +21,43 @@ contract ScrollChainMock is IScrollChain { function isBatchFinalized(uint256 batchIndex) external view override returns (bool) { return _isBatchFinalized[batchIndex]; } + + // no-ops + function lastFinalizedBatchIndex() external view returns (uint256) { + return 0; + } + + function committedBatches(uint256 batchIndex) external view returns (bytes32) { + return bytes32(0); + } + + function withdrawRoots(uint256 batchIndex) external view returns (bytes32) { + return bytes32(0); + } + + function commitBatches(uint8 version, bytes32 parentBatchHash, bytes32 lastBatchHash) external { + return; + } + + function revertBatch(bytes calldata batchHeader) external { + return; + } + + function finalizeBundlePostEuclidV2( + bytes calldata batchHeader, + uint256 totalL1MessagesPoppedOverall, + bytes32 postStateRoot, + bytes32 withdrawRoot, + bytes calldata aggrProof + ) external { + return; + } + + function commitAndFinalizeBatch(uint8 version, bytes32 parentBatchHash, FinalizeStruct calldata finalizeStruct) + external + { + return; + } } contract ScrollParentToChildProverTest is Test { From 4926ba3d1fc03a349f80e4a1f11816d719af5cc9 Mon Sep 17 00:00:00 2001 From: Luiz Date: Wed, 28 Jan 2026 13:35:04 -0300 Subject: [PATCH 23/25] update imports to external --- .gitmodules | 3 +++ foundry.lock | 9 ++++++++ lib/openzeppelin-contracts | 2 +- lib/openzeppelin-contracts-upgradeable | 1 + remappings.txt | 3 ++- .../provers/linea/ParentToChildProver.sol | 10 ++------ test/provers/linea/ParentToChildProver.t.sol | 23 +++++++++++++++---- 7 files changed, 37 insertions(+), 14 deletions(-) create mode 160000 lib/openzeppelin-contracts-upgradeable diff --git a/.gitmodules b/.gitmodules index d641a64..872279c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "lib/linea-monorepo"] path = lib/linea-monorepo url = https://github.com/consensys/linea-monorepo +[submodule "lib/openzeppelin-contracts-upgradeable"] + path = lib/openzeppelin-contracts-upgradeable + url = https://github.com/openzeppelin/openzeppelin-contracts-upgradeable diff --git a/foundry.lock b/foundry.lock index 5870cf2..bfc57e4 100644 --- a/foundry.lock +++ b/foundry.lock @@ -5,9 +5,18 @@ "lib/forge-std": { "rev": "8bbcf6e3f8f62f419e5429a0bd89331c85c37824" }, + "lib/linea-monorepo": { + "rev": "3e62ae1fff556279530378f11047120974e9c32a" + }, "lib/openzeppelin-contracts": { "rev": "5eb047a0c10386b6634db56327a1f74e8a0432c2" }, + "lib/openzeppelin-contracts-upgradeable": { + "tag": { + "name": "v5.5.0", + "rev": "aa677e9d28ed78fc427ec47ba2baef2030c58e7c" + } + }, "lib/scroll-contracts": { "tag": { "name": "v4.0.0", diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index 5eb047a..68e4095 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit 5eb047a0c10386b6634db56327a1f74e8a0432c2 +Subproject commit 68e4095c1de9853ae264852178c4466a3046323e diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable new file mode 160000 index 0000000..aa677e9 --- /dev/null +++ b/lib/openzeppelin-contracts-upgradeable @@ -0,0 +1 @@ +Subproject commit aa677e9d28ed78fc427ec47ba2baef2030c58e7c diff --git a/remappings.txt b/remappings.txt index e3b73a6..7c17139 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,5 +1,6 @@ forge-std/=lib/forge-std/src/ -@openzeppelin/=lib/openzeppelin-contracts/ +@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/ +@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ @eth-optimism/=node_modules/@eth-optimism/ @arbitrum/nitro-contracts/=node_modules/@arbitrum/nitro-contracts block-hash-pusher/=lib/block-hash-pusher/ diff --git a/src/contracts/provers/linea/ParentToChildProver.sol b/src/contracts/provers/linea/ParentToChildProver.sol index 5df7dcf..45f599e 100644 --- a/src/contracts/provers/linea/ParentToChildProver.sol +++ b/src/contracts/provers/linea/ParentToChildProver.sol @@ -5,13 +5,7 @@ import {SparseMerkleProof} from "../../libraries/linea/SparseMerkleProof.sol"; import {ProverUtils} from "../../libraries/ProverUtils.sol"; import {IStateProver} from "../../interfaces/IStateProver.sol"; import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; - -interface ILineaRollup { - /// @notice Returns the state root hash for a given L2 block number - /// @param blockNumber The L2 block number - /// @return The state root hash (bytes32(0) if not finalized) - function stateRootHashes(uint256 blockNumber) external view returns (bytes32); -} +import {ZkEvmV2} from "@linea-contracts/rollup/ZkEvmV2.sol"; /// @title Linea ParentToChildProver /// @notice Enables verification of Linea L2 state from Ethereum L1 @@ -95,7 +89,7 @@ contract ParentToChildProver is IStateProver { uint256 l2BlockNumber = abi.decode(input, (uint256)); // Get the state root from LineaRollup - targetStateCommitment = ILineaRollup(lineaRollup).stateRootHashes(l2BlockNumber); + targetStateCommitment = ZkEvmV2(lineaRollup).stateRootHashes(l2BlockNumber); if (targetStateCommitment == bytes32(0)) { revert TargetStateRootNotFound(); diff --git a/test/provers/linea/ParentToChildProver.t.sol b/test/provers/linea/ParentToChildProver.t.sol index 260c103..af86bee 100644 --- a/test/provers/linea/ParentToChildProver.t.sol +++ b/test/provers/linea/ParentToChildProver.t.sol @@ -3,16 +3,31 @@ pragma solidity ^0.8.28; import {Test} from "forge-std/Test.sol"; import {console} from "forge-std/console.sol"; -import {ParentToChildProver, ILineaRollup} from "../../../src/contracts/provers/linea/ParentToChildProver.sol"; +import {ParentToChildProver} from "../../../src/contracts/provers/linea/ParentToChildProver.sol"; +import {ZkEvmV2} from "@linea-contracts/rollup/ZkEvmV2.sol"; import {stdJson} from "forge-std/StdJson.sol"; /// @notice Mock LineaRollup contract for testing -contract MockLineaRollup { - mapping(uint256 => bytes32) public stateRootHashes; - +contract MockLineaRollup is ZkEvmV2 { function setStateRootHash(uint256 blockNumber, bytes32 stateRootHash) external { stateRootHashes[blockNumber] = stateRootHash; } + + function sendMessage(address _to, uint256 _fee, bytes calldata _calldata) external payable { + if (_fee > msg.value) { + revert ValueSentTooLow(); + } + + bytes32 messageHash = keccak256(abi.encode(msg.sender, _to, _fee, msg.value - _fee, 0, _calldata)); + + emit MessageSent(msg.sender, _to, _fee, msg.value - _fee, 0, _calldata, messageHash); + + // no-op + } + + function sender() external view returns (address) { + return TRANSIENT_MESSAGE_SENDER; + } } contract LineaParentToChildProverTest is Test { From 3c3e36e4039473c2cd742321d79bbb74a2419319 Mon Sep 17 00:00:00 2001 From: Luiz Date: Wed, 28 Jan 2026 13:51:18 -0300 Subject: [PATCH 24/25] up --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 872279c..8471ea6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,4 +15,4 @@ url = https://github.com/consensys/linea-monorepo [submodule "lib/openzeppelin-contracts-upgradeable"] path = lib/openzeppelin-contracts-upgradeable - url = https://github.com/openzeppelin/openzeppelin-contracts-upgradeable + url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable From 4ed935f80cd3cd784507623dca645663a1d8a370 Mon Sep 17 00:00:00 2001 From: Luiz Date: Wed, 28 Jan 2026 14:59:28 -0300 Subject: [PATCH 25/25] update docs --- src/contracts/provers/linea/ChildToParentProver.sol | 2 +- src/contracts/provers/scroll/ChildToParentProver.sol | 4 ++-- src/contracts/provers/zksync/ChildToParentProver.sol | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/contracts/provers/linea/ChildToParentProver.sol b/src/contracts/provers/linea/ChildToParentProver.sol index b26deba..42d4091 100644 --- a/src/contracts/provers/linea/ChildToParentProver.sol +++ b/src/contracts/provers/linea/ChildToParentProver.sol @@ -13,7 +13,7 @@ contract ChildToParentProver is IStateProver { /// @dev Address of the block hash buffer contract. address public immutable blockHashBuffer; /// @dev Storage slot the buffer contract uses to store block hashes. - /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/contracts/Buffer.sol#L32 + /// See https://github.com/openintentsframework/broadcaster/blob/main/src/contracts/block-hash-pusher/BaseBuffer.sol uint256 public constant blockHashMappingSlot = 51; /// @dev The chain ID of the home chain (child chain). diff --git a/src/contracts/provers/scroll/ChildToParentProver.sol b/src/contracts/provers/scroll/ChildToParentProver.sol index 974fa5e..fdcba4a 100644 --- a/src/contracts/provers/scroll/ChildToParentProver.sol +++ b/src/contracts/provers/scroll/ChildToParentProver.sol @@ -8,13 +8,13 @@ import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; /// @notice Scroll implementation of a child to parent IStateProver. /// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the block hash buffer. -/// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12 for more details. +/// See https://github.com/openintentsframework/broadcaster/blob/main/src/contracts/block-hash-pusher for more details. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. contract ChildToParentProver is IStateProver { /// @dev Address of the block hash buffer contract. address public immutable blockHashBuffer; /// @dev Storage slot the buffer contract uses to store block hashes. - /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/contracts/Buffer.sol#L32 + /// https://github.com/openintentsframework/broadcaster/blob/main/src/contracts/block-hash-pusher/BaseBuffer.sol uint256 public constant blockHashMappingSlot = 51; /// @dev The chain ID of the home chain (child chain). diff --git a/src/contracts/provers/zksync/ChildToParentProver.sol b/src/contracts/provers/zksync/ChildToParentProver.sol index d3ac10e..a025a69 100644 --- a/src/contracts/provers/zksync/ChildToParentProver.sol +++ b/src/contracts/provers/zksync/ChildToParentProver.sol @@ -8,13 +8,13 @@ import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol"; /// @notice ZkSync implementation of a child to parent IStateProver. /// @dev verifyTargetStateCommitment and getTargetStateCommitment get block hashes from the block hash buffer. -/// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12 for more details. +/// See https://github.com/openintentsframework/broadcaster/blob/main/src/contracts/block-hash-pusher for more details. /// verifyStorageSlot is implemented to work against any parent chain with a standard Ethereum block header and state trie. contract ChildToParentProver is IStateProver { /// @dev Address of the block hash buffer contract. address public immutable blockHashBuffer; /// @dev Storage slot the buffer contract uses to store block hashes. - /// See https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/contracts/Buffer.sol#L32 + /// See https://github.com/openintentsframework/broadcaster/blob/main/src/contracts/block-hash-pusher/BaseBuffer.sol uint256 public constant blockHashMappingSlot = 51; /// @dev The chain ID of the home chain (child chain).