diff --git a/logos_delivery/waku/node/waku_node/lightpush.nim b/logos_delivery/waku/node/waku_node/lightpush.nim index cfaade900..d5ee5903a 100644 --- a/logos_delivery/waku/node/waku_node/lightpush.nim +++ b/logos_delivery/waku/node/waku_node/lightpush.nim @@ -114,25 +114,23 @@ proc runRlnRefreshRetry( peer: RemotePeerInfo, fallback: legacy_lightpush_protocol.WakuLightPushResult[string], ): Future[legacy_lightpush_protocol.WakuLightPushResult[string]] {.async, gcsafe.} = - ## Force-refreshes the RLN merkle proof path and retries the publish once, - ## bounded by RlnRefreshRetryTimeout. Returns `fallback` on timeout so a - ## hanging RPC/libp2p round-trip cannot stall the caller indefinitely. + ## Force-refreshes the RLN merkle proof path and retries the publish once. + ## Only the refresh (on-chain refetch + proof regeneration) is bounded by + ## RlnRefreshRetryTimeout — a hanging RPC cannot stall the caller + ## indefinitely and `fallback` (the original rejection) is returned instead. + ## The retried publish itself runs unbounded, matching the first attempt. info "legacy lightpush send rejected as RLN-invalid; " & "refreshing merkle proof and retrying once" rln.get().groupManager.invalidateMerkleProofCache() - proc runRetry(): Future[legacy_lightpush_protocol.WakuLightPushResult[string]] {. - async, gcsafe - .} = - let retryMsg = (await attachRLNProof(rln.get(), msgWithProof)).valueOr: - return err("failed call attachRLNProof from lightpush retry: " & error) - return await internalLegacyLightpushPublish(node, pubsubForPublish, retryMsg, peer) - - let retryFut = runRetry() - if not (await retryFut.withTimeout(RlnRefreshRetryTimeout)): - warn "legacy lightpush RLN-refresh retry timed out; returning original error" + let refreshFut = attachRLNProof(rln.get(), msgWithProof) + if not (await refreshFut.withTimeout(RlnRefreshRetryTimeout)): + warn "legacy lightpush RLN proof refresh timed out; returning original error" return fallback - return retryFut.read() + let retryMsg = refreshFut.read().valueOr: + return err("failed call attachRLNProof from lightpush retry: " & error) + + return await internalLegacyLightpushPublish(node, pubsubForPublish, retryMsg, peer) proc legacyLightpushPublish*( node: WakuNode, @@ -367,15 +365,16 @@ proc lightpushPublish*( statusCode = $firstResult.error.code rln.get().groupManager.invalidateMerkleProofCache() - proc runRetry(): Future[lightpush_protocol.WakuLightPushResult] {.async, gcsafe.} = - let retryMsg = (await attachRLNProof(rln.get(), msgWithProof)).valueOr: - return lighpushErrorResult(LightPushErrorCode.OUT_OF_RLN_PROOF, error) - return - await lightpushPublishHandler(node, pubsubForPublish, retryMsg, toPeer, mixify) - - let retryFut = runRetry() - if not (await retryFut.withTimeout(RlnRefreshRetryTimeout)): - warn "lightpush RLN-refresh retry timed out; returning original error", + # Only the refresh (on-chain refetch + proof regeneration) is bounded — a + # hanging RPC cannot stall the caller indefinitely and the original + # rejection is returned instead. The retried publish itself runs unbounded, + # matching the first attempt. + let refreshFut = attachRLNProof(rln.get(), msgWithProof) + if not (await refreshFut.withTimeout(RlnRefreshRetryTimeout)): + warn "lightpush RLN proof refresh timed out; returning original error", statusCode = $firstResult.error.code return firstResult - return retryFut.read() + let retryMsg = refreshFut.read().valueOr: + return lighpushErrorResult(LightPushErrorCode.OUT_OF_RLN_PROOF, error) + + return await lightpushPublishHandler(node, pubsubForPublish, retryMsg, toPeer, mixify) diff --git a/logos_delivery/waku/rln/constants.nim b/logos_delivery/waku/rln/constants.nim index a2097ffc5..028c548c7 100644 --- a/logos_delivery/waku/rln/constants.nim +++ b/logos_delivery/waku/rln/constants.nim @@ -20,10 +20,11 @@ const RlnCredentialsFilename* = "rlnCredentials.txt" # RLN Validator message rejection Error string, is used to trigger proof refresh and publish retry in the lightpush client const RlnValidatorErrorMsg* = "RLN validation failed" -# Upper bound on the reactive refresh + retry after a stale-RLN rejection. -# The retry synchronously fetches a fresh merkle path from the RLN contract -# (eth_call round-trip) and republishes; without a bound a hanging RPC endpoint -# could stall the caller indefinitely. Matches the REST `futTimeout`. +# Upper bound on the reactive merkle proof refresh after a stale-RLN +# rejection: fetching a fresh merkle path from the RLN contract (eth_call +# round-trip) plus proof regeneration. Without a bound a hanging RPC endpoint +# could stall the caller indefinitely. The retried publish is not covered — +# it runs unbounded, matching the first attempt. const RlnRefreshRetryTimeout* = 5.seconds # inputs of the membership contract constructor