Skip to content

Commit 7e78964

Browse files
authored
perf(provenPeriods): bitmap (#258)
Reviewer @rvagg @Kubuxu Closes #257 This should reduce the proof storage growth by a factor of 256. If the proving period is 1 day, and the deal lasts 1 year, this mapping will use 2 slots instead of 356. #### Changes * Change provenPeriods to bitmap
1 parent 8cece67 commit 7e78964

File tree

5 files changed

+53
-14
lines changed

5 files changed

+53
-14
lines changed

service_contracts/foundry.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ fs_permissions = [{ access = "read", path = "./test" }]
2727
[lint]
2828
exclude_lints = [
2929
"asm-keccak256",
30+
"incorrect-shift",
3031
"mixed-case-function",
3132
"mixed-case-variable",
3233
"pascal-case-struct",

service_contracts/src/FilecoinWarmStorageService.sol

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,8 @@ contract FilecoinWarmStorageService is
231231
// Commission rate
232232
uint256 public serviceCommissionBps;
233233

234-
// Track which proving periods have valid proofs
235-
mapping(uint256 dataSetId => mapping(uint256 periodId => bool)) private provenPeriods;
234+
// Track which proving periods have valid proofs with bitmap
235+
mapping(uint256 dataSetId => mapping(uint256 periodId => uint256)) private provenPeriods;
236236
// Track when proving was first activated for each data set
237237
mapping(uint256 dataSetId => uint256) private provingActivationEpoch;
238238

@@ -818,7 +818,7 @@ contract FilecoinWarmStorageService is
818818
}
819819
provenThisPeriod[dataSetId] = true;
820820
uint256 currentPeriod = getProvingPeriodForEpoch(dataSetId, block.number);
821-
provenPeriods[dataSetId][currentPeriod] = true;
821+
provenPeriods[dataSetId][currentPeriod >> 8] |= 1 << (currentPeriod & 255);
822822
}
823823

824824
// nextProvingPeriod checks for unsubmitted proof in which case it emits a fault event
@@ -893,12 +893,12 @@ contract FilecoinWarmStorageService is
893893
}
894894

895895
// Record the status of the current/previous proving period that's ending
896-
if (provingDeadlines[dataSetId] != NO_PROVING_DEADLINE) {
896+
if (provingDeadlines[dataSetId] != NO_PROVING_DEADLINE && provenThisPeriod[dataSetId]) {
897897
// Determine the period ID that just completed
898898
uint256 completedPeriodId = getProvingPeriodForEpoch(dataSetId, provingDeadlines[dataSetId] - 1);
899899

900900
// Record whether this period was proven
901-
provenPeriods[dataSetId][completedPeriodId] = provenThisPeriod[dataSetId];
901+
provenPeriods[dataSetId][completedPeriodId >> 8] |= 1 << (completedPeriodId & 255);
902902
}
903903

904904
provingDeadlines[dataSetId] = nextDeadline;
@@ -1190,8 +1190,8 @@ contract FilecoinWarmStorageService is
11901190
return provenThisPeriod[dataSetId];
11911191
}
11921192

1193-
// For past periods, check the provenPeriods mapping
1194-
return provenPeriods[dataSetId][periodId];
1193+
// For past periods, check the provenPeriods bitmapping
1194+
return 0 != provenPeriods[dataSetId][periodId >> 8] & (1 << (periodId & 255));
11951195
}
11961196

