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

Zklink da #13

Open
wants to merge 3 commits into
base: zklink
Choose a base branch
from
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
1 change: 1 addition & 0 deletions l1-contracts/.env
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ CONTRACTS_DIAMOND_INIT_ADDR=0x0000000000000000000000000000000000000000
CONTRACTS_DIAMOND_UPGRADE_INIT_ADDR=0x0000000000000000000000000000000000000000
CONTRACTS_DIAMOND_PROXY_ADDR=0x0000000000000000000000000000000000000000
CONTRACTS_VERIFIER_ADDR=0x0000000000000000000000000000000000000000
CONTRACTS_DA_VERIFIER_ADDR=0x0000000000000000000000000000000000000000
CONTRACTS_L1_ERC20_BRIDGE_IMPL_ADDR=0x0000000000000000000000000000000000000000
CONTRACTS_L1_ERC20_BRIDGE_PROXY_ADDR=0x0000000000000000000000000000000000000000
CONTRACTS_L1_ALLOW_LIST_ADDR=0x0000000000000000000000000000000000000000
Expand Down
4 changes: 4 additions & 0 deletions l1-contracts/contracts/dev-contracts/test/DummyExecutor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ contract DummyExecutor is IExecutor {
return true;
}

function isBatchDataAvailable(bytes32) external pure returns (bool) {
return true;
}

