Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e0589c3
commit before rebase
parzival1821 Oct 10, 2025
f3c838c
Optimised the loop in validatePayment to loop over Proving Periods in…
parzival1821 Oct 8, 2025
204f4da
fixed small errors in updated algo inside validatePayment
parzival1821 Oct 8, 2025
a9419c2
updated abi and restructured validatePayment to prevent possible stak…
parzival1821 Oct 8, 2025
65186fc
implemented requested changes
parzival1821 Oct 9, 2025
4eac75b
stopped tracking foundry.lock
parzival1821 Oct 10, 2025
0b6bf57
commit before rebase
parzival1821 Oct 16, 2025
d857a69
made changes except adding the tests
parzival1821 Oct 17, 2025
a969679
remove foundry.lock and update abi
parzival1821 Oct 17, 2025
ab288c1
fixed mistake in _isPeriodProven , and fixed lint issues
parzival1821 Oct 17, 2025
b61a081
add changes and fix _findProvenEpochs
parzival1821 Oct 17, 2025
f724dea
make required changes
parzival1821 Oct 17, 2025
e3bddea
implemented required changes
parzival1821 Oct 17, 2025
3d78a36
revert submodules
wjmelements Oct 18, 2025
8ffc573
fix failing test,formatting, and some minor code quality improvements
parzival1821 Oct 18, 2025
78eeb8a
fixed a doc mistype in Errors.sol
parzival1821 Oct 20, 2025
df87fa7
fix documentation and reverse accidental submodule updation
parzival1821 Oct 20, 2025
7ddb183
cache activatonEpoch in validatePayment
parzival1821 Oct 20, 2025
34bdc4d
updated a few comments
parzival1821 Oct 21, 2025
01555fe
revert changes to forge-std, it now matches main
parzival1821 Oct 21, 2025
bc6b81a
Revert openzeppelin-contracts submodule to match main
parzival1821 Oct 22, 2025
85b716c
Update service_contracts/src/FilecoinWarmStorageService.sol
wjmelements Oct 22, 2025
8df221a
simplify
wjmelements Oct 22, 2025
6d5889f
doc
wjmelements Oct 22, 2025
abe64da
rm unused var
wjmelements Oct 22, 2025
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
3 changes: 2 additions & 1 deletion service_contracts/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ node_modules/

# Lock files
package-lock.json
foundry.lock

