Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[VEN-2083]: Syncing of Votes #97

Draft
wants to merge 15 commits into
base: develop
Choose a base branch
from
Draft
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
147 changes: 147 additions & 0 deletions contracts/Cross-chain/Voting/BlockHashDispatcher.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import { OApp, MessagingFee, Origin } from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol";
import { ensureNonzeroAddress } from "@venusprotocol/solidity-utilities/contracts/validators.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

/**
* @title BlockHashDispatcher
* @notice A contract for dispatching block hashes to a proposal chain and managing messaging between chains.
* @dev Inherits functionality from OApp, Pausable, and Ownable. Implements LayerZero messaging and access control.
*/
contract BlockHashDispatcher is Pausable, OApp {
/// @notice Messaging parameters structure
struct MessagingParams {
uint32 dstEid; // Destination chain ID
bytes32 receiver; // Receiver address on the destination chain
bytes payload; // Encoded data payload
bytes options; // Messaging options
bool payInLzToken; // Indicates payment in LayerZero tokens
}

/**
* @notice ID of the proposal chain (e.g., BNB Chain) where block hashes will be sent
*/
uint32 public BSC_CHAIN_ID;

/**
* @notice Emitted when a block hash is dispatched to the proposal chain
* @param pId Proposal Id
* @param blockNum Block number
* @param payload Encoded data payload
*/
event HashDispatched(uint256 indexed pId, uint256 indexed blockNum, bytes payload);

/// @notice Error thrown when an invalid chain ID is provided
error InvalidChainEid(uint32 eid);

/**
* @notice Constructor to initialize the contract
* @param endpoint_ Address of the LayerZero endpoint
* @param bnbChainEId_ Chain ID for the BNB Chain
* @param owner_ Address of the contract owner
*/
constructor(address endpoint_, uint16 bnbChainEId_, address owner_) OApp(endpoint_, owner_) Ownable() {
ensureNonzeroAddress(address(endpoint_));
if (bnbChainEId_ == 0) {
revert InvalidChainEid(bnbChainEId_);
}
BSC_CHAIN_ID = bnbChainEId_;
}

/**
* @notice Pauses the contract
* @dev Callable only by the owner
*/
function pause() external onlyOwner {
_pause();
}

/**
* @notice Unpauses the contract
* @dev Callable only by the owner
*/
function unpause() external onlyOwner {
_unpause();
}

/**
* @notice Generates a payload containing a block hash
* @param pId Unique identifier for the proposal
* @param blockNumber Block number for which the hash is generated
* @return payload Encoded payload containing the proposal ID, block number, and block hash
*/
function getPayload(uint256 pId, uint256 blockNumber) public view returns (bytes memory payload) {
bytes32 blockHash_ = blockhash(blockNumber);
payload = abi.encode(pId, blockNumber, blockHash_);
}

/**
* @notice Quotes the messaging fee for dispatching a block hash
* @param pId Proposal ID
* @param blockNumber Block number
* @param options Messaging options
* @param payInLzToken Payment method (native token or LayerZero token)
* @return fee The messaging fee details
*/
function quote(
uint256 pId,
uint256 blockNumber,
bytes memory options,
bool payInLzToken
) public view returns (MessagingFee memory fee) {
return _quote(BSC_CHAIN_ID, getPayload(pId, blockNumber), options, payInLzToken);
}

/**
* @notice Dispatches a block hash along with its proposal ID and block number to the proposal chain
* @param pId Proposal ID
* @param blockNumber Block number
* @param zroTokens Address for ZRO token payment
* @param options Custom gas options for execution on the destination chain
*/
function dispatchHash(
uint256 pId,
uint256 blockNumber,
uint256 zroTokens,
bytes calldata options
) external payable whenNotPaused {
bytes memory payload = getPayload(pId, blockNumber);

_lzSend(
BSC_CHAIN_ID,
payload,
options,
// Fee in native gas and ZRO token.
MessagingFee(msg.value, zroTokens),
// Refund address in case of failed source message.
payable(msg.sender)
);
}

/**
* @notice Internal function to handle incoming LayerZero messages
*/
function _lzReceive(
Origin calldata _origin,
bytes32 _guid,
bytes calldata payload,
address _executor,
bytes calldata _extraData
) internal override {}

/**
* @notice Retrieves the block hash for a given block number and proposal ID
* @param blockNumber The block number
* @param pId The proposal ID
* @return pId The proposal ID
* @return blockNumber The block number
* @return blockHash_ The block hash
*/
function getHash(uint256 blockNumber, uint256 pId) external view whenNotPaused returns (uint256, uint256, bytes32) {
bytes32 blockHash_ = blockhash(blockNumber);
return (pId, blockNumber, blockHash_);
}
}
94 changes: 94 additions & 0 deletions contracts/Cross-chain/Voting/DataWarehouse.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import { IDataWarehouse } from "../interfaces/IDataWarehouse.sol";
import { StateProofVerifier } from "../libs/StateProofVerifier.sol";
import { RLPReader } from "../libs/RLPReader.sol";

