Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions src/contracts/provers/arbitrum/ChildToParentProver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,30 @@ import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol";
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;
address public constant BLOCK_HASH_BUFFER = 0x0000000048C4Ed10cF14A02B9E0AbDDA5227b071;
/// @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;
uint256 public constant BLOCK_HASH_MAPPING_SLOT = 51;

/// @dev The chain Id of the home chain, i.e., the child chain.
uint256 public immutable homeChainId;
uint256 public immutable HOME_CHAIN_ID;

error CallNotOnHomeChain();
error CallOnHomeChain();

constructor(uint256 _homeChainId) {
homeChainId = _homeChainId;
HOME_CHAIN_ID = _homeChainId;
}

/// @notice Get a parent chain block hash from the buffer at `blockHashBuffer` using a storage proof
/// @notice Get a parent chain block hash from the buffer at `BLOCK_HASH_BUFFER` 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 verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input)
external
view
returns (bytes32 targetStateCommitment)
{
if (block.chainid == homeChainId) {
if (block.chainid == HOME_CHAIN_ID) {
revert CallOnHomeChain();
}
// decode the input
Expand All @@ -45,25 +45,25 @@ contract ChildToParentProver is IStateProver {

// calculate the slot based on the provided block number
// see: https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/contracts/Buffer.sol#L32
uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(blockHashMappingSlot), targetBlockNumber));
uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(BLOCK_HASH_MAPPING_SLOT), targetBlockNumber));

// verify proofs and get the block hash
targetStateCommitment = ProverUtils.getSlotFromBlockHeader(
homeBlockHash, rlpBlockHeader, blockHashBuffer, slot, accountProof, storageProof
homeBlockHash, rlpBlockHeader, BLOCK_HASH_BUFFER, slot, accountProof, storageProof
);
}