11971197
function max(uint256 a, uint256 b) internal pure returns (uint256) {

service_contracts/src/lib/FilecoinWarmStorageServiceStateInternalLibrary.sol

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,13 @@ library FilecoinWarmStorageServiceStateInternalLibrary {
148148
view
149149
returns (bool)
150150
{
151-
return service.extsload(
152-
keccak256(abi.encode(periodId, keccak256(abi.encode(dataSetId, StorageLayout.PROVEN_PERIODS_SLOT))))
153-
) != bytes32(0);
151+
return uint256(
152+
service.extsload(
153+
keccak256(
154+
abi.encode(periodId >> 8, keccak256(abi.encode(dataSetId, StorageLayout.PROVEN_PERIODS_SLOT)))
155+
)
156+
)
157+
) & (1 << (periodId & 255)) != 0;
154158
}
155159

156160
function provingActivationEpoch(FilecoinWarmStorageService service, uint256 dataSetId)

service_contracts/src/lib/FilecoinWarmStorageServiceStateLibrary.sol

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,13 @@ library FilecoinWarmStorageServiceStateLibrary {
144144
view
145145
returns (bool)
146146
{
147-
return service.extsload(
148-
keccak256(abi.encode(periodId, keccak256(abi.encode(dataSetId, StorageLayout.PROVEN_PERIODS_SLOT))))
149-
) != bytes32(0);
147+
return uint256(
148+
service.extsload(
149+
keccak256(
150+
abi.encode(periodId >> 8, keccak256(abi.encode(dataSetId, StorageLayout.PROVEN_PERIODS_SLOT)))
151+
)
152+
)
153+
) & (1 << (periodId & 255)) != 0;
150154
}
151155

152156
function provingActivationEpoch(FilecoinWarmStorageService service, uint256 dataSetId)

service_contracts/test/FilecoinWarmStorageService.t.sol

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {Cids} from "@pdp/Cids.sol";
99
import {MyERC1967Proxy} from "@pdp/ERC1967Proxy.sol";
1010
import {SessionKeyRegistry} from "@session-key-registry/SessionKeyRegistry.sol";
1111

12-
import {FilecoinWarmStorageService} from "../src/FilecoinWarmStorageService.sol";
12+
import {CHALLENGES_PER_PROOF, FilecoinWarmStorageService} from "../src/FilecoinWarmStorageService.sol";
1313
import {FilecoinWarmStorageServiceStateView} from "../src/FilecoinWarmStorageServiceStateView.sol";
1414
import {Payments} from "@fws-payments/Payments.sol";
1515
import {MockERC20, MockPDPVerifier} from "./mocks/SharedMocks.sol";
@@ -1168,6 +1168,36 @@ contract FilecoinWarmStorageServiceTest is Test {
11681168
assertEq(dataSet.payee, sp1, "Payee should remain unchanged");
11691169
}
11701170

1171+
function testProvenPeriods() public {
1172+
uint256 testDataSetId = createDataSetForServiceProviderTest(sp1, client, "Test Data Set");
1173+
for (uint256 i = 0; i < 2049; i++) {
1174+
assertFalse(viewContract.provenPeriods(testDataSetId, i));
1175+
}
1176+
(
1177+
uint64 maxProvingPeriod,
1178+
uint256 challengeWindowSize,
1179+
uint256 challengesPerProof,
1180+
uint256 initChallengeWindowStart
1181+
) = viewContract.getPDPConfig();
1182+
vm.startPrank(address(mockPDPVerifier));
1183+
pdpServiceWithPayments.nextProvingPeriod(testDataSetId, vm.getBlockNumber() + maxProvingPeriod, 100, "");
1184+
vm.roll(vm.getBlockNumber() + maxProvingPeriod - challengeWindowSize);
1185+
for (uint256 i = 0; i < 2049; i++) {
1186+
assertFalse(viewContract.provenPeriods(testDataSetId, i));
1187+
pdpServiceWithPayments.possessionProven(testDataSetId, 100, 12345, CHALLENGES_PER_PROOF);
1188+
assertTrue(viewContract.provenPeriods(testDataSetId, i));
1189+
1190+
vm.roll(vm.getBlockNumber() + challengeWindowSize);
1191+
pdpServiceWithPayments.nextProvingPeriod(testDataSetId, vm.getBlockNumber() + maxProvingPeriod, 100, "");
1192+
vm.roll(vm.getBlockNumber() + maxProvingPeriod - challengeWindowSize);
1193+
}
1194+
vm.stopPrank();
1195+
1196+
for (uint256 i = 0; i < 2049; i++) {
1197+
assertTrue(viewContract.provenPeriods(testDataSetId, i));
1198+
}
1199+
}
1200+
11711201
// Data Set Payment Termination Tests
11721202

11731203
function testTerminateServiceLifecycle() public {

0 commit comments

Comments
 (0)