Skip to content

Commit

Permalink
feat(evm): Make dendreth adapter work with finalized header
Browse files Browse the repository at this point in the history
  • Loading branch information
Dimo99 committed Aug 28, 2024
1 parent 7e8179f commit 605b234
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 30 deletions.
56 changes: 32 additions & 24 deletions packages/evm/contracts/adapters/DendrETH/DendrETHAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,20 @@ contract DendrETHAdapter is BlockHashAdapter {
address public immutable SOURCE_YAHO;
uint256 public immutable SOURCE_CHAIN_ID;

error InvalidUpdate();
error BlockHeaderNotAvailable(uint256 slot);
error FinalizedBlockHeaderNotAvailable(bytes32 finalizedHeader);
error InvalidSlot();
error InvalidBlockNumberProof();
error InvalidBlockHashProof();
error InvalidReceiptsRoot();
error ErrorParseReceipt();
error InvalidEventSignature();
error InvalidEventSource();

modifier onlyFinalizedHeaderIsInLightClient(bytes32 finalizedBlockHeader) {
_checkFinalizedHeaderIsInLightClient(finalizedBlockHeader);
_;
}

constructor(address dendrETHAddress, uint256 sourceChainId, address sourceYaho) {
DENDRETH_ADDRESS = dendrETHAddress;
SOURCE_CHAIN_ID = sourceChainId;
Expand All @@ -33,18 +38,17 @@ contract DendrETHAdapter is BlockHashAdapter {
/// @notice Stores the block header for a given block only if it exists
// in the DendrETH Light Client for the SOURCE_CHAIN_ID.
function storeBlockHeader(
uint64 slot,
bytes32 finalizedBlockHeader,
uint256 blockNumber,
bytes32[] calldata blockNumberProof,
bytes32 blockHash,
bytes32[] calldata blockHashProof
) external {
ILightClient lightClient = ILightClient(DENDRETH_ADDRESS);
bytes32 blockHeaderRoot = lightClient.optimisticHeaders(_getIndex(slot, lightClient));
if (!SSZ.verifyBlockNumber(blockNumber, blockNumberProof, blockHeaderRoot)) {
) external onlyFinalizedHeaderIsInLightClient(finalizedBlockHeader) {
if (!SSZ.verifyBlockNumber(blockNumber, blockNumberProof, finalizedBlockHeader)) {
revert InvalidBlockNumberProof();
}
if (!SSZ.verifyBlockHash(blockHash, blockHashProof, blockHeaderRoot)) {

if (!SSZ.verifyBlockHash(blockHash, blockHashProof, finalizedBlockHeader)) {
revert InvalidBlockHashProof();
}

Expand All @@ -54,49 +58,52 @@ contract DendrETHAdapter is BlockHashAdapter {
/// @notice Updates DendrETH Light client and stores the given block
// for the update
function storeBlockHeader(
uint64 slot,
uint256 blockNumber,
bytes32[] calldata blockNumberProof,
bytes32 blockHash,
bytes32[] calldata blockHashProof,
LightClientUpdate calldata update
) external {
ILightClient lightClient = ILightClient(DENDRETH_ADDRESS);
lightClient.light_client_update(update);
if (lightClient.optimisticHeaderSlot() != slot) {
revert InvalidUpdate();
}

bytes32 blockHeaderRoot = lightClient.optimisticHeaderRoot();
if (!SSZ.verifyBlockNumber(blockNumber, blockNumberProof, blockHeaderRoot)) {
lightClient.lightClientUpdate(update);

bytes32 finalizedHeaderRoot = lightClient.finalizedHeaderRoot();

if (!SSZ.verifyBlockNumber(blockNumber, blockNumberProof, finalizedHeaderRoot)) {
revert InvalidBlockNumberProof();
}
if (!SSZ.verifyBlockHash(blockHash, blockHashProof, blockHeaderRoot)) {

if (!SSZ.verifyBlockHash(blockHash, blockHashProof, finalizedHeaderRoot)) {
revert InvalidBlockHashProof();
}

_storeHash(SOURCE_CHAIN_ID, blockNumber, blockHash);
}

function verifyAndStoreDispatchedMessage(
bytes32 srcFinalizedHeader,
uint64 srcSlot,
bytes32[] calldata slotProof,
uint64 txSlot,
bytes32[] memory receiptsRootProof,
bytes32 receiptsRoot,
bytes[] memory receiptProof,
bytes memory txIndexRLPEncoded,
uint256 logIndex
) external {
ILightClient lightClient = ILightClient(DENDRETH_ADDRESS);
bytes32 blockHeaderRoot = lightClient.optimisticHeaders(_getIndex(srcSlot, lightClient));
) external onlyFinalizedHeaderIsInLightClient(srcFinalizedHeader) {
if (!SSZ.verifySlot(srcSlot, slotProof, srcFinalizedHeader)) {
revert InvalidSlot();
}

bool isValidReceiptsRoot = Merkle.verifyReceiptsRoot(
receiptsRootProof,
receiptsRoot,
srcSlot,
txSlot,
blockHeaderRoot
srcFinalizedHeader
);

if (!isValidReceiptsRoot) revert InvalidReceiptsRoot();

Receipt.ParsedReceipt memory parsedReceipt = Receipt.parseReceipt(
Expand All @@ -116,13 +123,15 @@ contract DendrETHAdapter is BlockHashAdapter {
_storeHash(SOURCE_CHAIN_ID, messageId, messageHash);
}

function _getIndex(uint64 slot, ILightClient lightClient) internal view returns (uint256) {
function _checkFinalizedHeaderIsInLightClient(bytes32 finalizedBlockHeader) internal view {
ILightClient lightClient = ILightClient(DENDRETH_ADDRESS);

uint256 currentIndex = lightClient.currentIndex();
uint256 i = currentIndex;
bool found = false;

do {
if (slot == lightClient.optimisticSlots(i)) {
if (finalizedBlockHeader == lightClient.finalizedHeaders(i)) {
found = true;
break;
}
Expand All @@ -133,8 +142,7 @@ contract DendrETHAdapter is BlockHashAdapter {
} while (i != currentIndex);

if (!found) {
revert BlockHeaderNotAvailable(slot);
revert FinalizedBlockHeaderNotAvailable(finalizedBlockHeader);
}
return i;
}
}
20 changes: 14 additions & 6 deletions packages/evm/contracts/adapters/DendrETH/interfaces/IDendrETH.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.20;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

struct LightClientUpdate {
bytes32 attestedHeaderRoot;
Expand All @@ -14,13 +14,21 @@ struct LightClientUpdate {
interface ILightClient {
function currentIndex() external view returns (uint256);

function optimisticHeaders(uint256 index) external view returns (bytes32);

function optimisticHeaderRoot() external view returns (bytes32);

function optimisticHeaderSlot() external view returns (uint256);

function finalizedHeaderRoot() external view returns (bytes32);

function executionStateRoot() external view returns (bytes32);

function optimisticHeaders(uint256 index) external view returns (bytes32);

function optimisticSlots(uint256 index) external view returns (uint256);

function optimisticHeaderSlot() external view returns (uint256);
function finalizedHeaders(uint256 index) external view returns (bytes32);

function executionStateRoots(uint256 index) external view returns (bytes32);

function light_client_update(LightClientUpdate calldata update) external;
function lightClientUpdate(LightClientUpdate calldata update) external payable;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ library SSZ {
uint256 internal constant EXECUTION_PAYLOAD_BLOCK_NUMBER_INDEX = 3222;
uint256 internal constant EXECUTION_PAYLOAD_BLOCK_HASH_INDEX = 3228;

// G-index for the BeaconBlockHeader -> slot
uint256 internal constant SLOT_INDEX = 8;

function toLittleEndian(uint256 _v) internal pure returns (bytes32) {
_v =
((_v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) |
Expand Down Expand Up @@ -74,4 +77,8 @@ library SSZ {
) internal pure returns (bool) {
return isValidMerkleBranch(_blockHash, EXECUTION_PAYLOAD_BLOCK_HASH_INDEX, _blockHashProof, _headerRoot);
}

function verifySlot(uint256 _slot, bytes32[] memory _slotProof, bytes32 _headerRoot) internal pure returns (bool) {
return isValidMerkleBranch(toLittleEndian(_slot), SLOT_INDEX, _slotProof, _headerRoot);
}
}

0 comments on commit 605b234

Please sign in to comment.