From fe701edbf6396914858d982916bc58fd74e82d83 Mon Sep 17 00:00:00 2001 From: William Morriss Date: Tue, 26 May 2026 10:31:56 -0500 Subject: [PATCH 1/4] feat(verifier): allow getNextPieceId and getNextChallengeEpoch during cleanup mode Assisted-by: Claude:claude-sonnet-4-6 --- src/PDPVerifier.sol | 51 +++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/PDPVerifier.sol b/src/PDPVerifier.sol index 0543252..e7ae394 100644 --- a/src/PDPVerifier.sol +++ b/src/PDPVerifier.sol @@ -248,10 +248,14 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { return nextDataSetId; } + // Returns false if the data set is 1) not yet created 2) fully deleted (cleanup complete) + function dataSetExists(uint256 setId) internal view returns (bool) { + return setId < nextDataSetId && storageProvider[setId] != address(0); + } + // Returns false if the data set is 1) not yet created 2) deleted or in cleanup mode function dataSetLive(uint256 setId) public view returns (bool) { - return setId < nextDataSetId && storageProvider[setId] != address(0) - && nextChallengeEpoch[setId] != CLEANUP_MODE_SENTINEL; + return dataSetExists(setId) && nextChallengeEpoch[setId] != CLEANUP_MODE_SENTINEL; } // Returns false if the data set is not live or if the piece id is 1) not yet created 2) deleted @@ -272,60 +276,60 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { // Returns the leaf count of a data set function getDataSetLeafCount(uint256 setId) public view returns (uint256) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); return dataSetLeafCount[setId]; } - // Returns the next piece ID for a data set + // Returns the next piece ID for a data set. Also valid during cleanup mode. function getNextPieceId(uint256 setId) public view returns (uint256) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetExists(setId), DataSetNotFound()); return nextPieceId[setId]; } - // Returns the next challenge epoch for a data set + // Returns the next challenge epoch for a data set. Returns type(uint256).max during cleanup mode. function getNextChallengeEpoch(uint256 setId) public view returns (uint256) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetExists(setId), DataSetNotFound()); return nextChallengeEpoch[setId]; } // Returns the listener address for a data set function getDataSetListener(uint256 setId) public view returns (address) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); return dataSetListener[setId]; } // Returns the storage provider of a data set and the proposed storage provider if any function getDataSetStorageProvider(uint256 setId) public view returns (address, address) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); return (storageProvider[setId], dataSetProposedStorageProvider[setId]); } function getDataSetLastProvenEpoch(uint256 setId) public view returns (uint256) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); return dataSetLastProvenEpoch[setId]; } // Returns the piece CID for a given data set and piece ID function getPieceCid(uint256 setId, uint256 pieceId) public view returns (Cids.Cid memory) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); return pieceCids[setId][pieceId]; } // Returns the piece leaf count for a given data set and piece ID function getPieceLeafCount(uint256 setId, uint256 pieceId) public view returns (uint256) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); return pieceLeafCounts[setId][pieceId]; } // Returns the index of the most recently added leaf that is challengeable in the current proving period function getChallengeRange(uint256 setId) public view returns (uint256) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); return challengeRange[setId]; } // Returns the piece ids of the pieces scheduled for removal at the start of the next proving period function getScheduledRemovals(uint256 setId) public view returns (uint256[] memory) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); uint256[] storage removals = scheduledRemovals[setId]; uint256[] memory result = new uint256[](removals.length); for (uint256 i = 0; i < removals.length; i++) { @@ -340,7 +344,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { * @return activeCount The number of active pieces in the data set */ function getActivePieceCount(uint256 setId) public view returns (uint256 activeCount) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); uint256 maxPieceId = nextPieceId[setId]; for (uint256 i = 0; i < maxPieceId; i++) { @@ -366,7 +370,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { view returns (Cids.Cid[] memory pieces, uint256[] memory pieceIds, bool hasMore) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); require(limit > 0, "Limit must be greater than 0"); // Single pass: collect data and check for more @@ -430,7 +434,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { view returns (Cids.Cid[] memory pieces, uint256[] memory pieceIds, bool hasMore) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); require(limit > 0, "Limit must be greater than 0"); uint256 maxPieceId = nextPieceId[setId]; @@ -494,7 +498,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { view returns (uint256[] memory pieceIds) { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); require(limit > 0, "Limit must be greater than 0"); bytes32 targetHash = keccak256(pieceCid.data); @@ -517,7 +521,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { // storage provider proposes new storage provider. If the storage provider proposes themself delete any outstanding proposed storage provider function proposeDataSetStorageProvider(uint256 setId, address newStorageProvider) public { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); address currentStorageProvider = storageProvider[setId]; require( currentStorageProvider == msg.sender, "Only the current storage provider can propose a new storage provider" @@ -531,7 +535,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { } function claimDataSetStorageProvider(uint256 setId, bytes calldata extraData) public { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); require( dataSetProposedStorageProvider[setId] == msg.sender, "Only the proposed storage provider can claim storage provider role" @@ -740,7 +744,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { require(listenerAddr == address(0), "listener must be zero for existing dataset"); require(msg.value == 0, "no fee on add to existing dataset"); - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); require(storageProvider[setId] == msg.sender, "Only the storage provider can add pieces"); return _addPiecesToDataSet(setId, pieceData, extraData); @@ -775,6 +779,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { error IndexedError(uint256 idx, string msg); error CleanupDepositRequired(); + error DataSetNotFound(); error DataSetNotLive(); error DataSetAlreadyInCleanup(); error OnlyStorageProviderCanDelete(); @@ -808,7 +813,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { // schedulePieceDeletions schedules deletion of a batch of pieces from a data set for the start of the next // proving period. It must be called by the storage provider. function schedulePieceDeletions(uint256 setId, uint256[] calldata pieceIds, bytes calldata extraData) public { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); require(storageProvider[setId] == msg.sender, "Only the storage provider can schedule removal of pieces"); require( pieceIds.length + scheduledRemovals[setId].length <= MAX_ENQUEUED_REMOVALS, @@ -1037,7 +1042,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { // removes pieces from a data set's state. function removePieces(uint256 setId, uint256[] memory pieceIds) internal { - require(dataSetLive(setId), "Data set not live"); + require(dataSetLive(setId), DataSetNotLive()); uint256 totalDelta = 0; for (uint256 i = 0; i < pieceIds.length; i++) { totalDelta += removeOnePiece(setId, pieceIds[i]); From cc03deadfdf7f27ca65f5f69aa628f0b3ee53d03 Mon Sep 17 00:00:00 2001 From: William Morriss Date: Tue, 26 May 2026 10:40:06 -0500 Subject: [PATCH 2/4] test(verifier): update error expectations from string to custom errors Assisted-by: Claude:claude-sonnet-4-6 --- test/PDPVerifier.t.sol | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/PDPVerifier.t.sol b/test/PDPVerifier.t.sol index 6b82a8c..0d9bed0 100644 --- a/test/PDPVerifier.t.sol +++ b/test/PDPVerifier.t.sol @@ -68,7 +68,7 @@ contract PDPVerifierDataSetCreateDeleteTest is MockFVMTest, PieceHelper { vm.expectEmit(true, true, false, false); emit IPDPEvents.DataSetDeleted(setId, 0); pdpVerifier.deleteDataSet(setId, empty); - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.getDataSetLeafCount(setId); } @@ -87,7 +87,7 @@ contract PDPVerifierDataSetCreateDeleteTest is MockFVMTest, PieceHelper { vm.expectEmit(true, true, false, false); emit IPDPEvents.DataSetDeleted(setId, 0); pdpVerifier.deleteDataSet(setId, empty); - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.getDataSetStorageProvider(setId); } @@ -112,19 +112,19 @@ contract PDPVerifierDataSetCreateDeleteTest is MockFVMTest, PieceHelper { pdpVerifier.deleteDataSet(setId, empty); vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.deleteDataSet(setId, empty); - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.getDataSetStorageProvider(setId); - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.getDataSetLeafCount(setId); - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.getDataSetListener(setId); - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.getPieceCid(setId, 0); - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.getPieceLeafCount(setId, 0); - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotFound.selector); pdpVerifier.getNextChallengeEpoch(setId); - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.addPieces(setId, address(0), new Cids.Cid[](1), empty); } @@ -399,7 +399,7 @@ contract PDPVerifierDataSetMutateTest is MockFVMTest, PieceHelper { pieces[0] = makeSamplePiece(64); bytes memory addPayload = abi.encode("add", "data"); - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.addPieces( 999, // Non-existent data set ID address(0), @@ -490,7 +490,7 @@ contract PDPVerifierDataSetMutateTest is MockFVMTest, PieceHelper { // Fail when data set is no longer live pieces[0] = makeSamplePiece(1); pdpVerifier.deleteDataSet(setId, empty); - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.addPieces(setId, address(0), pieces, empty); } @@ -561,7 +561,7 @@ contract PDPVerifierDataSetMutateTest is MockFVMTest, PieceHelper { // Attempt to schedule removal of the piece, which should fail uint256[] memory pieceIds = new uint256[](1); pieceIds[0] = 0; - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.schedulePieceDeletions(setId, pieceIds, empty); } @@ -1072,11 +1072,11 @@ contract PDPVerifierPaginationTest is MockFVMTest, PieceHelper { function testGetActivePiecesNotLive() public { // Test with invalid data set ID - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.getActivePieces(999, 0, 10); // Also test getActivePieceCount - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.getActivePieceCount(999); } @@ -1256,7 +1256,7 @@ contract PDPVerifierPaginationTest is MockFVMTest, PieceHelper { } function testGetActivePiecesByCursorNotLive() public { - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.getActivePiecesByCursor(999, 0, 10); } @@ -2496,7 +2496,7 @@ contract PDPVerifierCIDSearchTest is MockFVMTest, PieceHelper { function testFindPieceIdsByCid_InvalidDataSet() public { Cids.Cid memory target = makeSamplePiece(64); - vm.expectRevert("Data set not live"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.findPieceIdsByCid(999, target, 0, 10); } From 014bf10c0a55c44a1a58f1110ef12b2622accec6 Mon Sep 17 00:00:00 2001 From: William Morriss Date: Tue, 26 May 2026 10:40:40 -0500 Subject: [PATCH 3/4] refactor(verifier): drop redundant setId bounds check in dataSetExists Assisted-by: Claude:claude-sonnet-4-6 --- src/PDPVerifier.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PDPVerifier.sol b/src/PDPVerifier.sol index e7ae394..18ddaaf 100644 --- a/src/PDPVerifier.sol +++ b/src/PDPVerifier.sol @@ -250,7 +250,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { // Returns false if the data set is 1) not yet created 2) fully deleted (cleanup complete) function dataSetExists(uint256 setId) internal view returns (bool) { - return setId < nextDataSetId && storageProvider[setId] != address(0); + return storageProvider[setId] != address(0); } // Returns false if the data set is 1) not yet created 2) deleted or in cleanup mode From afaf2f47324f61f4a7efe82c641117ceab862738 Mon Sep 17 00:00:00 2001 From: William Morriss Date: Tue, 26 May 2026 10:45:42 -0500 Subject: [PATCH 4/4] refactor(verifier): remove redundant setId bounds check in deleteDataSet Assisted-by: Claude:claude-sonnet-4-6 --- src/PDPVerifier.sol | 4 ---- test/PDPVerifier.t.sol | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/PDPVerifier.sol b/src/PDPVerifier.sol index 18ddaaf..985b6bb 100644 --- a/src/PDPVerifier.sol +++ b/src/PDPVerifier.sol @@ -591,10 +591,6 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable { // cleanupPieces must be called to finish storage teardown and collect the cleanup deposit. // For zero-piece data sets, cleanup is finalized immediately and the deposit is paid to msg.sender. function deleteDataSet(uint256 setId, bytes calldata extraData) public { - if (setId >= nextDataSetId) { - revert("data set id out of bounds"); - } - address sp = storageProvider[setId]; require(sp != address(0), DataSetNotLive()); require(nextChallengeEpoch[setId] != CLEANUP_MODE_SENTINEL, DataSetAlreadyInCleanup()); diff --git a/test/PDPVerifier.t.sol b/test/PDPVerifier.t.sol index 0d9bed0..fb85ca4 100644 --- a/test/PDPVerifier.t.sol +++ b/test/PDPVerifier.t.sol @@ -98,7 +98,7 @@ contract PDPVerifierDataSetCreateDeleteTest is MockFVMTest, PieceHelper { pdpVerifier.deleteDataSet(0, empty); // Test with a data set ID that hasn't been created yet - vm.expectRevert("data set id out of bounds"); + vm.expectRevert(PDPVerifier.DataSetNotLive.selector); pdpVerifier.deleteDataSet(999, empty); }