Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion service_contracts/lib/fws-payments
68 changes: 65 additions & 3 deletions service_contracts/src/FilecoinWarmStorageService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ contract FilecoinWarmStorageService is
string[] pieceMetadata; // Array of metadata for each piece
uint256 clientDataSetId; // ClientDataSetID
bool withCDN; // Whether the data set is registered for CDN add-on
uint256 paymentEndEpoch; // 0 if payment is not terminated
}

// Decode structure for data set creation extra data
Expand Down Expand Up @@ -198,6 +199,7 @@ contract FilecoinWarmStorageService is
/// @dev This fee is burned to prevent spam registrations
uint256 public constant SP_REGISTRATION_FEE = 1 ether;
// Modifier to ensure only the PDP verifier contract can call certain functions

modifier onlyPDPVerifier() {
require(msg.sender == pdpVerifierAddress, "Caller is not the PDP verifier");
_;
Expand Down Expand Up @@ -530,6 +532,7 @@ contract FilecoinWarmStorageService is
IPDPTypes.PieceData[] memory pieceData,
bytes calldata extraData
) external onlyPDPVerifier {
requirePaymentNotTerminated(dataSetId);
// Verify the data set exists in our mapping
DataSetInfo storage info = dataSetInfo[dataSetId];
require(info.pdpRailId != 0, "Data set not registered with payment system");
Expand Down Expand Up @@ -558,6 +561,7 @@ contract FilecoinWarmStorageService is
external
onlyPDPVerifier
{
requirePaymentNotBeyondEndEpoch(dataSetId);
// Verify the data set exists in our mapping
DataSetInfo storage info = dataSetInfo[dataSetId];
require(info.pdpRailId != 0, "Data set not registered with payment system");
Expand Down Expand Up @@ -586,6 +590,7 @@ contract FilecoinWarmStorageService is
uint256, /*seed*/
uint256 challengeCount
) external onlyPDPVerifier {
requirePaymentNotBeyondEndEpoch(dataSetId);
if (provenThisPeriod[dataSetId]) {
revert("Only one proof of possession allowed per proving period. Open a new proving period.");
}
Expand Down Expand Up @@ -619,6 +624,7 @@ contract FilecoinWarmStorageService is
external
onlyPDPVerifier
{
requirePaymentNotBeyondEndEpoch(dataSetId);
// initialize state for new data set
if (provingDeadlines[dataSetId] == NO_PROVING_DEADLINE) {
uint256 firstDeadline = block.number + getMaxProvingPeriod();
Expand Down Expand Up @@ -717,6 +723,44 @@ contract FilecoinWarmStorageService is
emit DataSetStorageProviderChanged(dataSetId, oldStorageProvider, newStorageProvider);
}

function terminateDataSetPayment(uint256 dataSetId) external {
DataSetInfo storage info = dataSetInfo[dataSetId];
require(info.pdpRailId != 0, "invalid dataset ID");

// Check if already terminated
require(info.paymentEndEpoch == 0, "dataset payment already terminated");

// Check authorization
require(
msg.sender == info.payer || msg.sender == info.payee, "Only payer or payee can terminate data set payment"
);

Payments payments = Payments(paymentsContractAddress);

payments.terminateRail(info.pdpRailId);

if (info.withCDN) {
payments.terminateRail(info.cacheMissRailId);
payments.terminateRail(info.cdnRailId);
}
}

function requirePaymentNotTerminated(uint256 dataSetId) internal view {
DataSetInfo storage info = dataSetInfo[dataSetId];
require(info.pdpRailId != 0, "invalid dataset ID");
require(info.paymentEndEpoch == 0, "data set payment has already been terminated");
}

function requirePaymentNotBeyondEndEpoch(uint256 dataSetId) internal view {
DataSetInfo storage info = dataSetInfo[dataSetId];
if (info.paymentEndEpoch != 0) {
require(
block.number <= info.paymentEndEpoch,
"data set is beyond its payment end epoch: remove data set to make progress"
);
}
}

function updatePaymentRates(uint256 dataSetId, uint256 leafCount) internal {
// Revert if no payment rail is configured for this data set
require(dataSetInfo[dataSetId].pdpRailId != 0, "No PDP payment rail configured");
Expand Down Expand Up @@ -1173,10 +1217,10 @@ contract FilecoinWarmStorageService is

// Check if registration is already pending
require(pendingProviders[msg.sender].registeredAt == 0, "Registration already pending");

// Burn one-time fee to register
require(msg.value == SP_REGISTRATION_FEE, "Incorrect registration fee");
(bool sent, ) = BURN_ADDRESS.call{value: msg.value}("");
(bool sent,) = BURN_ADDRESS.call{value: msg.value}("");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unrelated

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a forge fmt

require(sent, "Burn failed");

// Store pending registration
Expand Down Expand Up @@ -1329,7 +1373,8 @@ contract FilecoinWarmStorageService is
metadata: storageInfo.metadata,
pieceMetadata: storageInfo.pieceMetadata,
clientDataSetId: storageInfo.clientDataSetId,
withCDN: storageInfo.withCDN
withCDN: storageInfo.withCDN,
paymentEndEpoch: storageInfo.paymentEndEpoch
});
}
return dataSets;
Expand Down Expand Up @@ -1407,4 +1452,21 @@ contract FilecoinWarmStorageService is
note: ""
});
}

function railTerminated(uint256 railId, address terminator, uint256 endEpoch) external override {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my understanding: After terminateDataSetPayment, this method will now be called up to three times for one data set, once per payment rail. The first call will change the state paymentEndEpoch = endEpoch, the other two calls will be noops and safe to ignore. Right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juliangruber That is correct !

require(msg.sender == paymentsContractAddress, "Caller is not the Payments contract");

if (terminator != address(this)) {
revert(
"cannot terminate rail using Payments contract: call `terminateDataSetPayment` on the service contract"
);
}

uint256 dataSetId = railToDataSet[railId];
require(dataSetId != 0, "data set does not exist for given rail");
DataSetInfo storage info = dataSetInfo[dataSetId];
if (info.paymentEndEpoch == 0) {
info.paymentEndEpoch = endEpoch;
}
}
}
Loading