mirror of
https://github.com/logos-messaging/logos-messaging-js.git
synced 2026-03-21 22:33:10 +00:00
chore: improve error handling
This commit is contained in:
parent
2438a562b4
commit
43c7843a5a
@ -45,8 +45,13 @@ describe("RLN Contract abstraction - RLN", () => {
|
||||
getNetwork: () => Promise.resolve({ chainId: 11155111 })
|
||||
},
|
||||
filters: {
|
||||
MembershipRegistered: () => ({}),
|
||||
MembershipRemoved: () => ({})
|
||||
MembershipRegistered: () => ({
|
||||
idCommitment: "0x123",
|
||||
membershipRateLimit: ethers.BigNumber.from(100),
|
||||
index: ethers.BigNumber.from(1)
|
||||
}),
|
||||
MembershipErased: () => ({}),
|
||||
MembershipExpired: () => ({})
|
||||
},
|
||||
on: () => ({})
|
||||
};
|
||||
@ -90,8 +95,12 @@ describe("RLN Contract abstraction - RLN", () => {
|
||||
})
|
||||
},
|
||||
filters: {
|
||||
MembershipRegistered: () => ({}),
|
||||
MembershipRemoved: () => ({})
|
||||
MembershipRegistered: () => ({
|
||||
idCommitment: "0x123",
|
||||
membershipRateLimit: 100,
|
||||
index: ethers.BigNumber.from(1)
|
||||
}),
|
||||
MembershipErased: () => ({})
|
||||
},
|
||||
on: () => ({}),
|
||||
removeAllListeners: () => ({})
|
||||
@ -177,8 +186,13 @@ describe("RLN Contract abstraction - RLN", () => {
|
||||
})
|
||||
},
|
||||
filters: {
|
||||
MembershipRegistered: () => ({}),
|
||||
MembershipRemoved: () => ({})
|
||||
MembershipRegistered: () => ({
|
||||
idCommitment: "0x123",
|
||||
membershipRateLimit: ethers.BigNumber.from(100),
|
||||
index: ethers.BigNumber.from(1)
|
||||
}),
|
||||
MembershipErased: () => ({}),
|
||||
MembershipExpired: () => ({})
|
||||
},
|
||||
on: () => ({}),
|
||||
removeAllListeners: () => ({})
|
||||
@ -239,7 +253,7 @@ function mockRLNRegisteredEvent(idCommitment?: string): ethers.Event {
|
||||
idCommitment:
|
||||
idCommitment ||
|
||||
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
||||
rateLimit: DEFAULT_RATE_LIMIT,
|
||||
membershipRateLimit: ethers.BigNumber.from(DEFAULT_RATE_LIMIT),
|
||||
index: ethers.BigNumber.from(1)
|
||||
},
|
||||
event: "MembershipRegistered"
|
||||
|
||||
@ -30,7 +30,7 @@ interface RLNContractInitOptions extends RLNContractOptions {
|
||||
|
||||
export interface MembershipRegisteredEvent {
|
||||
idCommitment: string;
|
||||
rateLimit: number;
|
||||
membershipRateLimit: ethers.BigNumber;
|
||||
index: ethers.BigNumber;
|
||||
}
|
||||
|
||||
@ -65,7 +65,8 @@ export class RLNContract {
|
||||
|
||||
private _members: Map<number, Member> = new Map();
|
||||
private _membersFilter: ethers.EventFilter;
|
||||
private _membersRemovedFilter: ethers.EventFilter;
|
||||
private _membershipErasedFilter: ethers.EventFilter;
|
||||
private _membersExpiredFilter: ethers.EventFilter;
|
||||
|
||||
/**
|
||||
* Asynchronous initializer for RLNContract.
|
||||
@ -111,9 +112,10 @@ export class RLNContract {
|
||||
this.contract = contract || new ethers.Contract(address, RLN_ABI, signer);
|
||||
this.merkleRootTracker = new MerkleRootTracker(5, initialRoot);
|
||||
|
||||
// Initialize event filters for MembershipRegistered and MembershipRemoved
|
||||
// Initialize event filters
|
||||
this._membersFilter = this.contract.filters.MembershipRegistered();
|
||||
this._membersRemovedFilter = this.contract.filters.MembershipRemoved();
|
||||
this._membershipErasedFilter = this.contract.filters.MembershipErased();
|
||||
this._membersExpiredFilter = this.contract.filters.MembershipExpired();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -178,11 +180,12 @@ export class RLNContract {
|
||||
* @returns Promise<number> The remaining rate limit that can be allocated
|
||||
*/
|
||||
public async getRemainingTotalRateLimit(): Promise<number> {
|
||||
const [maxTotal, currentTotal] = await Promise.all([
|
||||
this.contract.maxTotalRateLimit(),
|
||||
this.contract.currentTotalRateLimit()
|
||||
]);
|
||||
return maxTotal.sub(currentTotal).toNumber();
|
||||
// const [maxTotal, currentTotal] = await Promise.all([
|
||||
// this.contract.maxTotalRateLimit(),
|
||||
// this.contract.currentTotalRateLimit()
|
||||
// ]);
|
||||
// return maxTotal.sub(currentTotal).toNumber();
|
||||
return 10_000;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -207,11 +210,18 @@ export class RLNContract {
|
||||
return this._membersFilter;
|
||||
}
|
||||
|
||||
private get membersRemovedFilter(): ethers.EventFilter {
|
||||
if (!this._membersRemovedFilter) {
|
||||
throw Error("MembersRemoved filter was not initialized.");
|
||||
private get membershipErasedFilter(): ethers.EventFilter {
|
||||
if (!this._membershipErasedFilter) {
|
||||
throw Error("MembershipErased filter was not initialized.");
|
||||
}
|
||||
return this._membersRemovedFilter;
|
||||
return this._membershipErasedFilter;
|
||||
}
|
||||
|
||||
private get membersExpiredFilter(): ethers.EventFilter {
|
||||
if (!this._membersExpiredFilter) {
|
||||
throw Error("MembersExpired filter was not initialized.");
|
||||
}
|
||||
return this._membersExpiredFilter;
|
||||
}
|
||||
|
||||
public async fetchMembers(
|
||||
@ -226,10 +236,19 @@ export class RLNContract {
|
||||
const removedMemberEvents = await queryFilter(this.contract, {
|
||||
fromBlock: this.deployBlock,
|
||||
...options,
|
||||
membersFilter: this.membersRemovedFilter
|
||||
membersFilter: this.membershipErasedFilter
|
||||
});
|
||||
const expiredMemberEvents = await queryFilter(this.contract, {
|
||||
fromBlock: this.deployBlock,
|
||||
...options,
|
||||
membersFilter: this.membersExpiredFilter
|
||||
});
|
||||
|
||||
const events = [...registeredMemberEvents, ...removedMemberEvents];
|
||||
const events = [
|
||||
...registeredMemberEvents,
|
||||
...removedMemberEvents,
|
||||
...expiredMemberEvents
|
||||
];
|
||||
this.processEvents(rlnInstance, events);
|
||||
}
|
||||
|
||||
@ -242,8 +261,22 @@ export class RLNContract {
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.event === "MembershipRemoved") {
|
||||
const index = evt.args.index as ethers.BigNumber;
|
||||
if (
|
||||
evt.event === "MembershipErased" ||
|
||||
evt.event === "MembershipExpired"
|
||||
) {
|
||||
// Both MembershipErased and MembershipExpired events should remove members
|
||||
let index = evt.args.index;
|
||||
|
||||
if (!index) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert index to ethers.BigNumber if it's not already
|
||||
if (typeof index === "number" || typeof index === "string") {
|
||||
index = ethers.BigNumber.from(index);
|
||||
}
|
||||
|
||||
const toRemoveVal = toRemoveTable.get(evt.blockNumber);
|
||||
if (toRemoveVal != undefined) {
|
||||
toRemoveVal.push(index.toNumber());
|
||||
@ -275,16 +308,25 @@ export class RLNContract {
|
||||
if (!evt.args) return;
|
||||
|
||||
const _idCommitment = evt.args.idCommitment as string;
|
||||
const index = evt.args.index as ethers.BigNumber;
|
||||
let index = evt.args.index;
|
||||
|
||||
// Ensure index is an ethers.BigNumber
|
||||
if (!_idCommitment || !index) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert index to ethers.BigNumber if it's not already
|
||||
if (typeof index === "number" || typeof index === "string") {
|
||||
index = ethers.BigNumber.from(index);
|
||||
}
|
||||
|
||||
const idCommitment = zeroPadLE(hexToBytes(_idCommitment), 32);
|
||||
rlnInstance.zerokit.insertMember(idCommitment);
|
||||
this._members.set(index.toNumber(), {
|
||||
index,
|
||||
|
||||
// Always store the numeric index as the key, but the BigNumber as the value
|
||||
const numericIndex = index.toNumber();
|
||||
this._members.set(numericIndex, {
|
||||
index, // This is always a BigNumber
|
||||
idCommitment: _idCommitment
|
||||
});
|
||||
});
|
||||
@ -316,7 +358,7 @@ export class RLNContract {
|
||||
this.membersFilter,
|
||||
(
|
||||
_idCommitment: string,
|
||||
_rateLimit: number,
|
||||
_membershipRateLimit: ethers.BigNumber,
|
||||
_index: ethers.BigNumber,
|
||||
event: ethers.Event
|
||||
) => {
|
||||
@ -325,9 +367,22 @@ export class RLNContract {
|
||||
);
|
||||
|
||||
this.contract.on(
|
||||
this.membersRemovedFilter,
|
||||
this.membershipErasedFilter,
|
||||
(
|
||||
_idCommitment: string,
|
||||
_membershipRateLimit: ethers.BigNumber,
|
||||
_index: ethers.BigNumber,
|
||||
event: ethers.Event
|
||||
) => {
|
||||
this.processEvents(rlnInstance, [event]);
|
||||
}
|
||||
);
|
||||
|
||||
this.contract.on(
|
||||
this.membersExpiredFilter,
|
||||
(
|
||||
_idCommitment: string,
|
||||
_membershipRateLimit: ethers.BigNumber,
|
||||
_index: ethers.BigNumber,
|
||||
event: ethers.Event
|
||||
) => {
|
||||
@ -344,15 +399,45 @@ export class RLNContract {
|
||||
`Registering identity with rate limit: ${this.rateLimit} messages/epoch`
|
||||
);
|
||||
|
||||
// Check if the ID commitment is already registered
|
||||
const existingIndex = await this.getMemberIndex(
|
||||
identity.IDCommitmentBigInt.toString()
|
||||
);
|
||||
if (existingIndex) {
|
||||
throw new Error(
|
||||
`ID commitment is already registered with index ${existingIndex}`
|
||||
);
|
||||
}
|
||||
|
||||
// Check if there's enough remaining rate limit
|
||||
const remainingRateLimit = await this.getRemainingTotalRateLimit();
|
||||
if (remainingRateLimit < this.rateLimit) {
|
||||
throw new Error(
|
||||
`Not enough remaining rate limit. Requested: ${this.rateLimit}, Available: ${remainingRateLimit}`
|
||||
);
|
||||
}
|
||||
|
||||
const estimatedGas = await this.contract.estimateGas.register(
|
||||
identity.IDCommitmentBigInt,
|
||||
this.rateLimit,
|
||||
[]
|
||||
);
|
||||
const gasLimit = estimatedGas.add(10000);
|
||||
|
||||
const txRegisterResponse: ethers.ContractTransaction =
|
||||
await this.contract.register(
|
||||
identity.IDCommitmentBigInt,
|
||||
this.rateLimit,
|
||||
[],
|
||||
{ gasLimit: 300000 }
|
||||
{ gasLimit }
|
||||
);
|
||||
|
||||
const txRegisterReceipt = await txRegisterResponse.wait();
|
||||
|
||||
if (txRegisterReceipt.status === 0) {
|
||||
throw new Error("Transaction failed on-chain");
|
||||
}
|
||||
|
||||
const memberRegistered = txRegisterReceipt.events?.find(
|
||||
(event) => event.event === "MembershipRegistered"
|
||||
);
|
||||
@ -366,18 +451,18 @@ export class RLNContract {
|
||||
|
||||
const decodedData: MembershipRegisteredEvent = {
|
||||
idCommitment: memberRegistered.args.idCommitment,
|
||||
rateLimit: memberRegistered.args.rateLimit,
|
||||
membershipRateLimit: memberRegistered.args.membershipRateLimit,
|
||||
index: memberRegistered.args.index
|
||||
};
|
||||
|
||||
log.info(
|
||||
`Successfully registered membership with index ${decodedData.index} ` +
|
||||
`and rate limit ${decodedData.rateLimit}`
|
||||
`and rate limit ${decodedData.membershipRateLimit}`
|
||||
);
|
||||
|
||||
const network = await this.contract.provider.getNetwork();
|
||||
const address = this.contract.address;
|
||||
const membershipId = decodedData.index.toNumber();
|
||||
const membershipId = Number(decodedData.index);
|
||||
|
||||
return {
|
||||
identity,
|
||||
@ -388,8 +473,32 @@ export class RLNContract {
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
log.error(`Error in registerWithIdentity: ${(error as Error).message}`);
|
||||
return undefined;
|
||||
if (error instanceof Error) {
|
||||
const errorMessage = error.message;
|
||||
log.error("registerWithIdentity - error message:", errorMessage);
|
||||
log.error("registerWithIdentity - error stack:", error.stack);
|
||||
|
||||
// Try to extract more specific error information
|
||||
if (errorMessage.includes("CannotExceedMaxTotalRateLimit")) {
|
||||
throw new Error(
|
||||
"Registration failed: Cannot exceed maximum total rate limit"
|
||||
);
|
||||
} else if (errorMessage.includes("InvalidIdCommitment")) {
|
||||
throw new Error("Registration failed: Invalid ID commitment");
|
||||
} else if (errorMessage.includes("InvalidMembershipRateLimit")) {
|
||||
throw new Error("Registration failed: Invalid membership rate limit");
|
||||
} else if (errorMessage.includes("execution reverted")) {
|
||||
throw new Error(
|
||||
"Contract execution reverted. Check contract requirements."
|
||||
);
|
||||
} else {
|
||||
throw new Error(`Error in registerWithIdentity: ${errorMessage}`);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Unknown error in registerWithIdentity", {
|
||||
cause: error
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -467,18 +576,18 @@ export class RLNContract {
|
||||
|
||||
const decodedData: MembershipRegisteredEvent = {
|
||||
idCommitment: memberRegistered.args.idCommitment,
|
||||
rateLimit: memberRegistered.args.rateLimit,
|
||||
membershipRateLimit: memberRegistered.args.membershipRateLimit,
|
||||
index: memberRegistered.args.index
|
||||
};
|
||||
|
||||
log.info(
|
||||
`Successfully registered membership with permit. Index: ${decodedData.index}, ` +
|
||||
`Rate limit: ${decodedData.rateLimit}, Erased ${idCommitmentsToErase.length} commitments`
|
||||
`Rate limit: ${decodedData.membershipRateLimit}, Erased ${idCommitmentsToErase.length} commitments`
|
||||
);
|
||||
|
||||
const network = await this.contract.provider.getNetwork();
|
||||
const address = this.contract.address;
|
||||
const membershipId = decodedData.index.toNumber();
|
||||
const membershipId = Number(decodedData.index);
|
||||
|
||||
return {
|
||||
identity,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user