/// @notice Get a parent chain block hash from the buffer at `blockHashBuffer`.
/// @notice Get a parent chain block hash from the buffer at `BLOCK_HASH_BUFFER`.
/// @param input ABI encoded (uint256 targetBlockNumber)
function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) {
if (block.chainid != homeChainId) {
if (block.chainid != HOME_CHAIN_ID) {
revert CallNotOnHomeChain();
}
//decode the input
uint256 targetBlockNumber = abi.decode(input, (uint256));

// get the block hash from the buffer
targetStateCommitment = IBuffer(blockHashBuffer).parentChainBlockHash(targetBlockNumber);
targetStateCommitment = IBuffer(BLOCK_HASH_BUFFER).parentChainBlockHash(targetBlockNumber);
}

/// @notice Verify a storage slot given a target chain block hash and a proof.
Expand Down
22 changes: 11 additions & 11 deletions src/contracts/provers/arbitrum/ParentToChildProver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@ import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol";
/// 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
address public immutable outbox;
address public immutable OUTBOX;
/// @dev Storage slot the Outbox contract uses to store roots.
/// Should be set to 3 unless the outbox contract has been modified.
/// See https://github.com/OffchainLabs/nitro-contracts/blob/9d0e90ef588f94a9d2ffa4dc22713d91a76f57d4/src/bridge/AbsOutbox.sol#L32
uint256 public immutable rootsSlot;
uint256 public immutable ROOTS_SLOT;

/// @dev The chain ID of the home chain (where this prover reads from).
uint256 public immutable homeChainId;
uint256 public immutable HOME_CHAIN_ID;

error CallNotOnHomeChain();
error CallOnHomeChain();
error TargetBlockHashNotFound();

constructor(address _outbox, uint256 _rootsSlot, uint256 _homeChainId) {
outbox = _outbox;
rootsSlot = _rootsSlot;
homeChainId = _homeChainId;
OUTBOX = _outbox;
ROOTS_SLOT = _rootsSlot;
HOME_CHAIN_ID = _homeChainId;
}

/// @notice Verify a target chain block hash given a home chain block hash and a proof.
Expand All @@ -38,7 +38,7 @@ contract ParentToChildProver is IStateProver {
view
returns (bytes32 targetStateCommitment)
{
if (block.chainid == homeChainId) {
if (block.chainid == HOME_CHAIN_ID) {
revert CallOnHomeChain();
}

Expand All @@ -48,11 +48,11 @@ contract ParentToChildProver is IStateProver {

// calculate the slot based on the provided send root
// see: https://github.com/OffchainLabs/nitro-contracts/blob/9d0e90ef588f94a9d2ffa4dc22713d91a76f57d4/src/bridge/AbsOutbox.sol#L32
uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(rootsSlot), sendRoot));
uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(ROOTS_SLOT), sendRoot));

// verify proofs and get the block hash
targetStateCommitment =
ProverUtils.getSlotFromBlockHeader(homeBlockHash, rlpBlockHeader, outbox, slot, accountProof, storageProof);
ProverUtils.getSlotFromBlockHeader(homeBlockHash, rlpBlockHeader, OUTBOX, slot, accountProof, storageProof);

if (targetStateCommitment == bytes32(0)) {
revert TargetBlockHashNotFound();
Expand All @@ -62,14 +62,14 @@ contract ParentToChildProver is IStateProver {
/// @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 targetStateCommitment) {
if (block.chainid != homeChainId) {
if (block.chainid != HOME_CHAIN_ID) {
revert CallNotOnHomeChain();
}

// decode the input
bytes32 sendRoot = abi.decode(input, (bytes32));
// get the target block hash from the outbox
targetStateCommitment = IOutbox(outbox).roots(sendRoot);
targetStateCommitment = IOutbox(OUTBOX).roots(sendRoot);

if (targetStateCommitment == bytes32(0)) {
revert TargetBlockHashNotFound();
Expand Down
24 changes: 12 additions & 12 deletions src/contracts/provers/linea/ChildToParentProver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,31 @@ import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol";
/// 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;
address public immutable BLOCK_HASH_BUFFER;
/// @dev Storage slot the buffer contract uses to store block hashes.
/// See https://github.com/openintentsframework/broadcaster/blob/main/src/contracts/block-hash-pusher/BaseBuffer.sol
uint256 public constant blockHashMappingSlot = 1;
uint256 public constant BLOCK_HASH_MAPPING_SLOT = 1;

/// @dev The chain ID of the home chain (child chain).
uint256 public immutable homeChainId;
uint256 public immutable HOME_CHAIN_ID;

error CallNotOnHomeChain();
error CallOnHomeChain();

constructor(address _blockHashBuffer, uint256 _homeChainId) {
blockHashBuffer = _blockHashBuffer;
homeChainId = _homeChainId;
BLOCK_HASH_BUFFER = _blockHashBuffer;
HOME_CHAIN_ID = _homeChainId;
}

/// @notice Get a parent chain block hash from the buffer at `blockHashBuffer` using a storage proof
/// @notice Get a parent chain block hash from the buffer at `BLOCK_HASH_BUFFER` 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 verifyTargetStateCommitment(bytes32 homeBlockHash, bytes calldata input)
external
view
returns (bytes32 targetStateCommitment)
{
if (block.chainid == homeChainId) {
if (block.chainid == HOME_CHAIN_ID) {
revert CallOnHomeChain();
}
// decode the input
Expand All @@ -44,25 +44,25 @@ contract ChildToParentProver is IStateProver {

// calculate the slot based on the provided block number
// see: https://github.com/OffchainLabs/block-hash-pusher/blob/a1e26f2e42e6306d1e7f03c5d20fa6aa64ff7a12/contracts/Buffer.sol#L32
uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(blockHashMappingSlot), targetBlockNumber));
uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(BLOCK_HASH_MAPPING_SLOT), targetBlockNumber));

// verify proofs and get the block hash
targetStateCommitment = ProverUtils.getSlotFromBlockHeader(
homeBlockHash, rlpBlockHeader, blockHashBuffer, slot, accountProof, storageProof
homeBlockHash, rlpBlockHeader, BLOCK_HASH_BUFFER, slot, accountProof, storageProof
);
}

/// @notice Get a parent chain block hash from the buffer at `blockHashBuffer`.
/// @notice Get a parent chain block hash from the buffer at `BLOCK_HASH_BUFFER`.
/// @param input ABI encoded (uint256 targetBlockNumber)
function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) {
if (block.chainid != homeChainId) {
if (block.chainid != HOME_CHAIN_ID) {
revert CallNotOnHomeChain();
}
// decode the input
uint256 targetBlockNumber = abi.decode(input, (uint256));

// get the block hash from the buffer
targetStateCommitment = IBuffer(blockHashBuffer).parentChainBlockHash(targetBlockNumber);
targetStateCommitment = IBuffer(BLOCK_HASH_BUFFER).parentChainBlockHash(targetBlockNumber);
}

/// @notice Verify a storage slot given a target chain block hash and a proof.
Expand Down
22 changes: 11 additions & 11 deletions src/contracts/provers/linea/ParentToChildProver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ import {ZkEvmV2} from "@linea-contracts/rollup/ZkEvmV2.sol";
/// The state root stored on L1 is the SMT root, which requires linea_getProof for verification.
contract ParentToChildProver is IStateProver {
/// @dev Address of the LineaRollup contract on L1
address public immutable lineaRollup;
address public immutable LINEA_ROLLUP;

/// @dev Storage slot of the stateRootHashes mapping in LineaRollup
/// mapping(uint256 blockNumber => bytes32 stateRootHash)
uint256 public immutable stateRootHashesSlot;
uint256 public immutable STATE_ROOT_HASHES_SLOT;

/// @dev L1 chain ID (home chain)
uint256 public immutable homeChainId;
uint256 public immutable HOME_CHAIN_ID;

error CallNotOnHomeChain();
error CallOnHomeChain();
Expand All @@ -38,9 +38,9 @@ contract ParentToChildProver is IStateProver {
error StorageKeyMismatch();

constructor(address _lineaRollup, uint256 _stateRootHashesSlot, uint256 _homeChainId) {
lineaRollup = _lineaRollup;
stateRootHashesSlot = _stateRootHashesSlot;
homeChainId = _homeChainId;
LINEA_ROLLUP = _lineaRollup;
STATE_ROOT_HASHES_SLOT = _stateRootHashesSlot;
HOME_CHAIN_ID = _homeChainId;
}

/// @notice Verify L2 state root using L1 LineaRollup storage proof
Expand All @@ -54,7 +54,7 @@ contract ParentToChildProver is IStateProver {
view
returns (bytes32 targetStateCommitment)
{
if (block.chainid == homeChainId) {
if (block.chainid == HOME_CHAIN_ID) {
revert CallOnHomeChain();
}

Expand All @@ -63,12 +63,12 @@ contract ParentToChildProver is IStateProver {
abi.decode(input, (bytes, uint256, bytes, bytes));

// Calculate storage slot for stateRootHashes[l2BlockNumber]
uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(stateRootHashesSlot), l2BlockNumber));
uint256 slot = uint256(SlotDerivation.deriveMapping(bytes32(STATE_ROOT_HASHES_SLOT), l2BlockNumber));

// 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(
homeStateCommitment, rlpBlockHeader, lineaRollup, slot, accountProof, storageProof
homeStateCommitment, rlpBlockHeader, LINEA_ROLLUP, slot, accountProof, storageProof
);

if (targetStateCommitment == bytes32(0)) {
Expand All @@ -81,15 +81,15 @@ contract ParentToChildProver is IStateProver {
/// @param input ABI encoded (uint256 l2BlockNumber)
/// @return targetStateCommitment The L2 state root
function getTargetStateCommitment(bytes calldata input) external view returns (bytes32 targetStateCommitment) {
if (block.chainid != homeChainId) {
if (block.chainid != HOME_CHAIN_ID) {
revert CallNotOnHomeChain();
}

// Decode the input
uint256 l2BlockNumber = abi.decode(input, (uint256));

// Get the state root from LineaRollup
targetStateCommitment = ZkEvmV2(lineaRollup).stateRootHashes(l2BlockNumber);
targetStateCommitment = ZkEvmV2(LINEA_ROLLUP).stateRootHashes(l2BlockNumber);

if (targetStateCommitment == bytes32(0)) {
revert TargetStateRootNotFound();
Expand Down
16 changes: 8 additions & 8 deletions src/contracts/provers/optimism/ChildToParentProver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ interface IL1Block {
/// 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 IStateProver {
address public constant l1BlockPredeploy = 0x4200000000000000000000000000000000000015;
uint256 public constant l1BlockHashSlot = 2; // hash is at slot 2
address public constant L1_BLOCK_PREDEPLOY = 0x4200000000000000000000000000000000000015;
uint256 public constant L1_BLOCK_HASH_SLOT = 2; // hash is at slot 2

/// @dev The chain ID of the home chain (Optimism L2)
uint256 public immutable homeChainId;
uint256 public immutable HOME_CHAIN_ID;

error CallNotOnHomeChain();
error CallOnHomeChain();

constructor(uint256 _homeChainId) {
homeChainId = _homeChainId;
HOME_CHAIN_ID = _homeChainId;
}

/// @notice Verify the latest available target block hash given a home chain block hash and a storage proof of the L1Block predeploy.
Expand All @@ -38,7 +38,7 @@ contract ChildToParentProver is IStateProver {
view
returns (bytes32 targetStateCommitment)
{
if (block.chainid == homeChainId) {
if (block.chainid == HOME_CHAIN_ID) {
revert CallOnHomeChain();
}

Expand All @@ -50,7 +50,7 @@ contract ChildToParentProver is IStateProver {

// verify proofs and get the value
targetStateCommitment = ProverUtils.getSlotFromBlockHeader(
homeBlockHash, rlpBlockHeader, l1BlockPredeploy, l1BlockHashSlot, accountProof, storageProof
homeBlockHash, rlpBlockHeader, L1_BLOCK_PREDEPLOY, L1_BLOCK_HASH_SLOT, accountProof, storageProof
);
}

Expand All @@ -64,10 +64,10 @@ contract ChildToParentProver is IStateProver {
/// 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 targetStateCommitment) {
if (block.chainid != homeChainId) {
if (block.chainid != HOME_CHAIN_ID) {
revert CallNotOnHomeChain();
}
return IL1Block(l1BlockPredeploy).hash();
return IL1Block(L1_BLOCK_PREDEPLOY).hash();
}

/// @notice Verify a storage slot given a target chain block hash and a proof.
Expand Down
16 changes: 8 additions & 8 deletions src/contracts/provers/optimism/ParentToChildProver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,17 @@ contract ParentToChildProver is IStateProver {
uint256 public constant ANCHOR_GAME_SLOT = 3;

/// @notice The target chain's AnchorStateRegistry address.
address public immutable anchorStateRegistry;
address public immutable ANCHOR_STATE_REGISTRY;

/// @dev The chain ID of the home chain (where this prover reads from).
uint256 public immutable homeChainId;
uint256 public immutable HOME_CHAIN_ID;

error CallNotOnHomeChain();
error CallOnHomeChain();

constructor(address _anchorStateRegistry, uint256 _homeChainId) {
anchorStateRegistry = _anchorStateRegistry;
homeChainId = _homeChainId;
ANCHOR_STATE_REGISTRY = _anchorStateRegistry;
HOME_CHAIN_ID = _homeChainId;
}

/// @notice Verify the latest available target block hash given a home chain block hash, a storage proof of the AnchorStateRegistry, the anchor game proxy code and a root claim preimage.
Expand All @@ -64,7 +64,7 @@ contract ParentToChildProver is IStateProver {
view
returns (bytes32 targetStateCommitment)
{
if (block.chainid == homeChainId) {
if (block.chainid == HOME_CHAIN_ID) {
revert CallOnHomeChain();
}

Expand All @@ -87,7 +87,7 @@ contract ParentToChildProver is IStateProver {
uint160(
uint256(
ProverUtils.getStorageSlotFromStateRoot(
stateRoot, asrAccountProof, asrStorageProof, anchorStateRegistry, ANCHOR_GAME_SLOT
stateRoot, asrAccountProof, asrStorageProof, ANCHOR_STATE_REGISTRY, ANCHOR_GAME_SLOT
)
)
)
Expand Down Expand Up @@ -118,15 +118,15 @@ contract ParentToChildProver is IStateProver {
/// 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 targetStateCommitment) {
if (block.chainid != homeChainId) {
if (block.chainid != HOME_CHAIN_ID) {
revert CallNotOnHomeChain();
}

// decode the input
(address gameProxy, OutputRootProof memory rootClaimPreimage) = abi.decode(input, (address, OutputRootProof));

// check the game proxy address
require(IAnchorStateRegistry(anchorStateRegistry).isGameClaimValid(gameProxy), "Invalid game proxy");
require(IAnchorStateRegistry(ANCHOR_STATE_REGISTRY).isGameClaimValid(gameProxy), "Invalid game proxy");

bytes32 rootClaim = IFaultDisputeGame(gameProxy).rootClaim();
require(rootClaim == keccak256(abi.encode(rootClaimPreimage)), "Invalid root claim preimage");
Expand Down
Loading