@waku/rln
Version:
RLN (Rate Limiting Nullifier) implementation for Waku
107 lines • 4.24 kB
JavaScript
import { Logger } from "@waku/utils";
import { hexToBytes } from "@waku/utils/bytes";
import { ethers } from "ethers";
import { MerkleRootTracker } from "../root_tracker.js";
import { BytesUtils } from "../utils/bytes.js";
import { RLNBaseContract } from "./rln_base_contract.js";
const log = new Logger("waku:rln:contract");
export class RLNContract extends RLNBaseContract {
instance;
merkleRootTracker;
/**
* Asynchronous initializer for RLNContract.
* Allows injecting a mocked contract for testing purposes.
*/
static async init(rlnInstance, options) {
const rlnContract = new RLNContract(rlnInstance, options);
return rlnContract;
}
constructor(rlnInstance, options) {
super(options);
this.instance = rlnInstance;
const initialRoot = rlnInstance.zerokit.getMerkleRoot();
this.merkleRootTracker = new MerkleRootTracker(5, initialRoot);
}
processEvents(events) {
const toRemoveTable = new Map();
const toInsertTable = new Map();
events.forEach((evt) => {
if (!evt.args) {
return;
}
if (evt.event === "MembershipErased" ||
evt.event === "MembershipExpired") {
let index = evt.args.index;
if (!index) {
return;
}
if (typeof index === "number" || typeof index === "string") {
index = ethers.BigNumber.from(index);
}
else {
log.error("Index is not a number or string", {
index,
event: evt
});
return;
}
const toRemoveVal = toRemoveTable.get(evt.blockNumber);
if (toRemoveVal != undefined) {
toRemoveVal.push(index.toNumber());
toRemoveTable.set(evt.blockNumber, toRemoveVal);
}
else {
toRemoveTable.set(evt.blockNumber, [index.toNumber()]);
}
}
else if (evt.event === "MembershipRegistered") {
let eventsPerBlock = toInsertTable.get(evt.blockNumber);
if (eventsPerBlock == undefined) {
eventsPerBlock = [];
}
eventsPerBlock.push(evt);
toInsertTable.set(evt.blockNumber, eventsPerBlock);
}
});
this.removeMembers(this.instance, toRemoveTable);
this.insertMembers(this.instance, toInsertTable);
}
insertMembers(rlnInstance, toInsert) {
toInsert.forEach((events, blockNumber) => {
events.forEach((evt) => {
if (!evt.args)
return;
const _idCommitment = evt.args.idCommitment;
let index = evt.args.index;
if (!_idCommitment || !index) {
return;
}
if (typeof index === "number" || typeof index === "string") {
index = ethers.BigNumber.from(index);
}
const idCommitment = BytesUtils.zeroPadLE(hexToBytes(_idCommitment), 32);
rlnInstance.zerokit.insertMember(idCommitment);
const numericIndex = index.toNumber();
this._members.set(numericIndex, {
index,
idCommitment: _idCommitment
});
});
const currentRoot = rlnInstance.zerokit.getMerkleRoot();
this.merkleRootTracker.pushRoot(blockNumber, currentRoot);
});
}
removeMembers(rlnInstance, toRemove) {
const removeDescending = new Map([...toRemove].reverse());
removeDescending.forEach((indexes, blockNumber) => {
indexes.forEach((index) => {
if (this._members.has(index)) {
this._members.delete(index);
rlnInstance.zerokit.deleteMember(index);
}
});
this.merkleRootTracker.backFill(blockNumber);
});
}
}
//# sourceMappingURL=rln_contract.js.map