function executeBatches(StoredBatchInfo[] calldata _batchesData) external {
require(!shouldRevertOnExecuteBatches, "DummyExecutor: shouldRevertOnExecuteBatches");
uint256 nBatches = _batchesData.length;
Expand Down
5 changes: 4 additions & 1 deletion l1-contracts/contracts/zksync/Storage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pragma solidity 0.8.19;

import {IVerifier} from "./../zksync/interfaces/IVerifier.sol";
import {IDAVerifier} from "./../zksync/interfaces/IDAVerifier.sol";
import {PriorityQueue} from "./libraries/PriorityQueue.sol";
import {IL2Gateway} from "./interfaces/IL2Gateway.sol";

Expand Down Expand Up @@ -138,12 +139,14 @@ struct AppStorage {
mapping(address secondaryChainGateway => mapping(uint256 secondaryChainPriorityOpId => SecondaryChainSyncStatus syncStatus)) secondaryChainSyncStatus;
mapping(bytes32 canonicalTxHash => SecondaryChainOp secondaryChainOp) canonicalTxToSecondaryChainOp;
mapping(bytes32 secondaryChainCanonicalTxHash => bytes32 canonicalTxHash) secondaryToCanonicalTxHash;
/// @dev DA verifier contract. Used to verify commitment for batches
IDAVerifier daVerifier;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[45] __gap;
uint256[44] __gap;
/// @dev Storage of variables needed for deprecated diamond cut facet
uint256[7] __DEPRECATED_diamondCutStorage;
/// @notice Address which will exercise critical changes to the Diamond Proxy (upgrades, freezing & unfreezing)
Expand Down
5 changes: 5 additions & 0 deletions l1-contracts/contracts/zksync/ValidatorTimelock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ contract ValidatorTimelock is IExecutor, Ownable2Step {
return IExecutor(zkSyncContract).isBatchesSynced(_batchesData);
}

/// @dev Make a call to the zkSync contract with the same calldata.
function isBatchDataAvailable(bytes32 _commitment) external view returns (bool) {
return IExecutor(zkSyncContract).isBatchDataAvailable(_commitment);
}

/// @dev Check that batches were committed at least X time ago and
/// make a call to the zkSync contract with the same calldata.
function executeBatches(StoredBatchInfo[] calldata _newBatchesData) external onlyValidator {
Expand Down
69 changes: 69 additions & 0 deletions l1-contracts/contracts/zksync/da/CelestiaDAVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

import "../interfaces/IDAVerifier.sol";

/// @notice A tuple of data root with metadata. Each data root is associated
/// with a Celestia block height.
/// @dev `availableDataRoot` in
/// https://github.com/celestiaorg/celestia-specs/blob/master/src/specs/data_structures.md#header
struct DataRootTuple {
// Celestia block height the data root was included in.
// Genesis block is height = 0.
// First queryable block is height = 1.
uint256 height;
// Data root.
bytes32 dataRoot;
}

/// @notice Merkle Tree Proof structure.
struct BinaryMerkleProof {
// List of side nodes to verify and calculate tree.
bytes32[] sideNodes;
// The key of the leaf to verify.
uint256 key;
// The number of leaves in the tree
uint256 numLeaves;
}

/// @notice Data Availability Oracle interface.
interface IDAOracle {
/// @notice Verify a Data Availability attestation.
/// @param _tupleRootNonce Nonce of the tuple root to prove against.
/// @param _tuple Data root tuple to prove inclusion of.
/// @param _proof Binary Merkle tree proof that `tuple` is in the root at `_tupleRootNonce`.
/// @return `true` is proof is valid, `false` otherwise.
function verifyAttestation(
uint256 _tupleRootNonce,
DataRootTuple memory _tuple,
BinaryMerkleProof memory _proof
) external view returns (bool);
}

/// @author zk.link
/// @notice The celestia verifier that integrate with BlockStream.
/// @dev https://docs.celestia.org/developers/blobstream-contracts
contract CelestiaDAVerifier is IDAVerifier {
IDAOracle public immutable DA_ORACLE;

mapping(bytes32 commitment => bool) public validCommitment;

constructor(IDAOracle _daOracle) {
DA_ORACLE = _daOracle;
}

function isValidCommitment(bytes32 _commitment) external view returns (bool) {
return validCommitment[_commitment];
}

function verifyCommitment(
uint256 _tupleRootNonce,
DataRootTuple calldata _tuple,
BinaryMerkleProof calldata _proof
) external {
require(DA_ORACLE.verifyAttestation(_tupleRootNonce, _tuple, _proof), "Invalid attestation");
// The `dataRoot` of tuple is `commitment` of batch
validCommitment[_tuple.dataRoot] = true;
}
}
10 changes: 10 additions & 0 deletions l1-contracts/contracts/zksync/facets/Admin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {IL2Gateway} from "../interfaces/IL2Gateway.sol";

// While formally the following import is not used, it is needed to inherit documentation from it
import {IBase} from "../interfaces/IBase.sol";
import {IDAVerifier} from "../interfaces/IDAVerifier.sol";

/// @title Admin Contract controls access rights for contract management.
/// @author Matter Labs
Expand All @@ -35,6 +36,15 @@ contract AdminFacet is Base, IAdmin {
}
}

/// @inheritdoc IAdmin
function setDAVerifier(IDAVerifier _daVerifier) external onlyGovernor {
require(address(_daVerifier) != address(0), "gb");
if (s.daVerifier != _daVerifier) {
s.daVerifier = _daVerifier;
emit DAVerifierUpdate(_daVerifier);
}
}

/// @inheritdoc IAdmin
function setPendingGovernor(address _newPendingGovernor) external onlyGovernor {
// Save previous value into the stack to put it into the event later
Expand Down
11 changes: 11 additions & 0 deletions l1-contracts/contracts/zksync/facets/Executor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ contract ExecutorFacet is Base, IExecutor {
bytes32 priorityOperationsHash = _collectOperationsFromPriorityQueue(_storedBatch.numberOfLayer1Txs);
require(priorityOperationsHash == _storedBatch.priorityOperationsHash, "x"); // priority operations hash does not match to expected

// Public data should be available
require(isBatchDataAvailable(_storedBatch.commitment), "x1");

// Save root hash of L2 -> L1 logs tree
s.l2LogsRootHashes[currentBatchNumber] = _storedBatch.l2LogsTreeRoot;
}
Expand All @@ -311,6 +314,14 @@ contract ExecutorFacet is Base, IExecutor {
return true;
}

/// @inheritdoc IExecutor
function isBatchDataAvailable(bytes32 _commitment) public view returns (bool) {
if (address(s.daVerifier) == address(0)) {
return true;
}
return s.daVerifier.isValidCommitment(_commitment);
}

/// @inheritdoc IExecutor
function executeBatches(StoredBatchInfo[] calldata _batchesData) external nonReentrant onlyValidator {
uint256 nBatches = _batchesData.length;
Expand Down
8 changes: 8 additions & 0 deletions l1-contracts/contracts/zksync/interfaces/IAdmin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {IBase} from "./IBase.sol";
import {Diamond} from "../libraries/Diamond.sol";
import {FeeParams} from "../Storage.sol";
import {IL2Gateway} from "./IL2Gateway.sol";
import {IDAVerifier} from "./IDAVerifier.sol";

/// @title The interface of the Admin Contract that controls access rights for contract management.
/// @author Matter Labs
Expand All @@ -20,6 +21,10 @@ interface IAdmin is IBase {
/// @param _active Active flag
function setSecondaryChainGateway(address _gateway, bool _active) external;

/// @notice Update da verifier
/// @param _daVerifier The da verifier
function setDAVerifier(IDAVerifier _daVerifier) external;

/// @notice Starts the transfer of governor rights. Only the current governor can propose a new pending one.
/// @notice New governor can accept governor rights by calling `acceptGovernor` function.
/// @param _newPendingGovernor Address of the new governor
Expand Down Expand Up @@ -72,6 +77,9 @@ interface IAdmin is IBase {
/// @notice SecondaryChain's status changed
event SecondaryChainStatusUpdate(address indexed gateway, bool isActive);

/// @notice DAVerifier updated
event DAVerifierUpdate(IDAVerifier indexed daVerifier);

/// @notice Porter availability status changes
event IsPorterAvailableStatusUpdate(bool isPorterAvailable);

Expand Down
11 changes: 11 additions & 0 deletions l1-contracts/contracts/zksync/interfaces/IDAVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

/// @title The interface of the DAVerifier contract, responsible for the commitment verification of batch.
/// @author zk.link
/// @custom:security-contact security@matterlabs.dev
interface IDAVerifier {
/// @notice Is a valid commitment.
function isValidCommitment(bytes32 commitment) external view returns (bool);
}
4 changes: 4 additions & 0 deletions l1-contracts/contracts/zksync/interfaces/IExecutor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ interface IExecutor is IBase {
/// @param _batchesData Data of the batches to be executed.
function isBatchesSynced(StoredBatchInfo[] calldata _batchesData) external view returns (bool);

/// @notice Check if data is public
/// @param _commitment Commitment of the batch.
function isBatchDataAvailable(bytes32 _commitment) external view returns (bool);

/// @notice The function called by the operator to finalize (execute) batches. It is responsible for:
/// - Processing all pending operations (commpleting priority requests).
/// - Finalizing this batch (i.e. allowing to withdraw funds from the system)
Expand Down
3 changes: 2 additions & 1 deletion l1-contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@
"upgrade-system": "ts-node upgrade-system/index.ts",
"set-gateway": "ts-node scripts/set-gateway.ts",
"set-admin": "ts-node scripts/set-admin.ts",
"deploy-l1-erc20-bridge-imple": "ts-node scripts/deploy-l1-erc20-bridge-impl.ts"
"deploy-l1-erc20-bridge-imple": "ts-node scripts/deploy-l1-erc20-bridge-impl.ts",
"deploy-celestia-da-verifier": "ts-node scripts/deploy-celestia-da-verifier.ts"
},
"dependencies": {
"dotenv": "^16.0.3"
Expand Down
60 changes: 60 additions & 0 deletions l1-contracts/scripts/deploy-celestia-da-verifier.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Command } from "commander";
import { Wallet, ethers } from "ethers";
import { Deployer } from "../src.ts/deploy";
import { formatUnits, parseUnits } from "ethers/lib/utils";
import * as fs from "fs";
import * as path from "path";
import { web3Provider } from "./utils";

const provider = web3Provider();
const testConfigPath = path.join(process.env.ZKSYNC_HOME as string, "etc/test_config/constant");
const ethTestConfig = JSON.parse(fs.readFileSync(`${testConfigPath}/eth.json`, { encoding: "utf-8" }));

async function main() {
const program = new Command();

program.version("0.1.0").name("deploy-celestia-da-verifier");

program
.option("--private-key <private-key>")
.option("--gas-price <gas-price>")
.option("--nonce <nonce>")
.option("--create2-salt <create2-salt>")
.requiredOption("--da-oracle <da-oracle>")
.action(async (cmd) => {
const deployWallet = cmd.privateKey
? new Wallet(cmd.privateKey, provider)
: Wallet.fromMnemonic(
process.env.MNEMONIC ? process.env.MNEMONIC : ethTestConfig.mnemonic,
"m/44'/60'/0'/0/1"
).connect(provider);
console.log(`Using deployer wallet: ${deployWallet.address}`);

const gasPrice = cmd.gasPrice ? parseUnits(cmd.gasPrice, "gwei") : await provider.getGasPrice();
console.log(`Using gas price: ${formatUnits(gasPrice, "gwei")} gwei`);

let nonce = cmd.nonce ? parseInt(cmd.nonce) : await deployWallet.getTransactionCount();
console.log(`Using nonce: ${nonce}`);

const create2Salt = cmd.create2Salt ? cmd.create2Salt : ethers.utils.hexlify(ethers.utils.randomBytes(32));

const daOracle = cmd.daOracle;
console.log(`DA oracle: ${daOracle}`);

const deployer = new Deployer({
deployWallet,
verbose: true,
});

await deployer.deployCelestiaDAVerifier(daOracle, create2Salt, { gasPrice, nonce });
});

await program.parseAsync(process.argv);
}

main()
.then(() => process.exit(0))
.catch((err) => {
console.error("Error:", err);
process.exit(1);
});
2 changes: 2 additions & 0 deletions l1-contracts/scripts/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ export interface DeployedAddresses {
ExecutorFacet: string;
GettersFacet: string;
Verifier: string;
DAVerifier: string;
DiamondInit: string;
DiamondUpgradeInit: string;
DefaultUpgrade: string;
Expand Down Expand Up @@ -205,6 +206,7 @@ export function deployedAddressesFromEnv(): DeployedAddresses {
DefaultUpgrade: getAddressFromEnv("CONTRACTS_DEFAULT_UPGRADE_ADDR"),
DiamondProxy: getAddressFromEnv("CONTRACTS_DIAMOND_PROXY_ADDR"),
Verifier: getAddressFromEnv("CONTRACTS_VERIFIER_ADDR"),
DAVerifier: getAddressFromEnv("CONTRACTS_DA_VERIFIER_ADDR"),
},
Bridges: {
ERC20BridgeImplementation: getAddressFromEnv("CONTRACTS_L1_ERC20_BRIDGE_IMPL_ADDR"),
Expand Down
15 changes: 15 additions & 0 deletions l1-contracts/src.ts/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,21 @@ export class Deployer {
this.addresses.ZkSync.Verifier = contractAddress;
}

public async deployCelestiaDAVerifier(
daOracle: string,
create2Salt: string,
ethTxOptions: ethers.providers.TransactionRequest
) {
ethTxOptions.gasLimit ??= L1_GAS_LIMIT;
const contractAddress = await this.deployViaCreate2("CelestiaDAVerifier", [daOracle], create2Salt, ethTxOptions);

if (this.verbose) {
console.log(`CONTRACTS_DA_VERIFIER_ADDR=${contractAddress}`);
}

this.addresses.ZkSync.DAVerifier = contractAddress;
}

public async deployERC20BridgeImplementation(create2Salt: string, ethTxOptions: ethers.providers.TransactionRequest) {
ethTxOptions.gasLimit ??= L1_GAS_LIMIT;
const contractAddress = await this.deployViaCreate2(
Expand Down
2 changes: 1 addition & 1 deletion l1-contracts/upgrade-system/facets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ async function deployFacetCut(
) {
create2Salt = create2Salt ?? ethers.constants.HashZero;

ethTxOptions["gasLimit"] = 10_000_000;
ethTxOptions["gasLimit"] = 3_000_000;
const [address, txHash] = await deployViaCreate2(wallet, name, [], create2Salt, ethTxOptions, create2Address, true);

console.log(`Deployed ${name} at ${address} with txHash ${txHash}`);
Expand Down