diff --git a/contracts/v2/PolygonRollupManager.sol b/contracts/v2/PolygonRollupManager.sol index 85d02492f..0e2b6087b 100644 --- a/contracts/v2/PolygonRollupManager.sol +++ b/contracts/v2/PolygonRollupManager.sol @@ -866,6 +866,10 @@ contract PolygonRollupManager is RollupData storage rollup = _rollupIDToRollupData[rollupID]; + if (rollup.rollupVerifierType != VerifierType.StateTransition) { + revert OnlyStateTransitionChains(); + } + // Update total sequence parameters totalSequencedBatches += newSequencedBatches; @@ -1033,14 +1037,14 @@ contract PolygonRollupManager is /** * @notice Allows a trusted aggregator to verify pessimistic proof * @param rollupID Rollup identifier - * @param selectedGlobalExitRoot Selected global exit root to proof imported bridges + * @param l1InfoTreeLeafCount Count of the L1InfoTree leaf that will be used to verify imported bridge exits * @param newLocalExitRoot New local exit root * @param newPessimisticRoot New pessimistic information, Hash(localBalanceTreeRoot, nullifierTreeRoot) * @param proof SP1 proof (Plonk) */ function verifyPessimisticTrustedAggregator( uint32 rollupID, - bytes32 selectedGlobalExitRoot, + uint32 l1InfoTreeLeafCount, bytes32 newLocalExitRoot, bytes32 newPessimisticRoot, bytes calldata proof @@ -1052,17 +1056,19 @@ contract PolygonRollupManager is revert OnlyChainsWithPessimisticProofs(); } - // Check selected global exit root exist - if ( - globalExitRootManager.globalExitRootMap(selectedGlobalExitRoot) == 0 - ) { - revert GlobalExitRootNotExist(); + // Check l1InfoTreeLeafCount has a valid l1InfoTreeRoot + bytes32 l1InfoRoot = globalExitRootManager.l1InfoRootMap( + l1InfoTreeLeafCount + ); + + if (l1InfoRoot == bytes32(0)) { + revert L1InfoTreeLeafCountInvalid(); } bytes memory inputPessimisticBytes = _getInputPessimisticBytes( rollupID, rollup, - selectedGlobalExitRoot, + l1InfoRoot, newLocalExitRoot, newPessimisticRoot ); @@ -1292,13 +1298,13 @@ contract PolygonRollupManager is /** * @notice Function to calculate the pessimistic input bytes * @param rollupID Rollup id used to calculate the input snark bytes - * @param selectedGlobalExitRoot Selected global exit root to proof imported bridges + * @param l1InfoTreeRoot L1 Info tree root to proof imported bridges * @param newLocalExitRoot New local exit root * @param newPessimisticRoot New pessimistic information, Hash(localBalanceTreeRoot, nullifierTreeRoot) */ function getInputPessimisticBytes( uint32 rollupID, - bytes32 selectedGlobalExitRoot, + bytes32 l1InfoTreeRoot, bytes32 newLocalExitRoot, bytes32 newPessimisticRoot ) public view returns (bytes memory) { @@ -1306,7 +1312,7 @@ contract PolygonRollupManager is _getInputPessimisticBytes( rollupID, _rollupIDToRollupData[rollupID], - selectedGlobalExitRoot, + l1InfoTreeRoot, newLocalExitRoot, newPessimisticRoot ); @@ -1316,14 +1322,14 @@ contract PolygonRollupManager is * @notice Function to calculate the input snark bytes * @param rollupID Rollup identifier * @param rollup Rollup data storage pointer - * @param selectedGlobalExitRoot Selected global exit root to proof imported bridges + * @param l1InfoTreeRoot L1 Info tree root to proof imported bridges * @param newLocalExitRoot New local exit root * @param newPessimisticRoot New pessimistic information, Hash(localBalanceTreeRoot, nullifierTreeRoot) */ function _getInputPessimisticBytes( uint32 rollupID, RollupData storage rollup, - bytes32 selectedGlobalExitRoot, + bytes32 l1InfoTreeRoot, bytes32 newLocalExitRoot, bytes32 newPessimisticRoot ) internal view returns (bytes memory) { @@ -1336,7 +1342,7 @@ contract PolygonRollupManager is abi.encodePacked( rollup.lastLocalExitRoot, rollup.lastPessimisticRoot, - selectedGlobalExitRoot, + l1InfoTreeRoot, rollupID, consensusHash, newLocalExitRoot, diff --git a/contracts/v2/consensus/validium/PolygonValidiumEtrog.sol b/contracts/v2/consensus/validium/PolygonValidiumEtrog.sol index ce68c10f9..77b0784e8 100644 --- a/contracts/v2/consensus/validium/PolygonValidiumEtrog.sol +++ b/contracts/v2/consensus/validium/PolygonValidiumEtrog.sol @@ -121,7 +121,7 @@ contract PolygonValidiumEtrog is PolygonRollupBaseEtrog, IPolygonValidium { ); if (l1InfoRoot == bytes32(0)) { - revert L1InfoRootIndexInvalid(); + revert L1InfoTreeLeafCountInvalid(); } // Store storage variables in memory, to save gas, because will be overrided multiple times diff --git a/contracts/v2/interfaces/IPolygonRollupManager.sol b/contracts/v2/interfaces/IPolygonRollupManager.sol index 16cb7cae8..e90a86b25 100644 --- a/contracts/v2/interfaces/IPolygonRollupManager.sol +++ b/contracts/v2/interfaces/IPolygonRollupManager.sol @@ -278,9 +278,9 @@ interface IPolygonRollupManager { error InvalidRollup(); /** - * @dev Global exit root does not exists + * @dev Not valid L1 info tree leaf count */ - error GlobalExitRootNotExist(); + error L1InfoTreeLeafCountInvalid(); /** * @dev Only State Transition Chains @@ -378,7 +378,7 @@ interface IPolygonRollupManager { function verifyPessimisticTrustedAggregator( uint32 rollupID, - bytes32 selectedGlobalExitRoot, + uint32 l1InfoTreeLeafCount, bytes32 newLocalExitRoot, bytes32 newPessimisticRoot, bytes calldata proof diff --git a/contracts/v2/interfaces/IPolygonZkEVMVEtrogErrors.sol b/contracts/v2/interfaces/IPolygonZkEVMEtrogErrors.sol similarity index 90% rename from contracts/v2/interfaces/IPolygonZkEVMVEtrogErrors.sol rename to contracts/v2/interfaces/IPolygonZkEVMEtrogErrors.sol index 94d42cb3a..ec2161bc7 100644 --- a/contracts/v2/interfaces/IPolygonZkEVMVEtrogErrors.sol +++ b/contracts/v2/interfaces/IPolygonZkEVMEtrogErrors.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; import "../../interfaces/IPolygonZkEVMErrors.sol"; -interface IPolygonZkEVMVEtrogErrors is IPolygonZkEVMErrors { +interface IPolygonZkEVMEtrogErrors is IPolygonZkEVMErrors { /** * @dev Thrown when the caller is not the trusted sequencer */ @@ -55,9 +55,9 @@ interface IPolygonZkEVMVEtrogErrors is IPolygonZkEVMErrors { error MaxTimestampSequenceInvalid(); /** - * @dev Thrown when l1 info root does not exist + * @dev Thrown when l1 info tree leafCount does not exist */ - error L1InfoRootIndexInvalid(); + error L1InfoTreeLeafCountInvalid(); /** * @dev Thrown when the acc input hash does not match the predicted by the sequencer diff --git a/contracts/v2/lib/PolygonConsensusBase.sol b/contracts/v2/lib/PolygonConsensusBase.sol index adae70ef2..72284ac3e 100644 --- a/contracts/v2/lib/PolygonConsensusBase.sol +++ b/contracts/v2/lib/PolygonConsensusBase.sol @@ -5,7 +5,7 @@ import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeab import "../interfaces/IPolygonZkEVMGlobalExitRootV2.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "../../interfaces/IPolygonZkEVMErrors.sol"; -import "../interfaces/IPolygonZkEVMVEtrogErrors.sol"; +import "../interfaces/IPolygonZkEVMEtrogErrors.sol"; import "../interfaces/IPolygonConsensusBase.sol"; import "../interfaces/IPolygonRollupBase.sol"; import "../interfaces/IPolygonZkEVMBridgeV2.sol"; @@ -24,7 +24,7 @@ import "../PolygonRollupManager.sol"; abstract contract PolygonConsensusBase is Initializable, IPolygonConsensusBase, - IPolygonZkEVMVEtrogErrors + IPolygonZkEVMEtrogErrors { // POL token address IERC20Upgradeable public immutable pol; @@ -125,6 +125,9 @@ abstract contract PolygonConsensusBase is pol = _pol; bridgeAddress = _bridgeAddress; rollupManager = _rollupManager; + + // Disable initalizers on the implementation following the best practices + _disableInitializers(); } /** diff --git a/contracts/v2/lib/PolygonRollupBaseEtrog.sol b/contracts/v2/lib/PolygonRollupBaseEtrog.sol index 5c35d7e96..5700c94d1 100644 --- a/contracts/v2/lib/PolygonRollupBaseEtrog.sol +++ b/contracts/v2/lib/PolygonRollupBaseEtrog.sol @@ -3,9 +3,8 @@ pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import "../interfaces/IPolygonZkEVMGlobalExitRootV2.sol"; -import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "../../interfaces/IPolygonZkEVMErrors.sol"; -import "../interfaces/IPolygonZkEVMVEtrogErrors.sol"; +import "../interfaces/IPolygonZkEVMEtrogErrors.sol"; import "../PolygonRollupManager.sol"; import "../interfaces/IPolygonRollupBase.sol"; import "../interfaces/IPolygonZkEVMBridgeV2.sol"; @@ -354,7 +353,7 @@ abstract contract PolygonRollupBaseEtrog is ); if (l1InfoRoot == bytes32(0)) { - revert L1InfoRootIndexInvalid(); + revert L1InfoTreeLeafCountInvalid(); } // Store storage variables in memory, to save gas, because will be overrided multiple times diff --git a/contracts/v2/previousVersions/PolygonRollupBaseEtrogPrevious.sol b/contracts/v2/previousVersions/PolygonRollupBaseEtrogPrevious.sol index f9422cec1..8728c2204 100644 --- a/contracts/v2/previousVersions/PolygonRollupBaseEtrogPrevious.sol +++ b/contracts/v2/previousVersions/PolygonRollupBaseEtrogPrevious.sol @@ -5,7 +5,7 @@ import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeab import "../interfaces/IPolygonZkEVMGlobalExitRootV2.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "../../interfaces/IPolygonZkEVMErrors.sol"; -import "../interfaces/IPolygonZkEVMVEtrogErrors.sol"; +import "../interfaces/IPolygonZkEVMEtrogErrors.sol"; import "../PolygonRollupManager.sol"; import "./IPolygonRollupBasePrevious.sol"; import "../interfaces/IPolygonZkEVMBridgeV2.sol"; @@ -23,7 +23,7 @@ import "../lib/PolygonConstantsBase.sol"; abstract contract PolygonRollupBaseEtrogPrevious is Initializable, PolygonConstantsBase, - IPolygonZkEVMVEtrogErrors, + IPolygonZkEVMEtrogErrors, IPolygonRollupBasePrevious { using SafeERC20Upgradeable for IERC20Upgradeable; @@ -283,6 +283,9 @@ abstract contract PolygonRollupBaseEtrogPrevious is pol = _pol; bridgeAddress = _bridgeAddress; rollupManager = _rollupManager; + + // Disable initalizers on the implementation following the best practices + _disableInitializers(); } /** diff --git a/src/pessimistic-utils.js b/src/pessimistic-utils.js index 18f6c9867..80054a815 100644 --- a/src/pessimistic-utils.js +++ b/src/pessimistic-utils.js @@ -17,7 +17,7 @@ const ConsensusTypes = { * ) % FrSNARK * @param {String} lastLocalExitRoot - old LER * @param {String} lastPessimisticRoot - old pessimistic root. pessRoor = Poseidon(LBR # nullifierRoot) - * @param {String} selectedGlobalExitRoot - selected GER + * @param {String} l1InfoTreeRoot - L1 info tree root * @param {Number} rollupID - rollup identifier (networkID = rollupID - 1) * @param {String} consensusHash - consensus hash. consensusHash = Sha(consensusType # consensusPayload) * @param {String} newLocalExitRoot - new LER @@ -26,7 +26,7 @@ const ConsensusTypes = { function computeInputPessimisticBytes( lastLocalExitRoot, lastPessimisticRoot, - selectedGlobalExitRoot, + l1InfoTreeRoot, rollupID, consensusHash, newLocalExitRoot, @@ -37,7 +37,7 @@ function computeInputPessimisticBytes( [ lastLocalExitRoot, lastPessimisticRoot, - selectedGlobalExitRoot, + l1InfoTreeRoot, rollupID, consensusHash, newLocalExitRoot, diff --git a/test/contractsv2/PolygonPessimisticConsensus.test.ts b/test/contractsv2/PolygonPessimisticConsensus.test.ts index 8ea85906b..4da607412 100644 --- a/test/contractsv2/PolygonPessimisticConsensus.test.ts +++ b/test/contractsv2/PolygonPessimisticConsensus.test.ts @@ -31,12 +31,12 @@ describe("PolygonPessimisticConsensus", () => { // deploy consensus // create polygonPessimisticConsensus implementation const ppConsensusFactory = await ethers.getContractFactory("PolygonPessimisticConsensus"); - PolygonPPConsensusContract = await ppConsensusFactory.deploy( - gerManagerAddress, - polTokenAddress, - bridgeAddress, - rollupManagerAddress - ); + PolygonPPConsensusContract = await upgrades.deployProxy(ppConsensusFactory, [], { + initializer: false, + constructorArgs: [gerManagerAddress, polTokenAddress, bridgeAddress, rollupManagerAddress], + unsafeAllow: ["constructor", "state-variable-immutable"], + }); + await PolygonPPConsensusContract.waitForDeployment(); }); diff --git a/test/contractsv2/PolygonRollupManager-Pessimistic.test.ts b/test/contractsv2/PolygonRollupManager-Pessimistic.test.ts index 25a7e6403..500870b55 100644 --- a/test/contractsv2/PolygonRollupManager-Pessimistic.test.ts +++ b/test/contractsv2/PolygonRollupManager-Pessimistic.test.ts @@ -829,7 +829,7 @@ describe("Polygon Rollup Manager with Polygon Pessimistic Consensus", () => { ); // select unexistent global exit root - const unexistentGER = "0xddff00000000000000000000000000000000000000000000000000000000ddff"; + const unexistentL1InfoTreeCount = 2; const newLER = "0x0000000000000000000000000000000000000000000000000000000000000001"; const newPPRoot = "0x0000000000000000000000000000000000000000000000000000000000000002"; const proofPP = "0x00"; @@ -838,7 +838,7 @@ describe("Polygon Rollup Manager with Polygon Pessimistic Consensus", () => { await expect( rollupManagerContract.verifyPessimisticTrustedAggregator( pessimisticRollupID, - unexistentGER, + unexistentL1InfoTreeCount, newLER, newPPRoot, proofPP @@ -849,10 +849,16 @@ describe("Polygon Rollup Manager with Polygon Pessimistic Consensus", () => { await expect( rollupManagerContract .connect(trustedAggregator) - .verifyPessimisticTrustedAggregator(pessimisticRollupID, unexistentGER, newLER, newPPRoot, proofPP) - ).to.be.revertedWithCustomError(rollupManagerContract, "GlobalExitRootNotExist"); + .verifyPessimisticTrustedAggregator( + pessimisticRollupID, + unexistentL1InfoTreeCount, + newLER, + newPPRoot, + proofPP + ) + ).to.be.revertedWithCustomError(rollupManagerContract, "L1InfoTreeLeafCountInvalid"); - // create a bridge to generate a new GER + // create a bridge to generate a new GER and add another value in the l1IfoRootMap const tokenAddress = ethers.ZeroAddress; const amount = ethers.parseEther("1"); await polygonZkEVMBridgeContract.bridgeAsset( @@ -867,12 +873,14 @@ describe("Polygon Rollup Manager with Polygon Pessimistic Consensus", () => { } ); - const existingGER = await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot(); + // get last L1InfoTreeLeafCount + const lastL1InfoTreeLeafCount = await polygonZkEVMGlobalExitRoot.depositCount(); + const lastL1InfoTreeRoot = await polygonZkEVMGlobalExitRoot.l1InfoRootMap(0); // check JS function computeInputPessimisticBytes const inputPessimisticBytes = await rollupManagerContract.getInputPessimisticBytes( pessimisticRollupID, - existingGER, + lastL1InfoTreeRoot, newLER, newPPRoot ); @@ -884,7 +892,7 @@ describe("Polygon Rollup Manager with Polygon Pessimistic Consensus", () => { const expectedInputPessimsiticBytes = computeInputPessimisticBytes( infoRollup[4], infoRollup[10], - existingGER, + lastL1InfoTreeRoot, pessimisticRollupID, consensusHash, newLER, @@ -897,7 +905,13 @@ describe("Polygon Rollup Manager with Polygon Pessimistic Consensus", () => { await expect( rollupManagerContract .connect(trustedAggregator) - .verifyPessimisticTrustedAggregator(pessimisticRollupID, existingGER, newLER, newPPRoot, proofPP) + .verifyPessimisticTrustedAggregator( + pessimisticRollupID, + lastL1InfoTreeLeafCount, + newLER, + newPPRoot, + proofPP + ) ) .to.emit(rollupManagerContract, "VerifyBatchesTrustedAggregator") .withArgs(pessimisticRollupID, 0, ethers.ZeroHash, newLER, trustedAggregator.address); @@ -1005,7 +1019,7 @@ describe("Polygon Rollup Manager with Polygon Pessimistic Consensus", () => { ); // try to verify - const unexistentGER = "0xddff00000000000000000000000000000000000000000000000000000000ddff"; + const unexistentL1InfoTreeLeafcount = 2; const newLER = "0x0000000000000000000000000000000000000000000000000000000000000001"; const newPPRoot = "0x0000000000000000000000000000000000000000000000000000000000000002"; const proofPP = "0x00"; @@ -1013,7 +1027,13 @@ describe("Polygon Rollup Manager with Polygon Pessimistic Consensus", () => { await expect( rollupManagerContract .connect(trustedAggregator) - .verifyPessimisticTrustedAggregator(stateTransistionRollupID, unexistentGER, newLER, newPPRoot, proofPP) + .verifyPessimisticTrustedAggregator( + stateTransistionRollupID, + unexistentL1InfoTreeLeafcount, + newLER, + newPPRoot, + proofPP + ) ).to.be.revertedWithCustomError(rollupManagerContract, "OnlyChainsWithPessimisticProofs"); }); }); diff --git a/test/contractsv2/PolygonRollupManager.test.ts b/test/contractsv2/PolygonRollupManager.test.ts index 7c2e51768..6a74cd906 100644 --- a/test/contractsv2/PolygonRollupManager.test.ts +++ b/test/contractsv2/PolygonRollupManager.test.ts @@ -3038,12 +3038,17 @@ describe("Polygon Rollup Manager", () => { // Create zkEVM implementation const PolygonZKEVMV2Factory = await ethers.getContractFactory("PolygonZkEVMExistentEtrog"); - const PolygonZKEVMV2Contract = await PolygonZKEVMV2Factory.deploy( - polygonZkEVMGlobalExitRoot.target, - polTokenContract.target, - polygonZkEVMBridgeContract.target, - rollupManagerContract.target - ); + const PolygonZKEVMV2Contract = await upgrades.deployProxy(PolygonZKEVMV2Factory, [], { + initializer: false, + constructorArgs: [ + polygonZkEVMGlobalExitRoot.target, + polTokenContract.target, + polygonZkEVMBridgeContract.target, + rollupManagerContract.target, + ], + unsafeAllow: ["constructor", "state-variable-immutable"], + }); + await PolygonZKEVMV2Contract.waitForDeployment(); // Add a new rollup type with timelock diff --git a/test/contractsv2/PolygonValidiumEtrog.test.ts b/test/contractsv2/PolygonValidiumEtrog.test.ts index d91dbd55a..67766b020 100644 --- a/test/contractsv2/PolygonValidiumEtrog.test.ts +++ b/test/contractsv2/PolygonValidiumEtrog.test.ts @@ -29,7 +29,7 @@ function calculateGlobalExitRoot(mainnetExitRoot: any, rollupExitRoot: any) { return ethers.solidityPackedKeccak256(["bytes32", "bytes32"], [mainnetExitRoot, rollupExitRoot]); } -describe("PolygonZkEVMEtrog", () => { +describe("PolygonValidiumEtrog", () => { let deployer: any; let timelock: any; let emergencyCouncil: any; @@ -166,12 +166,17 @@ describe("PolygonZkEVMEtrog", () => { // deploy consensus // Create zkEVM implementation const PolygonZKEVMV2Factory = await ethers.getContractFactory("PolygonValidiumEtrog"); - PolygonZKEVMV2Contract = await PolygonZKEVMV2Factory.deploy( - polygonZkEVMGlobalExitRoot.target, - polTokenContract.target, - polygonZkEVMBridgeContract.target, - rollupManagerContract.target - ); + PolygonZKEVMV2Contract = await upgrades.deployProxy(PolygonZKEVMV2Factory, [], { + initializer: false, + constructorArgs: [ + polygonZkEVMGlobalExitRoot.target, + polTokenContract.target, + polygonZkEVMBridgeContract.target, + rollupManagerContract.target, + ], + unsafeAllow: ["constructor", "state-variable-immutable"], + }); + await PolygonZKEVMV2Contract.waitForDeployment(); // Create CdkCommitee diff --git a/test/contractsv2/PolygonZkEVMEtrog.test.ts b/test/contractsv2/PolygonZkEVMEtrog.test.ts index a08adace0..0d2e14cbb 100644 --- a/test/contractsv2/PolygonZkEVMEtrog.test.ts +++ b/test/contractsv2/PolygonZkEVMEtrog.test.ts @@ -163,12 +163,17 @@ describe("PolygonZkEVMEtrog", () => { // deploy consensus // Create zkEVM implementation const PolygonZKEVMV2Factory = await ethers.getContractFactory("PolygonZkEVMEtrog"); - PolygonZKEVMV2Contract = await PolygonZKEVMV2Factory.deploy( - polygonZkEVMGlobalExitRoot.target, - polTokenContract.target, - polygonZkEVMBridgeContract.target, - rollupManagerContract.target - ); + PolygonZKEVMV2Contract = await upgrades.deployProxy(PolygonZKEVMV2Factory, [], { + initializer: false, + constructorArgs: [ + polygonZkEVMGlobalExitRoot.target, + polTokenContract.target, + polygonZkEVMBridgeContract.target, + rollupManagerContract.target, + ], + unsafeAllow: ["constructor", "state-variable-immutable"], + }); + await PolygonZKEVMV2Contract.waitForDeployment(); }); @@ -490,7 +495,7 @@ describe("PolygonZkEVMEtrog", () => { expectedAccInputHash, trustedSequencer.address ) - ).to.be.revertedWithCustomError(PolygonZKEVMV2Contract, "L1InfoRootIndexInvalid"); + ).to.be.revertedWithCustomError(PolygonZKEVMV2Contract, "L1InfoTreeLeafCountInvalid"); await expect( PolygonZKEVMV2Contract.connect(trustedSequencer).sequenceBatches(