From c4917e4aedbc895363ac94f7352264cee92a1183 Mon Sep 17 00:00:00 2001 From: stubbsta Date: Tue, 6 Jan 2026 14:56:26 +0200 Subject: [PATCH] Update InitializeGuard to not raise exception --- .../test_rln_group_manager_onchain.nim | 57 ++--- .../group_manager/on_chain/group_manager.nim | 218 ++++++++---------- 2 files changed, 119 insertions(+), 156 deletions(-) diff --git a/tests/waku_rln_relay/test_rln_group_manager_onchain.nim b/tests/waku_rln_relay/test_rln_group_manager_onchain.nim index 22802465b..d70f22092 100644 --- a/tests/waku_rln_relay/test_rln_group_manager_onchain.nim +++ b/tests/waku_rln_relay/test_rln_group_manager_onchain.nim @@ -74,10 +74,11 @@ suite "Onchain group manager": raiseAssert "Expected error when keystore file doesn't exist" test "trackRootChanges: should guard against uninitialized state": - try: - discard manager.trackRootChanges() - except CatchableError: - check getCurrentExceptionMsg().len == 38 + let initializedResult = waitFor manager.trackRootChanges() + + check: + initializedResult.isErr() + initializedResult.error == "OnchainGroupManager is not initialized" test "trackRootChanges: should sync to the state of the group": let credentials = generateCredentials() @@ -87,8 +88,7 @@ suite "Onchain group manager": let merkleRootBefore = waitFor manager.fetchMerkleRoot() (waitFor manager.register(credentials, UserMessageLimit(20))).isOkOr: - assert false, - "error returned when calling register: " & error + assert false, "error returned when calling register: " & error discard waitFor withTimeout(trackRootChanges(manager), 15.seconds) @@ -132,7 +132,7 @@ suite "Onchain group manager": check: res.isErr() - res.error == "Not initialized: OnchainGroupManager is not initialized" + res.error == "OnchainGroupManager is not initialized" test "register: should register successfully": # TODO :- similar to ```trackRootChanges: should fetch history correctly``` @@ -143,8 +143,7 @@ suite "Onchain group manager": let merkleRootBefore = waitFor manager.fetchMerkleRoot() (waitFor manager.register(idCredentials, UserMessageLimit(20))).isOkOr: - assert false, - "error returned when calling register: " & error + assert false, "error returned when calling register: " & error let merkleRootAfter = waitFor manager.fetchMerkleRoot() @@ -171,13 +170,14 @@ suite "Onchain group manager": manager.onRegister(callback) - (waitFor manager.register( - RateCommitment( - idCommitment: idCommitment, userMessageLimit: UserMessageLimit(20) + ( + waitFor manager.register( + RateCommitment( + idCommitment: idCommitment, userMessageLimit: UserMessageLimit(20) + ) ) - )).isOkOr: - assert false, - "error returned when calling register: " & error + ).isOkOr: + assert false, "error returned when calling register: " & error waitFor fut @@ -188,7 +188,7 @@ suite "Onchain group manager": check: res.isErr() - res.error == "Not initialized: OnchainGroupManager is not initialized" + res.error == "OnchainGroupManager is not initialized" test "validateRoot: should validate good root": let idCredentials = generateCredentials() @@ -289,10 +289,8 @@ suite "Onchain group manager": manager.onRegister(callback) - (waitFor manager.register(credentials, UserMessageLimit(20))).isOkOr: - assert false, - "error returned when calling register: " & error + assert false, "error returned when calling register: " & error waitFor fut let rootUpdated = waitFor manager.updateRoots() @@ -328,8 +326,7 @@ suite "Onchain group manager": let idCredential = generateCredentials() (waitFor manager.register(idCredential, UserMessageLimit(20))).isOkOr: - assert false, - "error returned when calling register: " & error + assert false, "error returned when calling register: " & error let messageBytes = "Hello".toBytes() @@ -401,24 +398,18 @@ suite "Onchain group manager": manager.ethRpc = none(Web3) - var isReady = true - try: - isReady = waitFor manager.isReady() - except Exception, CatchableError: - assert false, "exception raised: " & getCurrentExceptionMsg() + let isReadyResult = waitFor manager.isReady() check: - isReady == false + isReadyResult.isErr() + isReadyResult.error == "Ethereum RPC client is not configured" test "isReady should return true if ethRpc is ready": (waitFor manager.init()).isOkOr: raiseAssert $error - var isReady = false - try: - isReady = waitFor manager.isReady() - except Exception, CatchableError: - assert false, "exception raised: " & getCurrentExceptionMsg() + let isReadyResult = waitFor manager.isReady() check: - isReady == true + isReadyResult.isOk() + isReadyResult.value == true diff --git a/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim b/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim index 1d1474f3c..bdb85f6bd 100644 --- a/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim +++ b/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim @@ -50,103 +50,85 @@ type proc fetchMerkleProofElements*( g: OnchainGroupManager ): Future[Result[seq[byte], string]] {.async.} = - try: - let membershipIndex = g.membershipIndex.get() - let index40 = stuint(membershipIndex, 40) + let membershipIndex = g.membershipIndex.get() + let index40 = stuint(membershipIndex, 40) - let methodSig = "getMerkleProof(uint40)" - var paddedParam = newSeq[byte](32) - let indexBytes = index40.toBytesBE() - for i in 0 ..< min(indexBytes.len, paddedParam.len): - paddedParam[paddedParam.len - indexBytes.len + i] = indexBytes[i] + let methodSig = "getMerkleProof(uint40)" + var paddedParam = newSeq[byte](32) + let indexBytes = index40.toBytesBE() + for i in 0 ..< min(indexBytes.len, paddedParam.len): + paddedParam[paddedParam.len - indexBytes.len + i] = indexBytes[i] - let response = await sendEthCallWithParams( - ethRpc = g.ethRpc.get(), - functionSignature = methodSig, - params = paddedParam, - fromAddress = g.ethRpc.get().defaultAccount, - toAddress = fromHex(Address, g.ethContractAddress), - chainId = g.chainId, - ) + let response = await sendEthCallWithParams( + ethRpc = g.ethRpc.get(), + functionSignature = methodSig, + params = paddedParam, + fromAddress = g.ethRpc.get().defaultAccount, + toAddress = fromHex(Address, g.ethContractAddress), + chainId = g.chainId, + ) - return response - except CatchableError: - error "Failed to fetch Merkle proof elements", error = getCurrentExceptionMsg() - return err("Failed to fetch merkle proof elements: " & getCurrentExceptionMsg()) + return response proc fetchMerkleRoot*( g: OnchainGroupManager ): Future[Result[UInt256, string]] {.async.} = - try: - let merkleRoot = await sendEthCallWithoutParams( - ethRpc = g.ethRpc.get(), - functionSignature = "root()", - fromAddress = g.ethRpc.get().defaultAccount, - toAddress = fromHex(Address, g.ethContractAddress), - chainId = g.chainId, - ) - return merkleRoot - except CatchableError: - error "Failed to fetch Merkle root", error = getCurrentExceptionMsg() - return err("Failed to fetch merkle root: " & getCurrentExceptionMsg()) + let merkleRoot = await sendEthCallWithoutParams( + ethRpc = g.ethRpc.get(), + functionSignature = "root()", + fromAddress = g.ethRpc.get().defaultAccount, + toAddress = fromHex(Address, g.ethContractAddress), + chainId = g.chainId, + ) + return merkleRoot proc fetchNextFreeIndex*( g: OnchainGroupManager ): Future[Result[UInt256, string]] {.async.} = - try: - let nextFreeIndex = await sendEthCallWithoutParams( - ethRpc = g.ethRpc.get(), - functionSignature = "nextFreeIndex()", - fromAddress = g.ethRpc.get().defaultAccount, - toAddress = fromHex(Address, g.ethContractAddress), - chainId = g.chainId, - ) - return nextFreeIndex - except CatchableError: - error "Failed to fetch next free index", error = getCurrentExceptionMsg() - return err("Failed to fetch next free index: " & getCurrentExceptionMsg()) + let nextFreeIndex = await sendEthCallWithoutParams( + ethRpc = g.ethRpc.get(), + functionSignature = "nextFreeIndex()", + fromAddress = g.ethRpc.get().defaultAccount, + toAddress = fromHex(Address, g.ethContractAddress), + chainId = g.chainId, + ) + return nextFreeIndex proc fetchMembershipStatus*( g: OnchainGroupManager, idCommitment: IDCommitment ): Future[Result[bool, string]] {.async.} = - try: - let params = idCommitment.reversed() - let responseBytes = ( - await sendEthCallWithParams( - ethRpc = g.ethRpc.get(), - functionSignature = "isInMembershipSet(uint256)", - params = params, - fromAddress = g.ethRpc.get().defaultAccount, - toAddress = fromHex(Address, g.ethContractAddress), - chainId = g.chainId, - ) - ).valueOr: - return err("Failed to check membership: " & error) - - return ok(responseBytes.len == 32 and responseBytes[^1] == 1'u8) - except CatchableError: - error "Failed to fetch membership set membership", error = getCurrentExceptionMsg() - return err("Failed to fetch membership set membership: " & getCurrentExceptionMsg()) - -proc fetchMaxMembershipRateLimit*( - g: OnchainGroupManager -): Future[Result[UInt256, string]] {.async.} = - try: - let maxMembershipRateLimit = await sendEthCallWithoutParams( + let params = idCommitment.reversed() + let responseBytes = ( + await sendEthCallWithParams( ethRpc = g.ethRpc.get(), - functionSignature = "maxMembershipRateLimit()", + functionSignature = "isInMembershipSet(uint256)", + params = params, fromAddress = g.ethRpc.get().defaultAccount, toAddress = fromHex(Address, g.ethContractAddress), chainId = g.chainId, ) - return maxMembershipRateLimit - except CatchableError: - error "Failed to fetch max membership rate limit", error = getCurrentExceptionMsg() - return err("Failed to fetch max membership rate limit: " & getCurrentExceptionMsg()) + ).valueOr: + return err("Failed to check membership: " & error) -template initializedGuard(g: OnchainGroupManager): untyped = + return ok(responseBytes.len == 32 and responseBytes[^1] == 1'u8) + +proc fetchMaxMembershipRateLimit*( + g: OnchainGroupManager +): Future[Result[UInt256, string]] {.async.} = + let maxMembershipRateLimit = await sendEthCallWithoutParams( + ethRpc = g.ethRpc.get(), + functionSignature = "maxMembershipRateLimit()", + fromAddress = g.ethRpc.get().defaultAccount, + toAddress = fromHex(Address, g.ethContractAddress), + chainId = g.chainId, + ) + + return maxMembershipRateLimit + +proc checkInitialized(g: OnchainGroupManager): Result[void, string] = if not g.initialized: - raise newException(CatchableError, "OnchainGroupManager is not initialized") + return err("OnchainGroupManager is not initialized") + return ok() proc updateRoots*(g: OnchainGroupManager): Future[bool] {.async.} = let rootRes = (await g.fetchMerkleRoot()).valueOr: @@ -167,42 +149,38 @@ proc updateRoots*(g: OnchainGroupManager): Future[bool] {.async.} = return false proc trackRootChanges*(g: OnchainGroupManager): Future[Result[void, string]] {.async.} = - try: - initializedGuard(g) - const rpcDelay = 5.seconds + checkInitialized(g).isOkOr: + return err(error) - while true: - await sleepAsync(rpcDelay) - let rootUpdated = await g.updateRoots() + const rpcDelay = 5.seconds - if rootUpdated: - ## The membership set on-chain has changed (some new members have joined or some members have left) - if g.membershipIndex.isSome(): - ## A membership index exists only if the node has registered with RLN. - ## Non-registered nodes cannot have Merkle proof elements. - let proofResult = await g.fetchMerkleProofElements() - if proofResult.isErr(): - error "Failed to fetch Merkle proof", error = proofResult.error - else: - g.merkleProofCache = proofResult.get() + while true: + await sleepAsync(rpcDelay) + let rootUpdated = await g.updateRoots() - let nextFreeIndex = (await g.fetchNextFreeIndex()).valueOr: - error "Failed to fetch next free index", error = error - return err("Failed to fetch next free index: " & error) + if rootUpdated: + ## The membership set on-chain has changed (some new members have joined or some members have left) + if g.membershipIndex.isSome(): + ## A membership index exists only if the node has registered with RLN. + ## Non-registered nodes cannot have Merkle proof elements. + let proofResult = await g.fetchMerkleProofElements() + if proofResult.isErr(): + error "Failed to fetch Merkle proof", error = proofResult.error + else: + g.merkleProofCache = proofResult.get() - let memberCount = cast[int64](nextFreeIndex) - waku_rln_number_registered_memberships.set(float64(memberCount)) - except CatchableError: - error "Fatal error in trackRootChanges", error = getCurrentExceptionMsg() - return err("Fatal error in trackRootChanges" & getCurrentExceptionMsg()) + let nextFreeIndex = (await g.fetchNextFreeIndex()).valueOr: + error "Failed to fetch next free index", error = error + return err("Failed to fetch next free index: " & error) + + let memberCount = cast[int64](nextFreeIndex) + waku_rln_number_registered_memberships.set(float64(memberCount)) method register*( g: OnchainGroupManager, rateCommitment: RateCommitment ): Future[Result[void, string]] {.async.} = - try: - initializedGuard(g) - except CatchableError as e: - return err("Not initialized: " & e.msg) + checkInitialized(g).isOkOr: + return err(error) try: let leaf = rateCommitment.toLeaf().get() @@ -221,10 +199,8 @@ method register*( identityCredential: IdentityCredential, userMessageLimit: UserMessageLimit, ): Future[Result[void, string]] {.async.} = - try: - initializedGuard(g) - except CatchableError as e: - return err("Not initialized: " & e.msg) + checkInitialized(g).isOkOr: + return err(error) let ethRpc = g.ethRpc.get() let wakuRlnContract = g.wakuRlnContract.get() @@ -335,20 +311,15 @@ method register*( method withdraw*( g: OnchainGroupManager, idCommitment: IDCommitment ): Future[Result[void, string]] {.async.} = - try: - initializedGuard(g) - except CatchableError as e: - return err("Not initialized: " & e.msg) - + checkInitialized(g).isOkOr: + return err(error) return ok() method withdrawBatch*( g: OnchainGroupManager, idCommitments: seq[IDCommitment] ): Future[Result[void, string]] {.async.} = - try: - initializedGuard(g) - except CatchableError as e: - return err("Not initialized: " & e.msg) + checkInitialized(g).isOkOr: + return err(error) return ok() @@ -382,7 +353,7 @@ method generateProof*( epoch: Epoch, messageId: MessageId, rlnIdentifier = DefaultRlnIdentifier, -): GroupManagerResult[RateLimitProof] {.gcsafe, raises: [].} = +): GroupManagerResult[RateLimitProof] {.gcsafe.} = ## Generates an RLN proof using the cached Merkle proof and custom witness # Ensure identity credentials and membership index are set if g.idCredentials.isNone(): @@ -480,7 +451,7 @@ method generateProof*( method verifyProof*( g: OnchainGroupManager, input: seq[byte], proof: RateLimitProof -): GroupManagerResult[bool] {.gcsafe, raises: [].} = +): GroupManagerResult[bool] {.gcsafe.} = ## -- Verifies an RLN rate-limit proof against the set of valid Merkle roots -- var normalizedProof = proof @@ -656,13 +627,14 @@ method stop*(g: OnchainGroupManager): Future[void] {.async, gcsafe.} = g.initialized = false -method isReady*(g: OnchainGroupManager): Future[bool] {.async.} = - initializedGuard(g) +method isReady*(g: OnchainGroupManager): Future[Result[bool, string]] {.async.} = + checkInitialized(g).isOkOr: + return err(error) if g.ethRpc.isNone(): - return false + return err("Ethereum RPC client is not configured") if g.wakuRlnContract.isNone(): - return false + return err("Waku RLN contract is not configured") - return true + return ok(true)