diff --git a/da-contracts/contracts/ValidiumL1DAValidator.sol b/l1-contracts/contracts/state-transition/data-availability/ValidiumL1DAValidator.sol similarity index 75% rename from da-contracts/contracts/ValidiumL1DAValidator.sol rename to l1-contracts/contracts/state-transition/data-availability/ValidiumL1DAValidator.sol index e163f8073..15825bbdd 100644 --- a/da-contracts/contracts/ValidiumL1DAValidator.sol +++ b/l1-contracts/contracts/state-transition/data-availability/ValidiumL1DAValidator.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.24; // solhint-disable gas-custom-errors, reason-string -import {IL1DAValidator, L1DAValidatorOutput} from "./IL1DAValidator.sol"; +import {IL1DAValidator, L1DAValidatorOutput} from "../chain-interfaces/IL1DAValidator.sol"; contract ValidiumL1DAValidator is IL1DAValidator { function checkDA( @@ -12,7 +12,7 @@ contract ValidiumL1DAValidator is IL1DAValidator { uint256, // _batchNumber bytes32, // _l2DAValidatorOutputHash bytes calldata _operatorDAInput, - uint256 // maxBlobsSupported + uint256 maxBlobsSupported ) external override returns (L1DAValidatorOutput memory output) { // For Validiums, we expect the operator to just provide the data for us. // We don't need to do any checks with regard to the l2DAValidatorOutputHash. @@ -22,5 +22,8 @@ contract ValidiumL1DAValidator is IL1DAValidator { // The rest of the fields that relate to blobs are empty. output.stateDiffHash = stateDiffHash; + + output.blobsLinearHashes = new bytes32[](maxBlobsSupported); + output.blobsOpeningCommitments = new bytes32[](maxBlobsSupported); } } diff --git a/l1-contracts/deploy-scripts/DeployL1.s.sol b/l1-contracts/deploy-scripts/DeployL1.s.sol index 0f86201dd..1112d917e 100644 --- a/l1-contracts/deploy-scripts/DeployL1.s.sol +++ b/l1-contracts/deploy-scripts/DeployL1.s.sol @@ -8,7 +8,7 @@ import {stdToml} from "forge-std/StdToml.sol"; import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol"; -import {StateTransitionDeployedAddresses, Utils, DAContractBytecodes, L2_BRIDGEHUB_ADDRESS, L2_ASSET_ROUTER_ADDRESS, L2_NATIVE_TOKEN_VAULT_ADDRESS, L2_MESSAGE_ROOT_ADDRESS} from "./Utils.sol"; +import {StateTransitionDeployedAddresses, Utils, L2_BRIDGEHUB_ADDRESS, L2_ASSET_ROUTER_ADDRESS, L2_NATIVE_TOKEN_VAULT_ADDRESS, L2_MESSAGE_ROOT_ADDRESS} from "./Utils.sol"; import {Multicall3} from "contracts/dev-contracts/Multicall3.sol"; import {Verifier} from "contracts/state-transition/Verifier.sol"; import {TestnetVerifier} from "contracts/state-transition/TestnetVerifier.sol"; @@ -54,6 +54,7 @@ import {ICTMDeploymentTracker} from "contracts/bridgehub/ICTMDeploymentTracker.s import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; import {IAssetRouterBase} from "contracts/bridge/asset-router/IAssetRouterBase.sol"; import {L2ContractsBytecodesLib} from "./L2ContractsBytecodesLib.sol"; +import {ValidiumL1DAValidator} from "contracts/state-transition/data-availability/ValidiumL1DAValidator.sol"; struct FixedForceDeploymentsData { uint256 l1ChainId; @@ -380,13 +381,11 @@ contract DeployL1Script is Script { } function deployDAValidators() internal { - DAContractBytecodes memory daBytecodes = Utils.readDAContractBytecodes(); - - address contractAddress = deployViaCreate2(daBytecodes.rollupL1DAValidator); + address contractAddress = deployViaCreate2(Utils.readRollupDAValidatorBytecode()); console.log("L1RollupDAValidator deployed at:", contractAddress); addresses.daAddresses.l1RollupDAValidator = contractAddress; - contractAddress = deployViaCreate2(daBytecodes.validiumL1DAValidator); + contractAddress = deployViaCreate2(type(ValidiumL1DAValidator).creationCode); console.log("L1ValidiumDAValidator deployed at:", contractAddress); addresses.daAddresses.l1ValidiumDAValidator = contractAddress; } @@ -1058,7 +1057,7 @@ contract DeployL1Script is Script { vm.serializeAddress( "deployed_addresses", "validium_l1_da_validator_addr", - addresses.daAddresses.l1RollupDAValidator + addresses.daAddresses.l1ValidiumDAValidator ); string memory deployedAddresses = vm.serializeAddress( diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index ba5eeb9fe..5c4fc3f05 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -95,6 +95,7 @@ contract DeployL2Script is Script { string memory root = vm.projectRoot(); string memory path = string.concat(root, "/script-config/config-deploy-l2-contracts.toml"); string memory toml = vm.readFile(path); + config.validiumMode = toml.readBool("$.validium_mode"); config.bridgehubAddress = toml.readAddress("$.bridgehub"); config.governance = toml.readAddress("$.governance"); config.l1SharedBridgeProxy = toml.readAddress("$.l1_shared_bridge"); diff --git a/l1-contracts/deploy-scripts/GatewayCTMFromL1.s.sol b/l1-contracts/deploy-scripts/GatewayCTMFromL1.s.sol index 66fb96ed9..6f17c234c 100644 --- a/l1-contracts/deploy-scripts/GatewayCTMFromL1.s.sol +++ b/l1-contracts/deploy-scripts/GatewayCTMFromL1.s.sol @@ -83,7 +83,6 @@ contract GatewayCTMFromL1 is Script { address multicall3; bytes diamondCutData; address relayedSLDAValidator; - // TODO(EVM-747): for now zero, since the contract structure is not adapted to it address validiumDAValidator; } @@ -229,6 +228,11 @@ contract GatewayCTMFromL1 is Script { L2ContractsBytecodesLib.readRelayedSLDAValidatorBytecode(), hex"" ); + + output.validiumDAValidator = _deployInternal( + L2ContractsBytecodesLib.readValidiumL1DAValidatorBytecode(), + hex"" + ); } function _deployInternal(bytes memory bytecode, bytes memory constructorargs) internal returns (address) { @@ -273,9 +277,11 @@ contract GatewayCTMFromL1 is Script { function deployGatewayVerifier() internal returns (address verifier) { if (config.testnetVerifier) { - verifier = address(_deployInternal(L2ContractsBytecodesLib.readTestnetVerifierBytecode(), hex"")); + verifier = address( + _deployInternal(L2ContractsBytecodesLib.readL2TestnetVerifierBytecode(), abi.encode(config.l1ChainId)) + ); } else { - verifier = address(_deployInternal(L2ContractsBytecodesLib.readVerifierBytecode(), hex"")); + verifier = address(_deployInternal(L2ContractsBytecodesLib.readL2VerifierBytecode(), hex"")); } console.log("Verifier deployed at", verifier); diff --git a/l1-contracts/deploy-scripts/L2ContractsBytecodesLib.sol b/l1-contracts/deploy-scripts/L2ContractsBytecodesLib.sol index 5249d28d0..b9481c578 100644 --- a/l1-contracts/deploy-scripts/L2ContractsBytecodesLib.sol +++ b/l1-contracts/deploy-scripts/L2ContractsBytecodesLib.sol @@ -148,7 +148,6 @@ library L2ContractsBytecodesLib { ); } - // FIXME: replace it with L2 verifier /// @notice Reads the bytecode of the Verifier contract. /// @return The bytecode of the Verifier contract. function readVerifierBytecode() internal view returns (bytes memory) { @@ -158,6 +157,12 @@ library L2ContractsBytecodesLib { ); } + /// @notice Reads the bytecode of the L2 Verifier contract. + /// @return The bytecode of the Verifier contract. + function readL2VerifierBytecode() internal view returns (bytes memory) { + return Utils.readHardhatBytecode("/../l2-contracts/artifacts-zk/contracts/verifier/Verifier.sol/Verifier.json"); + } + /// @notice Reads the bytecode of the Verifier contract. /// @return The bytecode of the Verifier contract. function readConsensusRegistryBytecode() internal view returns (bytes memory) { @@ -169,10 +174,10 @@ library L2ContractsBytecodesLib { /// @notice Reads the bytecode of the TestnetVerifier contract. /// @return The bytecode of the TestnetVerifier contract. - function readTestnetVerifierBytecode() internal view returns (bytes memory) { + function readL2TestnetVerifierBytecode() internal view returns (bytes memory) { return Utils.readHardhatBytecode( - "/../l1-contracts/artifacts-zk/contracts/state-transition/TestnetVerifier.sol/TestnetVerifier.json" + "/../l2-contracts/artifacts-zk/contracts/verifier/TestnetVerifier.sol/TestnetVerifier.json" ); } @@ -239,6 +244,13 @@ library L2ContractsBytecodesLib { ); } + function readValidiumL1DAValidatorBytecode() internal view returns (bytes memory) { + return + Utils.readHardhatBytecode( + "/../l1-contracts/artifacts-zk/contracts/state-transition/data-availability/ValidiumL1DAValidator.sol/ValidiumL1DAValidator.json" + ); + } + /// @notice Reads the bytecode of the L2SharedBridgeLegacy contract. /// @return The bytecode of the L2SharedBridgeLegacy contract. function readL2LegacySharedBridgeBytecode() internal view returns (bytes memory) { diff --git a/l1-contracts/deploy-scripts/Utils.sol b/l1-contracts/deploy-scripts/Utils.sol index 37a871571..b2d71bab7 100644 --- a/l1-contracts/deploy-scripts/Utils.sol +++ b/l1-contracts/deploy-scripts/Utils.sol @@ -28,11 +28,6 @@ address constant L2_ASSET_ROUTER_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x03) address constant L2_NATIVE_TOKEN_VAULT_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x04); address constant L2_MESSAGE_ROOT_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x05); -struct DAContractBytecodes { - bytes rollupL1DAValidator; - bytes validiumL1DAValidator; -} - // solhint-disable-next-line gas-struct-packing struct StateTransitionDeployedAddresses { address chainTypeManagerProxy; @@ -783,15 +778,8 @@ library Utils { vm.stopBroadcast(); } - function readDAContractBytecodes() internal view returns (DAContractBytecodes memory bytecodes) { - bytecodes = DAContractBytecodes({ - rollupL1DAValidator: readFoundryBytecode( - "/../da-contracts/out/RollupL1DAValidator.sol/RollupL1DAValidator.json" - ), - validiumL1DAValidator: readFoundryBytecode( - "/../da-contracts/out/ValidiumL1DAValidator.sol/ValidiumL1DAValidator.json" - ) - }); + function readRollupDAValidatorBytecode() internal view returns (bytes memory bytecode) { + bytecode = readFoundryBytecode("/../da-contracts/out/RollupL1DAValidator.sol/RollupL1DAValidator.json"); } // add this to be excluded from coverage report diff --git a/l1-contracts/src.ts/deploy.ts b/l1-contracts/src.ts/deploy.ts index 3eef1cf9f..b798378aa 100644 --- a/l1-contracts/src.ts/deploy.ts +++ b/l1-contracts/src.ts/deploy.ts @@ -78,7 +78,6 @@ import { ICTMDeploymentTrackerFactory } from "../typechain/ICTMDeploymentTracker import { TestnetERC20TokenFactory } from "../typechain/TestnetERC20TokenFactory"; import { RollupL1DAValidatorFactory } from "../../da-contracts/typechain/RollupL1DAValidatorFactory"; -import { ValidiumL1DAValidatorFactory } from "../../da-contracts/typechain/ValidiumL1DAValidatorFactory"; let L2_BOOTLOADER_BYTECODE_HASH: string; let L2_DEFAULT_ACCOUNT_BYTECODE_HASH: string; @@ -295,8 +294,8 @@ export class Deployer { let factory; if (contractName == "RollupL1DAValidator") { factory = new RollupL1DAValidatorFactory(this.deployWallet); - } else if (contractName == "ValidiumL1DAValidator") { - factory = new ValidiumL1DAValidatorFactory(this.deployWallet); + } else { + throw new Error(`Unknown DA contract name ${contractName}`); } return factory.getDeployTransaction().data; } @@ -1755,14 +1754,12 @@ export class Deployer { if (this.verbose) { console.log(`CONTRACTS_L1_ROLLUP_DA_VALIDATOR=${rollupDAValidatorAddress}`); } - const validiumValidatorBytecode = await this.loadFromDAFolder("ValidiumL1DAValidator"); const validiumDAValidatorAddress = await this.deployViaCreate2( "ValidiumL1DAValidator", [], create2Salt, ethTxOptions, - undefined, - validiumValidatorBytecode + undefined ); if (this.verbose) { diff --git a/l2-contracts/contracts/verifier/TestnetVerifier.sol b/l2-contracts/contracts/verifier/TestnetVerifier.sol new file mode 100644 index 000000000..808fa70db --- /dev/null +++ b/l2-contracts/contracts/verifier/TestnetVerifier.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import {Verifier} from "./Verifier.sol"; +import {IVerifier} from "./chain-interfaces/IVerifier.sol"; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +/// @notice Modified version of the main verifier contract for the testnet environment +/// @dev This contract is used to skip the zkp verification for the testnet environment. +/// If the proof is not empty, it will verify it using the main verifier contract, +/// otherwise, it will skip the verification. +contract TestnetVerifier is Verifier { + constructor(uint256 _l1ChainId) { + assert(_l1ChainId != 1); + } + + /// @dev Verifies a zk-SNARK proof, skipping the verification if the proof is empty. + /// @inheritdoc IVerifier + function verify(uint256[] calldata _publicInputs, uint256[] calldata _proof) public view override returns (bool) { + // We allow skipping the zkp verification for the test(net) environment + // If the proof is not empty, verify it, otherwise, skip the verification + if (_proof.length == 0) { + return true; + } + + return super.verify(_publicInputs, _proof); + } +}