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

Eigenda verifier #38

Draft
wants to merge 15 commits into
base: eigenda
Choose a base branch
from
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@
path = l1-contracts/lib/openzeppelin-contracts
url = https://github.com/Openzeppelin/openzeppelin-contracts
branch = release-v4.9
[submodule "l1-contracts/lib/eigenda"]
path = l1-contracts/lib/eigenda
url = https://github.com/Layr-Labs/eigenda
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {LogProcessingOutput} from "../../state-transition/chain-interfaces/IExec
import {LogProcessingOutput} from "../../state-transition/chain-interfaces/IExecutor.sol";

contract ExecutorProvingTest is ExecutorFacet {

constructor() ExecutorFacet(address(0)) {}

function getBatchProofPublicInput(
bytes32 _prevBatchCommitment,
bytes32 _currentBatchCommitment
Expand Down
2 changes: 2 additions & 0 deletions l1-contracts/contracts/dev-contracts/test/TestExecutor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {ExecutorFacet} from "../../state-transition/chain-deps/facets/Executor.s
pragma solidity 0.8.24;

contract TestExecutor is ExecutorFacet {

constructor() ExecutorFacet(address(0)) {}
/// @dev Since we want to test the blob functionality we want mock the calls to the blobhash opcode.
function _getBlobVersionedHash(uint256 _index) internal view virtual override returns (bytes32 versionedHash) {
(bool success, bytes memory data) = s.blobVersionedHashRetriever.staticcall(abi.encode(_index));
Expand Down
149 changes: 149 additions & 0 deletions l1-contracts/contracts/eigenda/EigenDAVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import {EigenDARollupUtils} from "@eigenda/eigenda-utils/libraries/EigenDARollupUtils.sol";
import {IEigenDAServiceManager} from "@eigenda/eigenda-utils/interfaces/IEigenDAServiceManager.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

Check failure on line 6 in l1-contracts/contracts/eigenda/EigenDAVerifier.sol

View workflow job for this annotation

GitHub Actions / lint

global import of path @openzeppelin/contracts/access/Ownable.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)

Check failure on line 6 in l1-contracts/contracts/eigenda/EigenDAVerifier.sol

View workflow job for this annotation

GitHub Actions / lint

global import of path @openzeppelin/contracts/access/Ownable.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)

Check failure on line 6 in l1-contracts/contracts/eigenda/EigenDAVerifier.sol

View workflow job for this annotation

GitHub Actions / lint

global import of path @openzeppelin/contracts/access/Ownable.sol is not allowed. Specify names to import individually or bind all exports of the module into a name (import "path" as Name)
import {BN254} from "eigenlayer-middleware/libraries/BN254.sol";

contract EigenDAVerifier is Ownable {
struct BlobInfo {
IEigenDAServiceManager.BlobHeader blobHeader;
EigenDARollupUtils.BlobVerificationProof blobVerificationProof;
}

IEigenDAServiceManager public EIGEN_DA_SERVICE_MANAGER;

constructor(address _initialOwner, address _eigenDAServiceManager) {
_transferOwnership(_initialOwner);
EIGEN_DA_SERVICE_MANAGER = IEigenDAServiceManager(_eigenDAServiceManager);
}

function setServiceManager(address _eigenDAServiceManager) external onlyOwner {
EIGEN_DA_SERVICE_MANAGER = IEigenDAServiceManager(_eigenDAServiceManager);
}

function decodeBlobHeader(
bytes calldata blobHeader
) internal pure returns (IEigenDAServiceManager.BlobHeader memory) {
uint32 offset = 0;
// Decode x
uint32 xLen = uint32(bytes4(blobHeader[0:4]));
uint256 x = uint256(bytes32(blobHeader[4:4 + xLen]));
offset += 4 + xLen;
// Decode y
uint32 yLen = uint32(bytes4(blobHeader[offset:4 + offset]));
uint256 y = uint256(bytes32(blobHeader[4 + offset:4 + offset + yLen]));
offset += 4 + yLen;

BN254.G1Point memory commitment = BN254.G1Point(x, y);
// Decode dataLength
uint32 dataLength = uint32(bytes4(blobHeader[offset:offset + 4]));
offset += 4;

// Decode quorumBlobParams
uint32 quorumBlobParamsLen = uint32(bytes4(blobHeader[offset:offset + 4]));
IEigenDAServiceManager.QuorumBlobParam[] memory quorumBlobParams = new IEigenDAServiceManager.QuorumBlobParam[](
quorumBlobParamsLen
);
offset += 4;
for (uint256 i = 0; i < quorumBlobParamsLen; i++) {
quorumBlobParams[i].quorumNumber = uint8(uint32(bytes4(blobHeader[offset:offset + 4])));
quorumBlobParams[i].adversaryThresholdPercentage = uint8(uint32(bytes4(blobHeader[offset + 4:offset + 8])));
quorumBlobParams[i].confirmationThresholdPercentage = uint8(
uint32(bytes4(blobHeader[offset + 8:offset + 12]))
);
quorumBlobParams[i].chunkLength = uint32(bytes4(blobHeader[offset + 12:offset + 16]));
offset += 16;
}
return IEigenDAServiceManager.BlobHeader(commitment, dataLength, quorumBlobParams);
}

function decodeBatchHeader(
bytes calldata batchHeader
) internal pure returns (IEigenDAServiceManager.BatchHeader memory) {
uint32 offset = 0;
// Decode blobHeadersRoot
bytes32 blobHeadersRoot = bytes32(batchHeader[offset:offset + 32]);
offset += 32;
// Decode quorumNumbers
uint32 quorumNumbersLen = uint32(bytes4(batchHeader[offset:offset + 4]));
bytes memory quorumNumbers = batchHeader[offset + 4:offset + 4 + quorumNumbersLen];
offset += 4 + quorumNumbersLen;
// Decode signedStakeForQuorums
uint32 signedStakeForQuorumsLen = uint32(bytes4(batchHeader[offset:offset + 4]));
bytes memory signedStakeForQuorums = batchHeader[offset + 4:offset + 4 + signedStakeForQuorumsLen];
offset += 4 + signedStakeForQuorumsLen;
// Decode referenceBlockNumber
uint32 referenceBlockNumber = uint32(bytes4(batchHeader[offset:offset + 4]));
return
IEigenDAServiceManager.BatchHeader(
blobHeadersRoot,
quorumNumbers,
signedStakeForQuorums,
referenceBlockNumber
);
}

function decodeBatchMetadata(
bytes calldata batchMetadata
) internal pure returns (IEigenDAServiceManager.BatchMetadata memory) {
uint32 offset = 0;
// Decode batchHeader
uint32 batchHeaderLen = uint32(bytes4(batchMetadata[offset:offset + 4]));
IEigenDAServiceManager.BatchHeader memory batchHeader = decodeBatchHeader(
batchMetadata[offset + 4:offset + 4 + batchHeaderLen]
);
offset += 4 + batchHeaderLen;
// Decode signatoryRecordHash
bytes32 signatoryRecordHash = bytes32(batchMetadata[offset:offset + 32]);
offset += 32;
// Decode confirmationBlockNumber
uint32 confirmationBlockNumber = uint32(bytes4(batchMetadata[offset:offset + 4]));
return IEigenDAServiceManager.BatchMetadata(batchHeader, signatoryRecordHash, confirmationBlockNumber);
}

function decodeBlobVerificationProof(
bytes calldata blobVerificationProof
) internal pure returns (EigenDARollupUtils.BlobVerificationProof memory) {
// Decode batchId
uint32 batchId = uint32(bytes4(blobVerificationProof[:4]));
// Decode blobIndex
uint32 blobIndex = uint32(bytes4(blobVerificationProof[4:8]));
// Decode batchMetadata
uint32 batchMetadataLen = uint32(bytes4(blobVerificationProof[8:12]));
IEigenDAServiceManager.BatchMetadata memory batchMetadata = decodeBatchMetadata(
blobVerificationProof[12:batchMetadataLen]
);
uint32 offset = 12 + batchMetadataLen;
// Decode inclusionProof
uint32 inclusionProofLen = uint32(bytes4(blobVerificationProof[offset:offset + 4]));
bytes memory inclusionProof = blobVerificationProof[offset + 4:offset + 4 + inclusionProofLen];
offset += 4 + inclusionProofLen;
// Decode quorumIndexes
uint32 quorumIndexesLen = uint32(bytes4(blobVerificationProof[offset:offset + 4]));
bytes memory quorumIndexes = blobVerificationProof[offset + 4:offset + 4 + quorumIndexesLen];

return
EigenDARollupUtils.BlobVerificationProof(batchId, blobIndex, batchMetadata, inclusionProof, quorumIndexes);

Check failure on line 128 in l1-contracts/contracts/eigenda/EigenDAVerifier.sol

View workflow job for this annotation

GitHub Actions / lint

Named parameters missing. MIN unnamed argumenst is 4

Check failure on line 128 in l1-contracts/contracts/eigenda/EigenDAVerifier.sol

View workflow job for this annotation

GitHub Actions / lint

Named parameters missing. MIN unnamed argumenst is 4

Check failure on line 128 in l1-contracts/contracts/eigenda/EigenDAVerifier.sol

View workflow job for this annotation

GitHub Actions / lint

Named parameters missing. MIN unnamed argumenst is 4
}

function decodeBlobInfo(bytes calldata blobInfo) internal pure returns (BlobInfo memory) {
uint32 blobHeaderLen = uint32(bytes4(blobInfo[:4]));
IEigenDAServiceManager.BlobHeader memory blobHeader = decodeBlobHeader(blobInfo[4:blobHeaderLen]);
EigenDARollupUtils.BlobVerificationProof memory blobVerificationProof = decodeBlobVerificationProof(
blobInfo[blobHeaderLen:]
);
return BlobInfo(blobHeader, blobVerificationProof);
}

function verifyBlob(bytes calldata blobInfo) external view {
BlobInfo memory blob = decodeBlobInfo(blobInfo);
this._verifyBlob(blob);
}

function _verifyBlob(BlobInfo calldata blobInfo) external view {
require(address(EIGEN_DA_SERVICE_MANAGER) != address(0), "EigenDAVerifier: EIGEN_DA_SERVICE_MANAGER not set");
EigenDARollupUtils.verifyBlob(blobInfo.blobHeader, EIGEN_DA_SERVICE_MANAGER, blobInfo.blobVerificationProof);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
// While formally the following import is not used, it is needed to inherit documentation from it
import {IZkSyncHyperchainBase} from "../../chain-interfaces/IZkSyncHyperchainBase.sol";

import {EigenDAVerifier} from "../../../eigenda/EigenDAVerifier.sol";

/// @title zkSync hyperchain Executor contract capable of processing events emitted in the zkSync hyperchain protocol.
/// @author Matter Labs
/// @custom:security-contact [email protected]
Expand All @@ -25,6 +27,12 @@
/// @inheritdoc IZkSyncHyperchainBase
string public constant override getName = "ExecutorFacet";

EigenDAVerifier immutable public eigenDAVerifier;

Check warning on line 30 in l1-contracts/contracts/state-transition/chain-deps/facets/Executor.sol

View workflow job for this annotation

GitHub Actions / lint

Immutable variables name are set to be in capitalized SNAKE_CASE

Check warning on line 30 in l1-contracts/contracts/state-transition/chain-deps/facets/Executor.sol

View workflow job for this annotation

GitHub Actions / lint

Immutable variables name are set to be in capitalized SNAKE_CASE

Check warning on line 30 in l1-contracts/contracts/state-transition/chain-deps/facets/Executor.sol

View workflow job for this annotation

GitHub Actions / lint

Immutable variables name are set to be in capitalized SNAKE_CASE

constructor(address _eigenDAVerifier) {
eigenDAVerifier = EigenDAVerifier(_eigenDAVerifier);
}

/// @dev Process one batch commit using the previous batch StoredBatchInfo
/// @dev returns new batch StoredBatchInfo
/// @notice Does not change storage
Expand All @@ -50,9 +58,9 @@

bytes32[] memory blobCommitments = new bytes32[](MAX_NUMBER_OF_BLOBS);
if (pricingMode == PubdataPricingMode.Validium) {

// In this scenario, pubdataCommitments has the data of the commitment and the pubdataSource, so the len should be higher or equal than 1
require(_newBatch.pubdataCommitments.length >= 1, "EF: v0l");
eigenDAVerifier.verifyBlob(_newBatch.pubdataCommitments[1:]);
for (uint8 i = uint8(SystemLogKey.BLOB_ONE_HASH_KEY); i <= uint8(SystemLogKey.BLOB_SIX_HASH_KEY); i++) {
logOutput.blobHashes[i - uint8(SystemLogKey.BLOB_ONE_HASH_KEY)] = bytes32(0);
}
Expand Down
18 changes: 17 additions & 1 deletion l1-contracts/deploy-scripts/DeployL1.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-de
import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol";
import {L1ERC20Bridge} from "contracts/bridge/L1ERC20Bridge.sol";
import {DiamondProxy} from "contracts/state-transition/chain-deps/DiamondProxy.sol";
import {EigenDAVerifier} from "contracts/eigenda/EigenDAVerifier.sol";

contract DeployL1Script is Script {
using stdToml for string;
Expand All @@ -50,6 +51,7 @@ contract DeployL1Script is Script {
address blobVersionedHashRetriever;
address validatorTimelock;
address create2Factory;
address eigendaVerifier;
}

struct BridgehubDeployedAddresses {
Expand Down Expand Up @@ -113,6 +115,7 @@ contract DeployL1Script is Script {
bytes diamondCutData;
bytes32 bootloaderHash;
bytes32 defaultAAHash;
address eigenServiceManager;
}

struct TokensConfig {
Expand All @@ -135,6 +138,7 @@ contract DeployL1Script is Script {
deployDefaultUpgrade();
deployGenesisUpgrade();
deployValidatorTimelock();
deployEigenDAVerifier();

deployGovernance();
deployChainAdmin();
Expand Down Expand Up @@ -209,6 +213,7 @@ contract DeployL1Script is Script {
config.contracts.bootloaderHash = toml.readBytes32("$.contracts.bootloader_hash");

config.tokens.tokenWethAddress = toml.readAddress("$.tokens.token_weth_address");
config.contracts.eigenServiceManager = toml.readAddress("$.contracts.eigen_service_manager");
}

function instantiateCreate2Factory() internal {
Expand Down Expand Up @@ -280,6 +285,16 @@ contract DeployL1Script is Script {
addresses.validatorTimelock = contractAddress;
}

function deployEigenDAVerifier() internal {
bytes memory bytecode = abi.encodePacked(
type(EigenDAVerifier).creationCode,
abi.encode(config.deployerAddress, config.contracts.eigenServiceManager)
);
address contractAddress = deployViaCreate2(bytecode);
console.log("EigenDAVerifier deployed at:", contractAddress);
addresses.eigendaVerifier = contractAddress;
}

function deployGovernance() internal {
bytes memory bytecode = abi.encodePacked(
type(Governance).creationCode,
Expand Down Expand Up @@ -347,7 +362,7 @@ contract DeployL1Script is Script {
}

function deployStateTransitionDiamondFacets() internal {
address executorFacet = deployViaCreate2(type(ExecutorFacet).creationCode);
address executorFacet = deployViaCreate2(abi.encodePacked(type(ExecutorFacet).creationCode,abi.encode(addresses.eigendaVerifier)));
console.log("ExecutorFacet deployed at:", executorFacet);
addresses.stateTransition.executorFacet = executorFacet;

Expand Down Expand Up @@ -706,6 +721,7 @@ contract DeployL1Script is Script {
);
vm.serializeAddress("deployed_addresses", "validator_timelock_addr", addresses.validatorTimelock);
vm.serializeAddress("deployed_addresses", "chain_admin", addresses.chainAdmin);
vm.serializeAddress("deployed_addresses", "eigenda_verifier_addr", addresses.eigendaVerifier);
vm.serializeString("deployed_addresses", "bridgehub", bridgehub);
vm.serializeString("deployed_addresses", "state_transition", stateTransition);
string memory deployedAddresses = vm.serializeString("deployed_addresses", "bridges", bridges);
Expand Down
6 changes: 5 additions & 1 deletion l1-contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ libs = ['node_modules', 'lib']
remappings = [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"l2-contracts/=../l2-contracts/contracts/"
"l2-contracts/=../l2-contracts/contracts/",
"@eigenda/eigenda-utils/libraries/=lib/eigenda/contracts/src/libraries/",
"@eigenda/eigenda-utils/interfaces/=lib/eigenda/contracts/src/interfaces/",
"eigenlayer-middleware/=lib/eigenda/contracts/lib/eigenlayer-middleware/src/",
"eigenlayer-core/=lib/eigenda/contracts/lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/"
]
allow_paths = ["../l2-contracts/contracts"]
fs_permissions = [
Expand Down
1 change: 1 addition & 0 deletions l1-contracts/lib/eigenda
Submodule eigenda added at e30979
Loading