diff --git a/.gas-snapshot b/.gas-snapshot index 4629d29..f124f9e 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1 +1,11 @@ -WakuRlnV2Test:test__ValidRegistration() (gas: 108661) \ No newline at end of file +WakuRlnV2Test:test__InvalidPaginationQuery__EndIndexGTIdCommitmentIndex() (gas: 13381) +WakuRlnV2Test:test__InvalidPaginationQuery__StartIndexGTEndIndex() (gas: 11225) +WakuRlnV2Test:test__InvalidRegistration__DuplicateIdCommitment() (gas: 92762) +WakuRlnV2Test:test__InvalidRegistration__FullTree() (gas: 95459) +WakuRlnV2Test:test__InvalidRegistration__InvalidIdCommitment__LargerThanField() (gas: 9926) +WakuRlnV2Test:test__InvalidRegistration__InvalidIdCommitment__Zero() (gas: 9139) +WakuRlnV2Test:test__InvalidRegistration__InvalidUserMessageLimit__LargerThanMax() (gas: 10147) +WakuRlnV2Test:test__InvalidRegistration__InvalidUserMessageLimit__Zero() (gas: 9242) +WakuRlnV2Test:test__ValidPaginationQuery(uint32) (runs: 1000, μ: 404876, ~: 132250) +WakuRlnV2Test:test__ValidRegistration(uint256,uint32) (runs: 1001, μ: 117450, ~: 117450) +WakuRlnV2Test:test__ValidRegistration__kats() (gas: 91849) \ No newline at end of file diff --git a/src/WakuRlnV2.sol b/src/WakuRlnV2.sol index ad03200..7fe3c3b 100644 --- a/src/WakuRlnV2.sol +++ b/src/WakuRlnV2.sol @@ -32,7 +32,7 @@ contract WakuRlnV2 { uint8 public constant DEPTH = 20; /// @notice The size of the merkle tree, i.e 2^depth - uint32 public immutable SET_SIZE; + uint32 public SET_SIZE; /// @notice The index of the next member to be registered uint32 public idCommitmentIndex = 0; @@ -64,9 +64,8 @@ contract WakuRlnV2 { _; } - modifier onlyValidUserMessageLimit(uint32 messageLimit) { - if (messageLimit > MAX_MESSAGE_LIMIT) revert InvalidUserMessageLimit(messageLimit); - if (messageLimit == 0) revert InvalidUserMessageLimit(messageLimit); + modifier onlyValidUserMessageLimit(uint32 userMessageLimit) { + if (!isValidUserMessageLimit(userMessageLimit)) revert InvalidUserMessageLimit(userMessageLimit); _; } @@ -116,6 +115,10 @@ contract WakuRlnV2 { return idCommitment != 0 && idCommitment < Q; } + function isValidUserMessageLimit(uint32 userMessageLimit) public view returns (bool) { + return userMessageLimit > 0 && userMessageLimit <= MAX_MESSAGE_LIMIT; + } + function indexToCommitment(uint32 index) public view returns (uint256) { return imtData.elements[LazyIMT.indexForElement(0, index)]; } diff --git a/test/WakuRlnV2.t.sol b/test/WakuRlnV2.t.sol index 4d86250..0284f04 100644 --- a/test/WakuRlnV2.t.sol +++ b/test/WakuRlnV2.t.sol @@ -1,15 +1,18 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.19 <0.9.0; -import { Test, console } from "forge-std/Test.sol"; +import { Test } from "forge-std/Test.sol"; +import { stdStorage, StdStorage } from "forge-std/Test.sol"; import { Deploy } from "../script/Deploy.s.sol"; import { DeploymentConfig } from "../script/DeploymentConfig.s.sol"; -import { WakuRlnV2 } from "../src/WakuRlnV2.sol"; +import "../src/WakuRlnV2.sol"; import { PoseidonT3 } from "poseidon-solidity/PoseidonT3.sol"; import { LazyIMT } from "@zk-kit/imt.sol/LazyIMT.sol"; contract WakuRlnV2Test is Test { + using stdStorage for StdStorage; + WakuRlnV2 internal w; DeploymentConfig internal deploymentConfig; @@ -20,7 +23,7 @@ contract WakuRlnV2Test is Test { (w, deploymentConfig) = deployment.run(); } - function test__ValidRegistration() external { + function test__ValidRegistration__kats() external { vm.pauseGasMetering(); uint256 idCommitment = 2; uint32 userMessageLimit = 2; @@ -45,4 +48,90 @@ contract WakuRlnV2Test is Test { ); vm.resumeGasMetering(); } + + function test__ValidRegistration(uint256 idCommitment, uint32 userMessageLimit) external { + vm.assume(w.isValidCommitment(idCommitment) && w.isValidUserMessageLimit(userMessageLimit)); + + assertEq(w.memberExists(idCommitment), false); + w.register(idCommitment, userMessageLimit); + uint256[] memory commitments = w.getCommitments(0, 1); + assertEq(commitments.length, 1); + uint256 rateCommitment = PoseidonT3.hash([idCommitment, userMessageLimit]); + assertEq(commitments[0], rateCommitment); + } + + function test__InvalidRegistration__InvalidIdCommitment__Zero() external { + uint256 idCommitment = 0; + uint32 userMessageLimit = 2; + vm.expectRevert(abi.encodeWithSelector(InvalidIdCommitment.selector, 0)); + w.register(idCommitment, userMessageLimit); + } + + function test__InvalidRegistration__InvalidIdCommitment__LargerThanField() external { + uint256 idCommitment = w.Q() + 1; + uint32 userMessageLimit = 2; + vm.expectRevert(abi.encodeWithSelector(InvalidIdCommitment.selector, idCommitment)); + w.register(idCommitment, userMessageLimit); + } + + function test__InvalidRegistration__InvalidUserMessageLimit__Zero() external { + uint256 idCommitment = 2; + uint32 userMessageLimit = 0; + vm.expectRevert(abi.encodeWithSelector(InvalidUserMessageLimit.selector, 0)); + w.register(idCommitment, userMessageLimit); + } + + function test__InvalidRegistration__InvalidUserMessageLimit__LargerThanMax() external { + uint256 idCommitment = 2; + uint32 userMessageLimit = w.MAX_MESSAGE_LIMIT() + 1; + vm.expectRevert(abi.encodeWithSelector(InvalidUserMessageLimit.selector, userMessageLimit)); + w.register(idCommitment, userMessageLimit); + } + + function test__InvalidRegistration__DuplicateIdCommitment() external { + uint256 idCommitment = 2; + uint32 userMessageLimit = 2; + w.register(idCommitment, userMessageLimit); + vm.expectRevert(DuplicateIdCommitment.selector); + w.register(idCommitment, userMessageLimit); + } + + function test__InvalidRegistration__FullTree() external { + uint32 userMessageLimit = 2; + // we modify the set_size to be small so the test can run faster + stdstore.target(address(w)).sig("SET_SIZE()").checked_write(1); + vm.pauseGasMetering(); + w.register(1, userMessageLimit); + vm.resumeGasMetering(); + vm.expectRevert(FullTree.selector); + w.register(2, userMessageLimit); + } + + function test__InvalidPaginationQuery__StartIndexGTEndIndex() external { + vm.expectRevert(abi.encodeWithSelector(InvalidPaginationQuery.selector, 1, 0)); + w.getCommitments(1, 0); + } + + function test__InvalidPaginationQuery__EndIndexGTIdCommitmentIndex() external { + vm.expectRevert(abi.encodeWithSelector(InvalidPaginationQuery.selector, 0, 2)); + w.getCommitments(0, 2); + } + + function test__ValidPaginationQuery(uint32 idCommitmentsLength) external { + vm.assume(idCommitmentsLength > 0 && idCommitmentsLength <= 100); + uint32 userMessageLimit = 2; + + vm.pauseGasMetering(); + for (uint256 i = 0; i < idCommitmentsLength; i++) { + w.register(i + 1, userMessageLimit); + } + vm.resumeGasMetering(); + + uint256[] memory commitments = w.getCommitments(0, idCommitmentsLength); + assertEq(commitments.length, idCommitmentsLength); + for (uint256 i = 0; i < idCommitmentsLength; i++) { + uint256 rateCommitment = PoseidonT3.hash([i + 1, userMessageLimit]); + assertEq(commitments[i], rateCommitment); + } + } }