Merge pull request #3 from waku-org/waku-rln-registry

feat: waku rln registry contract to enable autosharding
This commit is contained in:
Aaryamann Challani 2023-08-16 12:34:58 +05:30 committed by GitHub
commit 6188737f78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 2341 additions and 22 deletions

View File

@ -2,13 +2,17 @@
pragma solidity 0.8.15; pragma solidity 0.8.15;
import {IPoseidonHasher} from "rln-contract/PoseidonHasher.sol"; import {IPoseidonHasher} from "rln-contract/PoseidonHasher.sol";
import {RlnBase, DuplicateIdCommitment} from "rln-contract/RlnBase.sol"; import {RlnBase, DuplicateIdCommitment, FullTree} from "rln-contract/RlnBase.sol";
import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol"; import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol";
error NotImplemented(); error NotImplemented();
contract WakuRln is Ownable, RlnBase { contract WakuRln is Ownable, RlnBase {
constructor(address _poseidonHasher) Ownable() RlnBase(0, 20, _poseidonHasher, address(0)) {} uint16 public immutable contractIndex;
constructor(address _poseidonHasher, uint16 _contractIndex) Ownable() RlnBase(0, 20, _poseidonHasher, address(0)) {
contractIndex = _contractIndex;
}
/// Registers a member /// Registers a member
/// @param idCommitment The idCommitment of the member /// @param idCommitment The idCommitment of the member
@ -21,7 +25,7 @@ contract WakuRln is Ownable, RlnBase {
idCommitmentIndex += 1; idCommitmentIndex += 1;
} }
function register(uint256[] memory idCommitments) external onlyOwner { function register(uint256[] calldata idCommitments) external onlyOwner {
uint256 len = idCommitments.length; uint256 len = idCommitments.length;
for (uint256 i = 0; i < len;) { for (uint256 i = 0; i < len;) {
_register(idCommitments[i]); _register(idCommitments[i]);
@ -41,6 +45,7 @@ contract WakuRln is Ownable, RlnBase {
function _validateRegistration(uint256 idCommitment) internal view override { function _validateRegistration(uint256 idCommitment) internal view override {
if (members[idCommitment] != 0) revert DuplicateIdCommitment(); if (members[idCommitment] != 0) revert DuplicateIdCommitment();
if (idCommitmentIndex >= SET_SIZE) revert FullTree();
} }
function _validateSlash(uint256 idCommitment, address payable receiver, uint256[8] calldata proof) function _validateSlash(uint256 idCommitment, address payable receiver, uint256[8] calldata proof)

View File

@ -0,0 +1,86 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import {WakuRln} from "./WakuRln.sol";
import {IPoseidonHasher} from "rln-contract/PoseidonHasher.sol";
import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol";
error StorageAlreadyExists(address storageAddress);
error NoStorageContractAvailable();
error IncompatibleStorage();
error IncompatibleStorageIndex();
contract WakuRlnRegistry is Ownable {
uint16 public nextStorageIndex;
mapping(uint16 => address) public storages;
uint16 public usingStorageIndex = 0;
IPoseidonHasher public immutable poseidonHasher;
event NewStorageContract(uint16 index, address storageAddress);
modifier onlyUsableStorage() {
if (usingStorageIndex >= nextStorageIndex) revert NoStorageContractAvailable();
_;
}
constructor(address _poseidonHasher) Ownable() {
poseidonHasher = IPoseidonHasher(_poseidonHasher);
}
function _insertIntoStorageMap(address storageAddress) internal {
storages[nextStorageIndex] = storageAddress;
emit NewStorageContract(nextStorageIndex, storageAddress);
nextStorageIndex += 1;
}
function registerStorage(address storageAddress) external onlyOwner {
if (storages[nextStorageIndex] != address(0)) revert StorageAlreadyExists(storageAddress);
WakuRln wakuRln = WakuRln(storageAddress);
if (wakuRln.poseidonHasher() != poseidonHasher) revert IncompatibleStorage();
if (wakuRln.contractIndex() != nextStorageIndex) revert IncompatibleStorageIndex();
_insertIntoStorageMap(storageAddress);
}
function newStorage() external onlyOwner {
WakuRln newStorageContract = new WakuRln(address(poseidonHasher), nextStorageIndex);
_insertIntoStorageMap(address(newStorageContract));
}
function register(uint256[] calldata commitments) external payable onlyUsableStorage {
// iteratively check if the storage contract is full, and increment the usingStorageIndex if it is
while (true) {
try WakuRln(storages[usingStorageIndex]).register(commitments) {
break;
} catch (bytes memory err) {
if (keccak256(err) != keccak256(abi.encodeWithSignature("FullTree()"))) {
assembly {
revert(add(32, err), mload(err))
}
// when there are no further storage contracts available, revert
} else if (usingStorageIndex + 1 >= nextStorageIndex) {
revert NoStorageContractAvailable();
}
usingStorageIndex += 1;
}
}
}
function register(uint16 storageIndex, uint256[] calldata commitments) external payable {
if (storageIndex >= nextStorageIndex) revert NoStorageContractAvailable();
WakuRln(storages[storageIndex]).register(commitments);
}
function register(uint16 storageIndex, uint256 commitment) external payable {
if (storageIndex >= nextStorageIndex) revert NoStorageContractAvailable();
// optimize the gas used below
uint256[] memory commitments = new uint256[](1);
commitments[0] = commitment;
WakuRln(storages[storageIndex]).register(commitments);
}
function forceProgress() external onlyOwner onlyUsableStorage {
usingStorageIndex += 1;
}
}

View File

@ -10,7 +10,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const poseidonHasherAddress = (await deployments.get("PoseidonHasher")) const poseidonHasherAddress = (await deployments.get("PoseidonHasher"))
.address; .address;
await deploy("WakuRln", { await deploy("WakuRlnRegistry", {
from: deployer, from: deployer,
log: true, log: true,
args: [poseidonHasherAddress], args: [poseidonHasherAddress],
@ -18,5 +18,5 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
}; };
export default func; export default func;
func.tags = ["WakuRln"]; func.tags = ["WakuRlnRegistry"];
func.dependencies = ["PoseidonHasher"]; func.dependencies = ["PoseidonHasher"];

45
deploy/003_deploy_rln.ts Normal file
View File

@ -0,0 +1,45 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction, DeploymentSubmission } from "hardhat-deploy/types";
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployments, getUnnamedAccounts } = hre;
const [deployer] = await getUnnamedAccounts();
const wakuRlnRegistry = await deployments.get("WakuRlnRegistry");
const registryContract = new hre.ethers.Contract(
wakuRlnRegistry.address,
wakuRlnRegistry.abi,
hre.ethers.provider.getSigner(deployer)
);
const indexOfStorageToBeDeployed = await registryContract.nextStorageIndex();
const tx = await registryContract.newStorage();
await tx.wait();
const poseidonHasherAddress = (await deployments.get("PoseidonHasher"))
.address;
const storageAddress = await registryContract.storages(
indexOfStorageToBeDeployed
);
const extendedArtifact = await deployments.getExtendedArtifact("WakuRln");
console.log("Storage address: ", storageAddress);
const d: DeploymentSubmission = {
abi: extendedArtifact.abi,
address: storageAddress,
args: [poseidonHasherAddress, indexOfStorageToBeDeployed],
bytecode: extendedArtifact.bytecode,
deployedBytecode: extendedArtifact.deployedBytecode,
receipt: tx,
transactionHash: tx.hash,
metadata: extendedArtifact.metadata,
solcInput: extendedArtifact.solcInput,
devdoc: extendedArtifact.devdoc,
};
console.log(d);
deployments.save(`WakuRlnStorage_${indexOfStorageToBeDeployed}`, d);
};
export default func;
func.dependencies = ["WakuRlnRegistry"];

View File

@ -334,6 +334,861 @@
"type": "function" "type": "function"
} }
] ]
},
"WakuRlnRegistry": {
"address": "0x50D658a2ab7f66f4B73E27e8731B8b13Cd06Df8A",
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "_poseidonHasher",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "string",
"name": "reason",
"type": "string"
}
],
"name": "FailedToRegister",
"type": "error"
},
{
"inputs": [],
"name": "NoStorageContractAvailable",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "storageAddress",
"type": "address"
}
],
"name": "StorageAlreadyExists",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint16",
"name": "index",
"type": "uint16"
},
{
"indexed": false,
"internalType": "address",
"name": "storageAddress",
"type": "address"
}
],
"name": "NewStorageContract",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"inputs": [],
"name": "newStorage",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "nextStorageIndex",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "poseidonHasher",
"outputs": [
{
"internalType": "contract IPoseidonHasher",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "commitment",
"type": "uint256"
}
],
"name": "register",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "storageAddress",
"type": "address"
}
],
"name": "registerStorage",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"name": "storages",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "usingStorageIndex",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
}
]
},
"WakuRlnStorage_0": {
"address": "0x02c233d3899c3A435631AC857DAD5555F4f9656C",
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "_poseidonHasher",
"type": "address"
},
{
"internalType": "uint16",
"name": "_contractIndex",
"type": "uint16"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "DuplicateIdCommitment",
"type": "error"
},
{
"inputs": [],
"name": "NotImplemented",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "idCommitment",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "MemberRegistered",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "idCommitment",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "MemberWithdrawn",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"inputs": [],
"name": "DEPTH",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MEMBERSHIP_DEPOSIT",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "SET_SIZE",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "contractIndex",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "idCommitmentIndex",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "members",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "poseidonHasher",
"outputs": [
{
"internalType": "contract IPoseidonHasher",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256[]",
"name": "idCommitments",
"type": "uint256[]"
}
],
"name": "register",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "idCommitment",
"type": "uint256"
}
],
"name": "register",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "idCommitment",
"type": "uint256"
},
{
"internalType": "address payable",
"name": "receiver",
"type": "address"
},
{
"internalType": "uint256[8]",
"name": "proof",
"type": "uint256[8]"
}
],
"name": "slash",
"outputs": [],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "stakedAmounts",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "verifier",
"outputs": [
{
"internalType": "contract IVerifier",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "withdraw",
"outputs": [],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "withdrawalBalance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]
},
"WakuRlnStorage_1": {
"address": "0x662Be55E75c829A03c52CDba4Ab7dAde4e1be8a9",
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "_poseidonHasher",
"type": "address"
},
{
"internalType": "uint16",
"name": "_contractIndex",
"type": "uint16"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "DuplicateIdCommitment",
"type": "error"
},
{
"inputs": [],
"name": "NotImplemented",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "idCommitment",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "MemberRegistered",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "idCommitment",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "MemberWithdrawn",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"inputs": [],
"name": "DEPTH",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MEMBERSHIP_DEPOSIT",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "SET_SIZE",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "contractIndex",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "idCommitmentIndex",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "members",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "poseidonHasher",
"outputs": [
{
"internalType": "contract IPoseidonHasher",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256[]",
"name": "idCommitments",
"type": "uint256[]"
}
],
"name": "register",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "idCommitment",
"type": "uint256"
}
],
"name": "register",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "idCommitment",
"type": "uint256"
},
{
"internalType": "address payable",
"name": "receiver",
"type": "address"
},
{
"internalType": "uint256[8]",
"name": "proof",
"type": "uint256[8]"
}
],
"name": "slash",
"outputs": [],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "stakedAmounts",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "verifier",
"outputs": [
{
"internalType": "contract IVerifier",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "withdraw",
"outputs": [],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "withdrawalBalance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]
} }
} }
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -8,10 +8,16 @@ error NotImplemented()
## WakuRln ## WakuRln
### contractIndex
```solidity
uint16 contractIndex
```
### constructor ### constructor
```solidity ```solidity
constructor(address _poseidonHasher) public constructor(address _poseidonHasher, uint16 _contractIndex) public
``` ```
### \_register ### \_register
@ -85,3 +91,113 @@ function withdraw() external pure
``` ```
Allows a user to withdraw funds allocated to them upon slashing a member Allows a user to withdraw funds allocated to them upon slashing a member
## StorageAlreadyExists
```solidity
error StorageAlreadyExists(address storageAddress)
```
## NoStorageContractAvailable
```solidity
error NoStorageContractAvailable()
```
## IncompatibleStorage
```solidity
error IncompatibleStorage()
```
## IncompatibleStorageIndex
```solidity
error IncompatibleStorageIndex()
```
## WakuRlnRegistry
### nextStorageIndex
```solidity
uint16 nextStorageIndex
```
### storages
```solidity
mapping(uint16 => address) storages
```
### usingStorageIndex
```solidity
uint16 usingStorageIndex
```
### poseidonHasher
```solidity
contract IPoseidonHasher poseidonHasher
```
### NewStorageContract
```solidity
event NewStorageContract(uint16 index, address storageAddress)
```
### onlyUsableStorage
```solidity
modifier onlyUsableStorage()
```
### constructor
```solidity
constructor(address _poseidonHasher) public
```
### \_insertIntoStorageMap
```solidity
function _insertIntoStorageMap(address storageAddress) internal
```
### registerStorage
```solidity
function registerStorage(address storageAddress) external
```
### newStorage
```solidity
function newStorage() external
```
### register
```solidity
function register(uint256[] commitments) external payable
```
### register
```solidity
function register(uint16 storageIndex, uint256[] commitments) external payable
```
### register
```solidity
function register(uint16 storageIndex, uint256 commitment) external payable
```
### forceProgress
```solidity
function forceProgress() external
```

