Retry PendingConfirm null lookups before dropping#64
Merged
Conversation
A user's source tx is often invisible to a validator's RPC for the first few seconds after submission (mempool propagation lag, regional RPC differences). Dropping the pending entry on the first null poll left the user without protocol recourse if their tx was still propagating. Treat tx_info=None like a transient provider failure for the first PENDING_CONFIRM_NULL_RETRY_LIMIT (3) consecutive polls — extend the reservation and keep the entry queued. Counter resets on any non-null response and is cleaned up alongside extend_reservation_voted_at.
entrius
approved these changes
Apr 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When the validator's
PendingConfirmloop polls a user's source tx and the chain provider returnstx_info=None, the entry is dropped immediately and the reservation expires silently. If the tx is still propagating through the mempool — or the validator's RPC happens to be on a node that hasn't seen it yet — the user's already-sent funds are stranded with no protocol recourse.This makes
tx_info=Nonetransient for the first 3 consecutive polls, mirroring the existing handling forProviderUnreachableError: extend the reservation and keep the entry queued. Drop only after the limit. Counter resets on any non-null response.PENDING_CONFIRM_NULL_RETRY_LIMIT = 3inconstants.pypending_confirm_null_pollsin-memory counter onValidator, mirrorsextend_reservation_voted_atin shape and lifecycleinitialize_pending_user_reservationscovers both dicts in one pass — no leakNarrows the still-propagating-tx window without touching the genuinely-not-found path (typo, dropped from mempool) — those still drop, just ~36s later.
Test plan
ruff format+ruff checkpass (verified locally)tests/test_pending_confirm_queue.pystill passes (state-store-only; unaffected)