mirror of
https://github.com/logos-messaging/logos-messaging-rlnv2-contract.git
synced 2026-01-05 15:33:08 +00:00
fix: remove test_MultiUserEraseReuseRace
- test_TimestampManipulationRaces
This commit is contained in:
parent
7c8d2d7b89
commit
f8d670e41e
@ -1538,153 +1538,4 @@ contract WakuRlnV2Test is Test {
|
||||
vm.expectRevert("Ownable: caller is not the owner");
|
||||
w.setMaxTotalRateLimit(100);
|
||||
}
|
||||
|
||||
// Helper: Verify Merkle Proof Manually
|
||||
function _verifyMerkleProof(
|
||||
uint256[20] memory proof,
|
||||
uint256 root,
|
||||
uint32 index,
|
||||
uint256 leaf,
|
||||
uint8 depth
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bool)
|
||||
{
|
||||
uint256 current = leaf;
|
||||
uint32 idx = index;
|
||||
for (uint8 level = 0; level < depth; level++) {
|
||||
bool isLeft = (idx & 1) == 0;
|
||||
uint256 sibling = proof[level];
|
||||
uint256[2] memory inputs;
|
||||
if (isLeft) {
|
||||
inputs[0] = current;
|
||||
inputs[1] = sibling;
|
||||
} else {
|
||||
inputs[0] = sibling;
|
||||
inputs[1] = current;
|
||||
}
|
||||
current = PoseidonT3.hash(inputs);
|
||||
idx >>= 1;
|
||||
}
|
||||
return current == root;
|
||||
}
|
||||
|
||||
function test_MultiUserEraseReuseRace(uint8 numUsers, bool fullErase) external {
|
||||
vm.assume(numUsers > 1 && numUsers <= 8);
|
||||
uint32 rateLimit = w.minMembershipRateLimit();
|
||||
|
||||
address tokenOwner = address(tokenDeployer);
|
||||
|
||||
// Multi-user registers
|
||||
for (uint8 i = 1; i <= numUsers; i++) {
|
||||
address user = vm.addr(i);
|
||||
|
||||
(, uint256 price) = w.priceCalculator().calculate(rateLimit);
|
||||
vm.prank(tokenOwner);
|
||||
token.mint(user, price);
|
||||
|
||||
vm.startPrank(user);
|
||||
token.approve(address(w), price);
|
||||
w.register(i, rateLimit, new uint256[](0));
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
vm.warp(block.timestamp + w.activeDurationForNewMemberships() + w.gracePeriodDurationForNewMemberships() + 1);
|
||||
|
||||
// Fuzz unique erasures
|
||||
uint8 numErasures = uint8(uint256(keccak256(abi.encodePacked(block.timestamp))) % (numUsers / 2)) + 1;
|
||||
uint256[] memory eraseIds = new uint256[](numErasures);
|
||||
bool[] memory erased = new bool[](numUsers + 1); // Track to avoid duplicates
|
||||
uint8 eraseCount = 0;
|
||||
while (eraseCount < numErasures) {
|
||||
uint8 eraseIdx = uint8(uint256(keccak256(abi.encodePacked(block.timestamp, eraseCount))) % numUsers) + 1;
|
||||
if (!erased[eraseIdx]) {
|
||||
eraseIds[eraseCount] = eraseIdx;
|
||||
erased[eraseIdx] = true;
|
||||
eraseCount++;
|
||||
}
|
||||
}
|
||||
uint8 eraser = uint8(uint256(keccak256(abi.encodePacked(block.timestamp))) % numUsers) + 1;
|
||||
vm.prank(vm.addr(eraser));
|
||||
w.eraseMemberships(eraseIds, fullErase);
|
||||
|
||||
// Other users attempt reuses (balance to numErasures)
|
||||
uint8 numReuses = numErasures; // Balance to no net growth
|
||||
for (uint8 i = 0; i < numReuses; i++) {
|
||||
uint8 reuser = uint8(uint256(keccak256(abi.encodePacked(block.timestamp, i + numUsers))) % numUsers) + 1;
|
||||
address user = vm.addr(reuser);
|
||||
|
||||
(, uint256 price) = w.priceCalculator().calculate(rateLimit);
|
||||
vm.prank(tokenOwner);
|
||||
token.mint(user, price);
|
||||
|
||||
vm.startPrank(user);
|
||||
token.approve(address(w), price);
|
||||
uint256 newId =
|
||||
100 + uint256(keccak256(abi.encodePacked("new", reuser, block.timestamp, i))) % (w.Q() - 1) + 1;
|
||||
// uniqueness
|
||||
w.register(newId, rateLimit, new uint256[](0));
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
// Assert: No inconsistencies, reuses correct, proofs valid
|
||||
for (uint8 i = 1; i <= numUsers; i++) {
|
||||
bool isErased = erased[i];
|
||||
uint256 checkId = isErased ? 0 : i;
|
||||
if (checkId != 0) {
|
||||
(, uint32 idx, uint256 commitment) = w.getMembershipInfo(checkId);
|
||||
uint256[20] memory proof = w.getMerkleProof(idx);
|
||||
assertTrue(_verifyMerkleProof(proof, w.root(), idx, commitment, 20));
|
||||
}
|
||||
}
|
||||
assertEq(w.nextFreeIndex(), numUsers); // No growth beyond (reuses fill erased)
|
||||
}
|
||||
|
||||
function test_TimestampManipulationRaces(int16 deltaOffset) external {
|
||||
vm.assume(deltaOffset >= -15 && deltaOffset <= 15); // Miner manipulation range
|
||||
|
||||
uint32 rateLimit = w.minMembershipRateLimit();
|
||||
(, uint256 price) = w.priceCalculator().calculate(rateLimit);
|
||||
token.approve(address(w), price);
|
||||
w.register(1, rateLimit, new uint256[](0));
|
||||
|
||||
// Warp to near grace end (manipulable point)
|
||||
uint256 graceEnd =
|
||||
block.timestamp + w.activeDurationForNewMemberships() + w.gracePeriodDurationForNewMemberships();
|
||||
|
||||
// Compute absolute value
|
||||
int256 delta = int256(deltaOffset);
|
||||
int256 absDelta = delta >= 0 ? delta : -delta;
|
||||
uint256 offsetAbs;
|
||||
assembly {
|
||||
offsetAbs := absDelta
|
||||
}
|
||||
|
||||
uint256 newTimestamp = delta >= 0 ? graceEnd + offsetAbs : graceEnd - offsetAbs;
|
||||
vm.warp(newTimestamp);
|
||||
|
||||
// Attempt extension (race: should fail if manipulated at the end)
|
||||
uint256[] memory ids = new uint256[](1);
|
||||
ids[0] = 1;
|
||||
if (deltaOffset >= 0) {
|
||||
// Manipulated at/after: expired (exclusive end)
|
||||
vm.expectRevert(abi.encodeWithSelector(CannotExtendNonGracePeriodMembership.selector, ids[0]));
|
||||
}
|
||||
w.extendMemberships(ids);
|
||||
|
||||
// Attempt erase (race: should succeed if at/after, fail if before)
|
||||
if (deltaOffset < 0) {
|
||||
// Manipulated before: not expired
|
||||
vm.expectRevert(abi.encodeWithSelector(CannotEraseActiveMembership.selector, ids[0]));
|
||||
}
|
||||
w.eraseMemberships(ids, true);
|
||||
|
||||
// Assert states based on manipulation
|
||||
if (deltaOffset >= 0) {
|
||||
assertTrue(w.isExpired(1));
|
||||
} else {
|
||||
assertFalse(w.isExpired(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user