/**
* @title DataWarehouse
* @author BGD Labs
* @notice This contract stores account state roots and allows proving against them
*/
contract DataWarehouse is IDataWarehouse {
using RLPReader for bytes;
using RLPReader for RLPReader.RLPItem;

uint256 public delay;
// account address => (block hash => Account state root hash)
mapping(address => mapping(bytes32 => bytes32)) internal _storageRoots;

// account address => (block hash => (slot => slot value))
mapping(address => mapping(bytes32 => mapping(bytes32 => uint256))) internal _slotsRegistered;

/// @inheritdoc IDataWarehouse
function getStorageRoots(address account, bytes32 blockHash) external view returns (bytes32) {
return _storageRoots[account][blockHash];
}

/// @inheritdoc IDataWarehouse
function getRegisteredSlot(bytes32 blockHash, address account, bytes32 slot) external view returns (uint256) {
return _slotsRegistered[account][blockHash][slot];
}

/// @inheritdoc IDataWarehouse
function processStorageRoot(
address account,
bytes32 blockHash,
bytes memory blockHeaderRLP,
bytes memory accountStateProofRLP
) external returns (StateProofVerifier.BlockHeader memory) {
StateProofVerifier.BlockHeader memory decodedHeader = StateProofVerifier.verifyBlockHeader(
blockHeaderRLP,
blockHash
);

// The path for an account in the state trie is the hash of its address
bytes32 proofPath = keccak256(abi.encodePacked(account));
StateProofVerifier.Account memory accountData = StateProofVerifier.extractAccountFromProof(
proofPath,
decodedHeader.stateRootHash,
accountStateProofRLP.toRlpItem().toList()
);

_storageRoots[account][blockHash] = accountData.storageRoot;

emit StorageRootProcessed(msg.sender, account, blockHash);

return decodedHeader;
}

/// @inheritdoc IDataWarehouse
function getStorage(
address account,
bytes32 blockHash,
bytes32 slot,
bytes memory storageProof
) public view returns (StateProofVerifier.SlotValue memory) {
bytes32 root = _storageRoots[account][blockHash];
require(root != bytes32(0), "DataWarehouse: storage root not processed");
// The path for a storage value is the hash of its slot
bytes32 proofPath = keccak256(abi.encodePacked(slot));
StateProofVerifier.SlotValue memory slotData = StateProofVerifier.extractSlotValueFromProof(
proofPath,
root,
storageProof.toRlpItem().toList()
);

return slotData;
}

/// @inheritdoc IDataWarehouse
function processStorageSlot(
address account,
bytes32 blockHash,
bytes32 slot,
bytes calldata storageProof
) external {
StateProofVerifier.SlotValue memory storageSlot = getStorage(account, blockHash, slot, storageProof);

_slotsRegistered[account][blockHash][slot] = storageSlot.value;

emit StorageSlotProcessed(msg.sender, account, blockHash, slot, storageSlot.value);
}
}
Loading