diff --git a/logos_delivery/waku/node/waku_node/lightpush.nim b/logos_delivery/waku/node/waku_node/lightpush.nim index ae502233c..256249f8c 100644 --- a/logos_delivery/waku/node/waku_node/lightpush.nim +++ b/logos_delivery/waku/node/waku_node/lightpush.nim @@ -151,17 +151,27 @@ proc legacyLightpushPublish*( info "legacy lightpush send rejected as RLN-invalid; " & "refreshing merkle proof and retrying once" - let (retryMsg, _) = ( - await checkAndGenerateRLNProof( - rln, - msgWithProof, - forceMerkleProofRefresh = true, - reuseMessageId = drawnMessageId, - ) - ).valueOr: - return err("failed call checkAndGenerateRLNProof from lightpush retry: " & error) - return await internalPublish(node, pubsubForPublish, retryMsg, peer) + proc runRetry(): Future[legacy_lightpush_protocol.WakuLightPushResult[string]] {. + async, gcsafe + .} = + let (retryMsg, _) = ( + await checkAndGenerateRLNProof( + rln, + msgWithProof, + forceMerkleProofRefresh = true, + reuseMessageId = drawnMessageId, + ) + ).valueOr: + return + err("failed call checkAndGenerateRLNProof from lightpush retry: " & error) + return await internalPublish(node, pubsubForPublish, retryMsg, peer) + + let retryFut = runRetry() + if not (await retryFut.withTimeout(RlnRefreshRetryTimeout)): + warn "legacy lightpush RLN-refresh retry timed out; returning original error" + return firstResult + return retryFut.read() except CatchableError: return err(getCurrentExceptionMsg()) @@ -347,11 +357,23 @@ proc lightpushPublish*( info "lightpush send rejected; refreshing merkle proof and retrying once", statusCode = $firstResult.error.code - let (retryMsg, _) = ( - await checkAndGenerateRLNProof( - rln, msgWithProof, forceMerkleProofRefresh = true, reuseMessageId = drawnMessageId - ) - ).valueOr: - return lighpushErrorResult(LightPushErrorCode.OUT_OF_RLN_PROOF, error) - return await lightpushPublishHandler(node, pubsubForPublish, retryMsg, toPeer, mixify) + proc runRetry(): Future[lightpush_protocol.WakuLightPushResult] {.async, gcsafe.} = + let (retryMsg, _) = ( + await checkAndGenerateRLNProof( + rln, + msgWithProof, + forceMerkleProofRefresh = true, + reuseMessageId = drawnMessageId, + ) + ).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", + statusCode = $firstResult.error.code + return firstResult + return retryFut.read() diff --git a/logos_delivery/waku/rln/constants.nim b/logos_delivery/waku/rln/constants.nim index 6ffe51d2b..a2097ffc5 100644 --- a/logos_delivery/waku/rln/constants.nim +++ b/logos_delivery/waku/rln/constants.nim @@ -20,6 +20,12 @@ 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`. +const RlnRefreshRetryTimeout* = 5.seconds + # inputs of the membership contract constructor # TODO may be able to make these constants private and put them inside the waku_rln_utils const