# Ignore IDEs
.idea
.idea
24 changes: 0 additions & 24 deletions service_contracts/abi/FilecoinWarmStorageService.abi.json
Original file line number Diff line number Diff line change
Expand Up @@ -401,30 +401,6 @@
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "isEpochProven",
"inputs": [
{
"name": "dataSetId",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "epoch",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "bool",
"internalType": "bool"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "migrate",
Expand Down
2 changes: 1 addition & 1 deletion service_contracts/lib/openzeppelin-contracts
Copy link
Contributor

Choose a reason for hiding this comment

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

you still haven't reverted your changes to the submodules

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My bad, fixed it now

6 changes: 5 additions & 1 deletion service_contracts/src/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,11 @@ library Errors {
/// @param railId The rail ID
error RailNotAssociated(uint256 railId);

/// @notice The epoch range is invalid (toEpoch must be > fromEpoch)
/// @notice The epoch range is invalid
/// @notice Will be emitted if any of the following conditions is NOT met:
/// @notice 1. fromEpoch must be less than toEpoch
/// @notice 2. toEpoch must be less than block number
/// @notice 3. toEpoch must be greater than the activation epoch
/// @param fromEpoch The starting epoch (exclusive)
/// @param toEpoch The ending epoch (inclusive)
error InvalidEpochRange(uint256 fromEpoch, uint256 toEpoch);
Expand Down
119 changes: 72 additions & 47 deletions service_contracts/src/FilecoinWarmStorageService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1141,43 +1141,6 @@ contract FilecoinWarmStorageService is
return (epoch - activationEpoch) / maxProvingPeriod;
}

/**
* @notice Checks if a specific epoch has been proven
* @dev Returns true only if the epoch belongs to a proven proving period
* @param dataSetId The ID of the data set to check
* @param epoch The epoch to check
* @return True if the epoch has been proven, false otherwise
*/
function isEpochProven(uint256 dataSetId, uint256 epoch) public view returns (bool) {
// Check if data set is active
if (provingActivationEpoch[dataSetId] == 0) {
return false;
}

// Check if this epoch is before activation
if (epoch < provingActivationEpoch[dataSetId]) {
return false;
}

// Check if this epoch is in the future (beyond current block)
if (epoch > block.number) {
return false;
}

// Get the period this epoch belongs to
uint256 periodId = getProvingPeriodForEpoch(dataSetId, epoch);

// Special case: current ongoing proving period
uint256 currentPeriod = getProvingPeriodForEpoch(dataSetId, block.number);
if (periodId == currentPeriod) {
// For the current period, check if it has been proven already
return provenThisPeriod[dataSetId];
}

// For past periods, check the provenPeriods bitmapping
return 0 != provenPeriods[dataSetId][periodId >> 8] & (1 << (periodId & 255));
}

function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
Expand Down Expand Up @@ -1470,7 +1433,8 @@ contract FilecoinWarmStorageService is
require(totalEpochsRequested > 0, Errors.InvalidEpochRange(fromEpoch, toEpoch));

// If proving wasn't ever activated for this data set, don't pay anything
if (provingActivationEpoch[dataSetId] == 0) {
uint256 activationEpoch = provingActivationEpoch[dataSetId];
if (activationEpoch == 0) {
return ValidationResult({
modifiedAmount: 0,
settleUpto: fromEpoch,
Expand All @@ -1482,15 +1446,8 @@ contract FilecoinWarmStorageService is
uint256 provenEpochCount = 0;
uint256 lastProvenEpoch = fromEpoch;

// Check each epoch in the range
for (uint256 epoch = fromEpoch + 1; epoch <= toEpoch; epoch++) {
bool isProven = isEpochProven(dataSetId, epoch);

if (isProven) {
provenEpochCount++;
lastProvenEpoch = epoch;
}
}
(provenEpochCount, lastProvenEpoch) =
_findProvenEpochs(dataSetId, fromEpoch, toEpoch, provenEpochCount, lastProvenEpoch, activationEpoch);

// If no epochs are proven, we can't settle anything
if (provenEpochCount == 0) {
Expand All @@ -1514,6 +1471,74 @@ contract FilecoinWarmStorageService is
});
}

function _findProvenEpochs(
uint256 dataSetId,
uint256 fromEpoch,
uint256 toEpoch,
uint256 provenEpochCount,
uint256 lastProvenEpoch,
uint256 activationEpoch
) internal view returns (uint256, uint256) {
if (toEpoch < activationEpoch) {
revert Errors.InvalidEpochRange(fromEpoch, toEpoch);
}
if (toEpoch > block.number) {
revert Errors.InvalidEpochRange(fromEpoch, toEpoch);
}
uint256 currentPeriod = getProvingPeriodForEpoch(dataSetId, block.number);

if (fromEpoch < activationEpoch - 1) {
fromEpoch = activationEpoch - 1;
}

uint256 startingPeriod = getProvingPeriodForEpoch(dataSetId, fromEpoch + 1);
uint256 endingPeriod = getProvingPeriodForEpoch(dataSetId, toEpoch);

// handle first period separately
uint256 startingPeriodDeadline = _calcPeriodDeadline(dataSetId, startingPeriod);

if (toEpoch < startingPeriodDeadline) {
// alternative way to check the same: `startingPeriod == endingPeriod`
if (_isPeriodProven(dataSetId, startingPeriod, currentPeriod)) {
provenEpochCount = (toEpoch - fromEpoch); // epochs: (`from + 1` -> `to`) (both inclusive)
lastProvenEpoch = toEpoch;
}
} else {
if (_isPeriodProven(dataSetId, startingPeriod, currentPeriod)) {
provenEpochCount += (startingPeriodDeadline - fromEpoch); // epochs: (`from + 1` -> `deadline`)
}

// now loop through the proving periods between endingPeriod and startingPeriod.
for (uint256 period = startingPeriod + 1; period < endingPeriod; period++) {
if (_isPeriodProven(dataSetId, period, currentPeriod)) {
provenEpochCount += maxProvingPeriod;
lastProvenEpoch = _calcPeriodDeadline(dataSetId, period);
}
}

// now handle the last period separately
if (_isPeriodProven(dataSetId, endingPeriod, currentPeriod)) {
// epochs to add: start from `start of current period` , go upto `toEpoch`. Note that `start of current period` is same as `deadline of previous period` + 1
provenEpochCount += (toEpoch - _calcPeriodDeadline(dataSetId, endingPeriod - 1));
lastProvenEpoch = toEpoch;
}
}

return (provenEpochCount, lastProvenEpoch);
}

function _isPeriodProven(uint256 dataSetId, uint256 periodId, uint256 currentPeriod) private view returns (bool) {
if (periodId == currentPeriod) {
return provenThisPeriod[dataSetId];
}
uint256 isProven = provenPeriods[dataSetId][periodId >> 8] & (1 << (periodId & 255));
return isProven != 0;
}

function _calcPeriodDeadline(uint256 dataSetId, uint256 periodId) private view returns (uint256) {
return provingActivationEpoch[dataSetId] + (periodId + 1) * maxProvingPeriod;
}

function railTerminated(uint256 railId, address terminator, uint256 endEpoch) external override {
require(msg.sender == paymentsContractAddress, Errors.CallerNotPayments(paymentsContractAddress, msg.sender));

Expand Down
Loading