Skip to content

Commit 10aadbe

Browse files
refactor(rln): cache min/max rate limits at contract instantiation
1 parent b16a49e commit 10aadbe

File tree

2 files changed

+42
-33
lines changed

2 files changed

+42
-33
lines changed

packages/rln/src/contract/rln_base_contract.ts

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Logger } from "@waku/utils";
2-
import { Contract, ethers } from "ethers";
2+
import { ethers } from "ethers";
33

44
import { IdentityCredential } from "../identity.js";
55
import { DecryptedCredentials } from "../keystore/types.js";
@@ -22,17 +22,18 @@ export class RLNBaseContract {
2222
public contract: ethers.Contract;
2323
private deployBlock: undefined | number;
2424
private rateLimit: number;
25+
private minRateLimit?: number;
26+
private maxRateLimit?: number;
2527

2628
protected _members: Map<number, Member> = new Map();
2729
private _membersFilter: ethers.EventFilter;
2830
private _membershipErasedFilter: ethers.EventFilter;
2931
private _membersExpiredFilter: ethers.EventFilter;
3032

3133
/**
32-
* Constructor for RLNBaseContract.
33-
* Allows injecting a mocked contract for testing purposes.
34+
* Private constructor for RLNBaseContract. Use static create() instead.
3435
*/
35-
public constructor(options: RLNContractInitOptions) {
36+
private constructor(options: RLNContractInitOptions) {
3637
const {
3738
address,
3839
signer,
@@ -67,11 +68,24 @@ export class RLNBaseContract {
6768
.catch((error) => {
6869
log.error("Failed to initialize members", { error });
6970
});
71+
}
7072

71-
// Validate rate limit asynchronously
72-
this.validateRateLimit(rateLimit).catch((error) => {
73-
log.error("Failed to validate initial rate limit", { error });
74-
});
73+
/**
74+
* Static async factory to create and initialize RLNBaseContract
75+
*/
76+
public static async create(
77+
options: RLNContractInitOptions
78+
): Promise<RLNBaseContract> {
79+
const instance = new RLNBaseContract(options);
80+
const [min, max] = await Promise.all([
81+
instance.contract.minMembershipRateLimit(),
82+
instance.contract.maxMembershipRateLimit()
83+
]);
84+
instance.minRateLimit = ethers.BigNumber.from(min).toNumber();
85+
instance.maxRateLimit = ethers.BigNumber.from(max).toNumber();
86+
87+
instance.validateRateLimit(instance.rateLimit);
88+
return instance;
7589
}
7690

7791
/**
@@ -96,21 +110,21 @@ export class RLNBaseContract {
96110
}
97111

98112
/**
99-
* Gets the minimum allowed rate limit from the contract
100-
* @returns Promise<number> The minimum rate limit in messages per epoch
113+
* Gets the minimum allowed rate limit (cached)
101114
*/
102-
public async getMinRateLimit(): Promise<number> {
103-
const minRate = await this.contract.minMembershipRateLimit();
104-
return ethers.BigNumber.from(minRate).toNumber();
115+
public getMinRateLimit(): number {
116+
if (this.minRateLimit === undefined)
117+
throw new Error("minRateLimit not initialized");
118+
return this.minRateLimit;
105119
}
106120

107121
/**
108-
* Gets the maximum allowed rate limit from the contract
109-
* @returns Promise<number> The maximum rate limit in messages per epoch
122+
* Gets the maximum allowed rate limit (cached)
110123
*/
111-
public async getMaxRateLimit(): Promise<number> {
112-
const maxRate = await this.contract.maxMembershipRateLimit();
113-
return ethers.BigNumber.from(maxRate).toNumber();
124+
public getMaxRateLimit(): number {
125+
if (this.maxRateLimit === undefined)
126+
throw new Error("maxRateLimit not initialized");
127+
return this.maxRateLimit;
114128
}
115129

116130
/**
@@ -147,8 +161,8 @@ export class RLNBaseContract {
147161
* Updates the rate limit for future registrations
148162
* @param newRateLimit The new rate limit to use
149163
*/
150-
public async setRateLimit(newRateLimit: number): Promise<void> {
151-
await this.validateRateLimit(newRateLimit);
164+
public setRateLimit(newRateLimit: number): void {
165+
this.validateRateLimit(newRateLimit);
152166
this.rateLimit = newRateLimit;
153167
}
154168

@@ -662,21 +676,16 @@ export class RLNBaseContract {
662676
}
663677

664678
/**
665-
* Validates that the rate limit is within the allowed range
679+
* Validates that the rate limit is within the allowed range (sync)
666680
* @throws Error if the rate limit is outside the allowed range
667681
*/
668-
private async validateRateLimit(rateLimit: number): Promise<void> {
669-
const [minRate, maxRate] = await Promise.all([
670-
this.contract.minMembershipRateLimit(),
671-
this.contract.maxMembershipRateLimit()
672-
]);
673-
674-
const minRateNum = ethers.BigNumber.from(minRate).toNumber();
675-
const maxRateNum = ethers.BigNumber.from(maxRate).toNumber();
676-
677-
if (rateLimit < minRateNum || rateLimit > maxRateNum) {
682+
private validateRateLimit(rateLimit: number): void {
683+
if (this.minRateLimit === undefined || this.maxRateLimit === undefined) {
684+
throw new Error("Rate limits not initialized");
685+
}
686+
if (rateLimit < this.minRateLimit || rateLimit > this.maxRateLimit) {
678687
throw new Error(
679-
`Rate limit must be between ${minRateNum} and ${maxRateNum} messages per epoch`
688+
`Rate limit must be between ${this.minRateLimit} and ${this.maxRateLimit} messages per epoch`
680689
);
681690
}
682691
}

packages/rln/src/credentials_manager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export class RLNCredentialsManager {
8080

8181
this.credentials = credentials;
8282
this.signer = signer!;
83-
this.contract = new RLNBaseContract({
83+
this.contract = await RLNBaseContract.create({
8484
address: address!,
8585
signer: signer!,
8686
rateLimit: rateLimit ?? this.zerokit?.rateLimit

0 commit comments

Comments
 (0)