From 7b99e5ff20170f59dbb503a6ae19acb279210c8d Mon Sep 17 00:00:00 2001 From: The Dark Jester Date: Thu, 31 Oct 2024 09:38:52 -0700 Subject: [PATCH] [Fix] M-01 Validate final blob was submitted on finalization (#226) * Validate final blob was submitted on finalization * Use new error code in Coordinator * Use correct name for error --- config/common/smart-contract-errors.toml | 3 +- contracts/contracts/LineaRollup.sol | 5 ++ .../contracts/interfaces/l1/ILineaRollup.sol | 5 ++ contracts/test/LineaRollup.ts | 50 +++++++++++++++++++ .../app/config/CoordinatorConfigTest.kt | 1 + 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/config/common/smart-contract-errors.toml b/config/common/smart-contract-errors.toml index eaa68c18..67162f9e 100644 --- a/config/common/smart-contract-errors.toml +++ b/config/common/smart-contract-errors.toml @@ -41,9 +41,10 @@ "b015579f" = "IsNotPaused" "3b174434" = "MessageHashesListLengthHigherThanOneHundred" "ca389c44" = "InvalidProofOrProofVerificationRanOutOfGas" +"42ab979d" = "ParentBlobNotSubmitted" +"edeae83c" = "FinalBlobNotSubmitted" # L2 Message Service "6446cc9c" = "MessageHashesListLengthIsZero" "d39e75f9" = "L1MessageNumberSynchronizationWrong" "7557a60a" = "L1RollingHashSynchronizationWrong" "36a4bb94" = "FinalRollingHashIsZero" -"42ab979d" = "ParentBlobNotSubmitted" diff --git a/contracts/contracts/LineaRollup.sol b/contracts/contracts/LineaRollup.sol index 73d72346..6f9cee2c 100644 --- a/contracts/contracts/LineaRollup.sol +++ b/contracts/contracts/LineaRollup.sol @@ -445,6 +445,7 @@ contract LineaRollup is /// @dev currentFinalizedShnarf is updated in _finalizeBlocks and lastFinalizedShnarf MUST be set beforehand for the transition. bytes32 lastFinalizedShnarf = currentFinalizedShnarf; + bytes32 finalShnarf = _finalizeBlocks(_finalizationData, lastFinalizedBlockNumber); uint256 publicInput = _computePublicInput( @@ -507,6 +508,10 @@ contract LineaRollup is _finalizationData.shnarfData.dataEvaluationClaim ); + if (blobShnarfExists[finalShnarf] == 0) { + revert FinalBlobNotSubmitted(finalShnarf); + } + _addL2MerkleRoots(_finalizationData.l2MerkleRoots, _finalizationData.l2MerkleTreesDepth); _anchorL2MessagingBlocks(_finalizationData.l2MessagingBlocksOffsets, _lastFinalizedBlock); diff --git a/contracts/contracts/interfaces/l1/ILineaRollup.sol b/contracts/contracts/interfaces/l1/ILineaRollup.sol index c93f16a9..c4c747c6 100644 --- a/contracts/contracts/interfaces/l1/ILineaRollup.sol +++ b/contracts/contracts/interfaces/l1/ILineaRollup.sol @@ -278,6 +278,11 @@ interface ILineaRollup { */ error ParentBlobNotSubmitted(bytes32 shnarf); + /** + * @dev Thrown when a shnarf does not exist for the final blob being finalized. + */ + error FinalBlobNotSubmitted(bytes32 shnarf); + /** * @notice Adds or updates the verifier contract address for a proof type. * @dev VERIFIER_SETTER_ROLE is required to execute. diff --git a/contracts/test/LineaRollup.ts b/contracts/test/LineaRollup.ts index 3b6cbc1c..7f697725 100644 --- a/contracts/test/LineaRollup.ts +++ b/contracts/test/LineaRollup.ts @@ -1342,6 +1342,56 @@ describe("Linea Rollup contract", () => { ]); }); + it("Should revert if the final shnarf does not exist", async () => { + const submissionDataBeforeFinalization = generateCallDataSubmission(0, 4); + let index = 0; + for (const data of submissionDataBeforeFinalization) { + const parentAndExpectedShnarf = generateParentAndExpectedShnarfForIndex(index); + await lineaRollup + .connect(operator) + .submitDataAsCalldata(data, parentAndExpectedShnarf.parentShnarf, parentAndExpectedShnarf.expectedShnarf, { + gasLimit: 30_000_000, + }); + index++; + } + + const finalizationData = await generateFinalizationData({ + l1RollingHash: calculateRollingHash(HASH_ZERO, messageHash), + l1RollingHashMessageNumber: 10n, + lastFinalizedTimestamp: DEFAULT_LAST_FINALIZED_TIMESTAMP, + endBlockNumber: BigInt(calldataAggregatedProof1To155.finalBlockNumber), + parentStateRootHash: calldataAggregatedProof1To155.parentStateRootHash, + finalTimestamp: BigInt(calldataAggregatedProof1To155.finalTimestamp), + l2MerkleRoots: calldataAggregatedProof1To155.l2MerkleRoots, + l2MerkleTreesDepth: BigInt(calldataAggregatedProof1To155.l2MerkleTreesDepth), + l2MessagingBlocksOffsets: calldataAggregatedProof1To155.l2MessagingBlocksOffsets, + aggregatedProof: calldataAggregatedProof1To155.aggregatedProof, + shnarfData: generateParentShnarfData(index), + }); + + await lineaRollup.setRollingHash( + calldataAggregatedProof1To155.l1RollingHashMessageNumber, + calldataAggregatedProof1To155.l1RollingHash, + ); + + finalizationData.shnarfData.snarkHash = generateRandomBytes(32); + + const { dataEvaluationClaim, dataEvaluationPoint, finalStateRootHash, parentShnarf, snarkHash } = + finalizationData.shnarfData; + const expectedMissingBlobShnarf = generateKeccak256( + ["bytes32", "bytes32", "bytes32", "bytes32", "bytes32"], + [parentShnarf, snarkHash, finalStateRootHash, dataEvaluationPoint, dataEvaluationClaim], + ); + + const finalizeCompressedCall = lineaRollup + .connect(operator) + .finalizeBlocks(calldataAggregatedProof1To155.aggregatedProof, TEST_PUBLIC_VERIFIER_INDEX, finalizationData); + + await expectRevertWithCustomError(lineaRollup, finalizeCompressedCall, "FinalBlobNotSubmitted", [ + expectedMissingBlobShnarf, + ]); + }); + it("Should revert if finalizationData.finalTimestamp is greater than the block.timestamp", async () => { const submissionDataBeforeFinalization = generateCallDataSubmission(0, 4); let index = 0; diff --git a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt index def06e39..2c886f7a 100644 --- a/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt +++ b/coordinator/app/src/test/kotlin/net/consensys/zkevm/coordinator/app/config/CoordinatorConfigTest.kt @@ -181,6 +181,7 @@ class CoordinatorConfigTest { "3b174434" to "MessageHashesListLengthHigherThanOneHundred", "ca389c44" to "InvalidProofOrProofVerificationRanOutOfGas", "42ab979d" to "ParentBlobNotSubmitted", + "edeae83c" to "FinalBlobNotSubmitted", // L2 Message Service "6446cc9c" to "MessageHashesListLengthIsZero", "d39e75f9" to "L1MessageNumberSynchronizationWrong",