Skip to content

Commit 45b39e2

Browse files
authored
feat: restore createDataSet (#219)
Removed in #201 as per original request. This puts that function back in just to give us the option to create empty data sets if needed, and gives us a smoother transition path for our dependencies (mainly Curio).
1 parent fc812ab commit 45b39e2

File tree

2 files changed

+91
-50
lines changed

2 files changed

+91
-50
lines changed

src/PDPVerifier.sol

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,23 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable {
177177
require(success, "Burn failed");
178178
}
179179

180+
// Validates msg.value meets sybil fee requirement and burns the fee.
181+
// Returns the sybil fee amount for later refund calculation.
182+
function _validateAndBurnSybilFee() internal returns (uint256 sybilFee) {
183+
sybilFee = PDPFees.sybilFee();
184+
require(msg.value >= sybilFee, "sybil fee not met");
185+
burnFee(sybilFee);
186+
}
187+
188+
// Refunds any amount sent over the sybil fee back to msg.sender.
189+
// Must be called after all state changes to avoid re-entrancy issues.
190+
function _refundExcessSybilFee(uint256 sybilFee) internal {
191+
if (msg.value > sybilFee) {
192+
(bool success,) = msg.sender.call{value: msg.value - sybilFee}("");
193+
require(success, "Transfer failed.");
194+
}
195+
}
196+
180197
// Returns the current challenge finality value
181198
function getChallengeFinality() public view returns (uint256) {
182199
return challengeFinality;
@@ -387,6 +404,45 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable {
387404
}
388405
}
389406

407+
// Internal helper to create a new data set and initialize its state.
408+
// Returns the newly created data set ID.
409+
function _createDataSet(address listenerAddr, bytes memory extraData) internal returns (uint256) {
410+
uint256 setId = nextDataSetId++;
411+
dataSetLeafCount[setId] = 0;
412+
nextChallengeEpoch[setId] = NO_CHALLENGE_SCHEDULED; // initialized on first call to NextProvingPeriod
413+
storageProvider[setId] = msg.sender;
414+
dataSetListener[setId] = listenerAddr;
415+
dataSetLastProvenEpoch[setId] = NO_PROVEN_EPOCH;
416+
417+
if (listenerAddr != address(0)) {
418+
PDPListener(listenerAddr).dataSetCreated(setId, msg.sender, extraData);
419+
}
420+
emit DataSetCreated(setId, msg.sender);
421+
422+
return setId;
423+
}
424+
425+
// Creates a new empty data set with no pieces. Pieces can be added later via addPieces().
426+
// This is the simpler alternative to creating and adding pieces atomically via addPieces(NEW_DATA_SET_SENTINEL, ...).
427+
//
428+
// Parameters:
429+
// - listenerAddr: Address of PDPListener contract to receive callbacks (can be address(0) for no listener)
430+
// - extraData: Arbitrary bytes passed to listener's dataSetCreated callback
431+
// - msg.value: Must include sybil fee (PDPFees.sybilFee()), excess is refunded
432+
//
433+
// Returns: The newly created data set ID
434+
//
435+
// Only the storage provider (msg.sender) can call this function.
436+
function createDataSet(address listenerAddr, bytes calldata extraData) public payable returns (uint256) {
437+
require(extraData.length <= EXTRA_DATA_MAX_SIZE, "Extra data too large");
438+
uint256 sybilFee = _validateAndBurnSybilFee();
439+
440+
uint256 setId = _createDataSet(listenerAddr, extraData);
441+
442+
_refundExcessSybilFee(sybilFee);
443+
return setId;
444+
}
445+
390446
// Removes a data set. Must be called by the storage provider.
391447
function deleteDataSet(uint256 setId, bytes calldata extraData) public {
392448
require(extraData.length <= EXTRA_DATA_MAX_SIZE, "Extra data too large");
@@ -408,9 +464,28 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable {
408464
emit DataSetDeleted(setId, deletedLeafCount);
409465
}
410466

411-
// Create Dataset and Add Pieces, When setId == NEW_DATA_SET_SENTINEL, this will create a new dataset with piece data provided
412-
// with the provided listenerAddr and expect extraData to be abi.encode(bytes createPayload, bytes addPayload).
413-
// When adding to an existing set, pass listenerAddr == address(0) and setId to the live dataset.
467+
// Appends pieces to a data set. Optionally creates a new data set if setId == 0.
468+
// These pieces won't be challenged until the next proving period is started by calling nextProvingPeriod.
469+
//
470+
// Two modes of operation:
471+
// 1. Add to existing data set:
472+
// - setId: ID of the existing data set
473+
// - listenerAddr: must be address(0)
474+
// - extraData: arbitrary bytes passed to the listener's piecesAdded callback
475+
// - msg.value: must be 0 (no fee required)
476+
// - Returns: first piece ID added
477+
//
478+
// 2. Create new data set and add pieces (atomic operation):
479+
// - setId: must be NEW_DATA_SET_SENTINEL (0)
480+
// - listenerAddr: listener contract address (required, cannot be address(0))
481+
// - pieceData: array of pieces to add (can be empty to create empty data set)
482+
// - extraData: abi.encode(bytes createPayload, bytes addPayload) where:
483+
// - createPayload: passed to listener's dataSetCreated callback
484+
// - addPayload: passed to listener's piecesAdded callback (if pieces added)
485+
// - msg.value: must include sybil fee (PDPFees.sybilFee()), excess is refunded
486+
// - Returns: the newly created data set ID
487+
//
488+
// Only the storage provider can call this function.
414489
function addPieces(uint256 setId, address listenerAddr, Cids.Cid[] calldata pieceData, bytes calldata extraData)
415490
public
416491
payable
@@ -420,31 +495,17 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable {
420495
(bytes memory createPayload, bytes memory addPayload) = abi.decode(extraData, (bytes, bytes));
421496

422497
require(createPayload.length <= EXTRA_DATA_MAX_SIZE, "Extra data too large");
423-
uint256 sybilFee = PDPFees.sybilFee();
424-
require(msg.value >= sybilFee, "sybil fee not met");
425-
burnFee(sybilFee);
498+
uint256 sybilFee = _validateAndBurnSybilFee();
426499

427500
require(listenerAddr != address(0), "listener required for new dataset");
428-
uint256 newSetId = nextDataSetId++;
429-
storageProvider[newSetId] = msg.sender;
430-
dataSetListener[newSetId] = listenerAddr;
431-
432-
if (listenerAddr != address(0)) {
433-
PDPListener(listenerAddr).dataSetCreated(newSetId, msg.sender, createPayload);
434-
}
435-
emit DataSetCreated(newSetId, msg.sender);
501+
uint256 newSetId = _createDataSet(listenerAddr, createPayload);
436502

437503
// Add pieces to the newly created data set (if any)
438504
if (pieceData.length > 0) {
439505
_addPiecesToDataSet(newSetId, pieceData, addPayload);
440506
}
441507

442-
// Return the at the end to avoid any possible re-entrency issues.
443-
if (msg.value > sybilFee) {
444-
(bool success,) = msg.sender.call{value: msg.value - sybilFee}("");
445-
require(success, "Transfer failed.");
446-
}
447-
508+
_refundExcessSybilFee(sybilFee);
448509
return newSetId;
449510
} else {
450511
// Adding to an existing set; no fee should be sent and listenerAddr must be zero

test/PDPVerifier.t.sol

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,7 @@ contract PDPVerifierDataSetCreateDeleteTest is MockFVMTest, PieceHelper {
3737
vm.expectEmit(true, true, false, false);
3838
emit IPDPEvents.DataSetCreated(1, address(this));
3939

40-
uint256 setId = pdpVerifier.addPieces{value: PDPFees.sybilFee()}(
41-
NEW_DATA_SET_SENTINEL, address(listener), new Cids.Cid[](0), abi.encode(empty, empty)
42-
);
40+
uint256 setId = pdpVerifier.createDataSet{value: PDPFees.sybilFee()}(address(listener), empty);
4341
assertEq(setId, 1, "First data set ID should be 1");
4442
assertEq(pdpVerifier.getDataSetLeafCount(setId), 0, "Data set leaf count should be 0");
4543

@@ -66,9 +64,7 @@ contract PDPVerifierDataSetCreateDeleteTest is MockFVMTest, PieceHelper {
6664
function testDeleteDataSet() public {
6765
vm.expectEmit(true, true, false, false);
6866
emit IPDPEvents.DataSetCreated(1, address(this));
69-
uint256 setId = pdpVerifier.addPieces{value: PDPFees.sybilFee()}(
70-
NEW_DATA_SET_SENTINEL, address(listener), new Cids.Cid[](0), abi.encode(empty, empty)
71-
);
67+
uint256 setId = pdpVerifier.createDataSet{value: PDPFees.sybilFee()}(address(listener), empty);
7268
vm.expectEmit(true, true, false, false);
7369
emit IPDPEvents.DataSetDeleted(setId, 0);
7470
pdpVerifier.deleteDataSet(setId, empty);
@@ -79,9 +75,7 @@ contract PDPVerifierDataSetCreateDeleteTest is MockFVMTest, PieceHelper {
7975
function testOnlyStorageProviderCanDeleteDataSet() public {
8076
vm.expectEmit(true, true, false, false);
8177
emit IPDPEvents.DataSetCreated(1, address(this));
82-
uint256 setId = pdpVerifier.addPieces{value: PDPFees.sybilFee()}(
83-
NEW_DATA_SET_SENTINEL, address(listener), new Cids.Cid[](0), abi.encode(empty, empty)
84-
);
78+
uint256 setId = pdpVerifier.createDataSet{value: PDPFees.sybilFee()}(address(listener), empty);
8579
// Create a new address to act as a non-storage-provider
8680
address nonStorageProvider = address(0x1234);
8781
// Expect revert when non-storage-provider tries to delete the data set
@@ -111,9 +105,7 @@ contract PDPVerifierDataSetCreateDeleteTest is MockFVMTest, PieceHelper {
111105
function testMethodsOnDeletedDataSetFails() public {
112106
vm.expectEmit(true, true, false, false);
113107
emit IPDPEvents.DataSetCreated(1, address(this));
114-
uint256 setId = pdpVerifier.addPieces{value: PDPFees.sybilFee()}(
115-
NEW_DATA_SET_SENTINEL, address(listener), new Cids.Cid[](0), abi.encode(empty, empty)
116-
);
108+
uint256 setId = pdpVerifier.createDataSet{value: PDPFees.sybilFee()}(address(listener), empty);
117109

118110
vm.expectEmit(true, true, false, false);
119111
emit IPDPEvents.DataSetDeleted(setId, 0);
@@ -139,14 +131,10 @@ contract PDPVerifierDataSetCreateDeleteTest is MockFVMTest, PieceHelper {
139131
function testGetDataSetID() public {
140132
vm.expectEmit(true, true, false, false);
141133
emit IPDPEvents.DataSetCreated(1, address(this));
142-
pdpVerifier.addPieces{value: PDPFees.sybilFee()}(
143-
NEW_DATA_SET_SENTINEL, address(listener), new Cids.Cid[](0), abi.encode(empty, empty)
144-
);
134+
pdpVerifier.createDataSet{value: PDPFees.sybilFee()}(address(listener), empty);
145135
vm.expectEmit(true, true, false, false);
146136
emit IPDPEvents.DataSetCreated(2, address(this));
147-
pdpVerifier.addPieces{value: PDPFees.sybilFee()}(
148-
NEW_DATA_SET_SENTINEL, address(listener), new Cids.Cid[](0), abi.encode(empty, empty)
149-
);
137+
pdpVerifier.createDataSet{value: PDPFees.sybilFee()}(address(listener), empty);
150138
assertEq(3, pdpVerifier.getNextDataSetId(), "Next data set ID should be 3");
151139
assertEq(3, pdpVerifier.getNextDataSetId(), "Next data set ID should be 3");
152140
}
@@ -157,14 +145,10 @@ contract PDPVerifierDataSetCreateDeleteTest is MockFVMTest, PieceHelper {
157145
// Test that data set IDs start from 1, not 0
158146
assertEq(pdpVerifier.getNextDataSetId(), 1, "Next data set ID should start at 1");
159147

160-
uint256 firstSetId = pdpVerifier.addPieces{value: PDPFees.sybilFee()}(
161-
NEW_DATA_SET_SENTINEL, address(listener), new Cids.Cid[](0), abi.encode(empty, empty)
162-
);
148+
uint256 firstSetId = pdpVerifier.createDataSet{value: PDPFees.sybilFee()}(address(listener), empty);
163149
assertEq(firstSetId, 1, "First data set ID should be 1, not 0");
164150

165-
uint256 secondSetId = pdpVerifier.addPieces{value: PDPFees.sybilFee()}(
166-
NEW_DATA_SET_SENTINEL, address(listener), new Cids.Cid[](0), abi.encode(empty, empty)
167-
);
151+
uint256 secondSetId = pdpVerifier.createDataSet{value: PDPFees.sybilFee()}(address(listener), empty);
168152
assertEq(secondSetId, 2, "Second data set ID should be 2");
169153

170154
assertEq(pdpVerifier.getNextDataSetId(), 3, "Next data set ID should be 3 after creating two data sets");
@@ -175,17 +159,13 @@ contract PDPVerifierDataSetCreateDeleteTest is MockFVMTest, PieceHelper {
175159

176160
// Test 1: Fails when sending not enough for sybil fee
177161
vm.expectRevert("sybil fee not met");
178-
pdpVerifier.addPieces{value: sybilFee - 1}(
179-
NEW_DATA_SET_SENTINEL, address(listener), new Cids.Cid[](0), abi.encode(empty, empty)
180-
);
162+
pdpVerifier.createDataSet{value: sybilFee - 1}(address(listener), empty);
181163

182164
// Test 2: Returns funds over the sybil fee back to the sender
183165
uint256 excessAmount = 1 ether;
184166
uint256 initialBalance = address(this).balance;
185167

186-
uint256 setId = pdpVerifier.addPieces{value: sybilFee + excessAmount}(
187-
NEW_DATA_SET_SENTINEL, address(listener), new Cids.Cid[](0), abi.encode(empty, empty)
188-
);
168+
uint256 setId = pdpVerifier.createDataSet{value: sybilFee + excessAmount}(address(listener), empty);
189169

190170
uint256 finalBalance = address(this).balance;
191171
uint256 refundedAmount = finalBalance - (initialBalance - sybilFee - excessAmount);

0 commit comments

Comments
 (0)