View File

@ -7,4 +7,6 @@ cache_path = 'cache_forge'
# 5667: Unused function parameter. Remove or comment out the variable name to silence this warning. # 5667: Unused function parameter. Remove or comment out the variable name to silence this warning.
# 5740: Unreachable code. # 5740: Unreachable code.
ignored_error_codes = [5667, 5740] ignored_error_codes = [5667, 5740]
# setting this to allow expensive larger inserts during tests
memory_limit = 100_000_000

View File

@ -1,23 +1,12 @@
// SPDX-License-Identifier: Unlicense // SPDX-License-Identifier: MIT
pragma solidity ^0.8.15; pragma solidity ^0.8.15;
import {PoseidonHasher} from "rln-contract/PoseidonHasher.sol"; import {PoseidonHasher} from "rln-contract/PoseidonHasher.sol";
import "../contracts/WakuRLn.sol"; import "./utils.sol";
import "../contracts/WakuRln.sol";
import "forge-std/Test.sol"; import "forge-std/Test.sol";
import "forge-std/StdCheats.sol"; import "forge-std/StdCheats.sol";
function noDuplicate(uint256[] calldata ids) pure returns (bool) {
uint256 len = ids.length;
for (uint256 i = 0; i < len; i++) {
for (uint256 j = i + 1; j < len; j++) {
if (ids[i] == ids[j]) {
return false;
}
}
}
return true;
}
contract WakuRlnTest is Test { contract WakuRlnTest is Test {
using stdStorage for StdStorage; using stdStorage for StdStorage;
@ -33,7 +22,7 @@ contract WakuRlnTest is Test {
/// @dev Setup the testing environment. /// @dev Setup the testing environment.
function setUp() public { function setUp() public {
poseidon = new PoseidonHasher(); poseidon = new PoseidonHasher();
wakuRln = new WakuRln(address(poseidon)); wakuRln = new WakuRln(address(poseidon), 0);
} }
/// @dev Ensure that you can hash a value. /// @dev Ensure that you can hash a value.

103
test/WakuRlnRegistry.t.sol Normal file
View File

@ -0,0 +1,103 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "../contracts/WakuRlnRegistry.sol";
import {PoseidonHasher} from "rln-contract/PoseidonHasher.sol";
import {DuplicateIdCommitment, FullTree} from "rln-contract/RlnBase.sol";
import {noDuplicate} from "./utils.sol";
import "forge-std/Test.sol";
import "forge-std/StdCheats.sol";
contract WakuRlnRegistryTest is Test {
using stdStorage for StdStorage;
WakuRlnRegistry public wakuRlnRegistry;
PoseidonHasher public poseidonHasher;
function setUp() public {
poseidonHasher = new PoseidonHasher();
wakuRlnRegistry = new WakuRlnRegistry(address(poseidonHasher));
}
function test__NewStorage() public {
wakuRlnRegistry.newStorage();
}
function test__RegisterStorage_BadIndex() public {
wakuRlnRegistry.registerStorage(address(new WakuRln(address(poseidonHasher), 0)));
address newStorage = address(new WakuRln(address(poseidonHasher), 0));
vm.expectRevert(IncompatibleStorageIndex.selector);
wakuRlnRegistry.registerStorage(newStorage);
}
function test__RegisterStorage_BadImpl() public {
address newStorage = address(new WakuRln(address(new PoseidonHasher()), 0));
vm.expectRevert(IncompatibleStorage.selector);
wakuRlnRegistry.registerStorage(newStorage);
}
function test__Register(uint256[] calldata commitments) public {
vm.assume(noDuplicate(commitments));
wakuRlnRegistry.newStorage();
wakuRlnRegistry.register(commitments);
}
function test__InvalidRegistration_Duplicate(uint256[] calldata commitments) public {
vm.assume(!noDuplicate(commitments));
wakuRlnRegistry.newStorage();
vm.expectRevert(DuplicateIdCommitment.selector);
wakuRlnRegistry.register(commitments);
}
function test__forceProgression() public {
wakuRlnRegistry.newStorage();
wakuRlnRegistry.forceProgress();
require(wakuRlnRegistry.usingStorageIndex() == 1);
}
function test__SingleRegistration(uint256 commitment) public {
wakuRlnRegistry.newStorage();
wakuRlnRegistry.register(0, commitment);
}
function test__InvalidSingleRegistration__NoStorageContract(uint256 commitment) public {
wakuRlnRegistry.newStorage();
vm.expectRevert(NoStorageContractAvailable.selector);
wakuRlnRegistry.register(1, commitment);
}
function test__InvalidSingleRegistration__Duplicate(uint256 commitment) public {
wakuRlnRegistry.newStorage();
wakuRlnRegistry.register(0, commitment);
vm.expectRevert(DuplicateIdCommitment.selector);
wakuRlnRegistry.register(0, commitment);
}
function test__InvalidSingleRegistration__FullTree() public {
vm.pauseGasMetering();
wakuRlnRegistry.newStorage();
WakuRln wakuRln = WakuRln(wakuRlnRegistry.storages(0));
uint256 setSize = wakuRln.SET_SIZE();
// setSize - 1 because RlnBase uses 1-indexing
for (uint256 i = 0; i < setSize - 1; i++) {
wakuRlnRegistry.register(0, i);
}
vm.resumeGasMetering();
vm.expectRevert(FullTree.selector);
wakuRlnRegistry.register(0, setSize);
}
function test__InvalidRegistration__NoStorageContract() public {
vm.pauseGasMetering();
wakuRlnRegistry.newStorage();
address storageContract = wakuRlnRegistry.storages(0);
uint256 setSize = WakuRln(storageContract).SET_SIZE();
uint256[] memory commitments = new uint256[](setSize);
for (uint256 i = 1; i < setSize; i++) {
commitments[i] = i;
}
vm.expectRevert(NoStorageContractAvailable.selector);
wakuRlnRegistry.register(commitments);
}
}

14
test/utils.sol Normal file
View File

@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
function noDuplicate(uint256[] calldata ids) pure returns (bool) {
uint256 len = ids.length;
for (uint256 i = 0; i < len; i++) {
for (uint256 j = i + 1; j < len; j++) {
if (ids[i] == ids[j]) {
return false;
}
}
}
return true;
}