Hero hole cards render face down after ~1h on a table (auth signature never renewed)
Maintainers usually reply within 1 day
@bitcoinbrisbane is already working on this.
Since Nov 2, 2026.
Assessment
This issue has not been assessed yet.
Description
Summary
Several nights recently, a seated player was dealt hole cards that rendered face down (card backs) to that player. Everyone else's view looked normal. A browser refresh fixes it immediately. Related symptom previously reported in #409 (closed without an identified root cause).
Likely root cause (inferred from code, ~80% confidence)
The per-player websocket auth is signed once per socket and never renewed. After ~1 hour, the chain rejects it, and the relay silently falls back to the public (fully masked) state.
- UI signs once.
src/context/GameStateContext.tsx(block52/ui main, L302-310): on socket open,createAuthPayload()signspokerchain-query:<unix ts>and sends a singlesubscribe{gameId, playerAddress, timestamp, signature}. Nothing re-signs while the socket stays open. The wake handler (L462-485) returns early for an open, live socket (L473), so a tab becoming visible does not re-sign either. - Relay keeps the first signature forever. block52/pokerchain
pkg/wsserver/server.goL806-810 storesplayerId/timestamp/signatureon the client at subscribe. Every broadcast (sendPersonalizedUpdate, L538+, andauthedStateJSONinoptimistic.goL159-186) reuses them. - Silent masked fallback. On any error from the authenticated
GameState/OptimisticGameStatequery, the relay falls back to the publicGamequery (server.go~L462-473 and L565-568), where all hole cards are masked. No error is sent to the client. - Chain 1h window.
x/poker/keeper/query_game_state.goL47-56 (andquery_optimistic_game_state.goL39) reject a timestamp more than 1 hour from block time.
So ~60 min after the socket opened, every update reaches the hero with their own cards as X, and the seat draws backs. A refresh re-signs, which is why it fixes it.
Possible trigger for it showing up now: #910 (fix for #867) stopped a browser offline blip from tearing down an open socket. Previously those blips likely forced reconnects, and each reconnect quietly re-signed. Sockets now live longer than 1h more often. This is unverified.
How to confirm
- Relay logs for the affected player should show the authenticated query failing with
timestamp must be within 1 hour of block time, followed by the public-query fallback. - Repro: sit at a table for more than 60 min without refreshing. Hole cards should go face down at about the hour mark.
Load impact of the fix
One extra read-only signed query per player every 30-45 min (re-subscribe returns a fresh snapshot). No indexer involvement, negligible device cost.
Proposed fix
- Periodically re-sign and re-send
subscribeon the same socket every 30-45 min. The relay already overwrites stored credentials on a new subscribe. Apply the snapshot as a normal state update, withoutbus.reset(). - Re-sign and re-subscribe when the tab becomes visible again (
visibilitychange). - Debounced safety net: if the hero is seated in a live hand and their own hole cards arrive masked (
X/??), re-subscribe with a fresh signature once, with a debounce to avoid loops. - Follow-up for block52/pokerchain (relay): when a client's authenticated query fails, send an
auth_expiredevent (or keep the last per-player state) instead of silently serving the public masked state, and log it clearly.
Code refs: block52/ui main 12b9a929, block52/pokerchain v0.1.206 da56cd6.
- Dominant language
- TypeScript
- Stars
- 2
- Forks
- 5
- Avg merge
- 21h 50m
- Merged PRs (30d)
- 104
Getting set up
We have not checked this project's setup files yet. Start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from block52/ui
-
enhancement tech debt
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
feat(ui): player language setting and translated player screensPossibly taken @Dzeezbtc claimed this 1 day ago. Open
Difficulty 5/5 Over a week Newbie friendliness 25/100
Maintainers usually reply within 1 day
-
feat(ui): player notes and tags — click a seat to note a player; tag icons (fish, shark, tight, loose…) show by their pillPossibly taken @Dzeezbtc claimed this 4 days ago. Open
Difficulty 4/5 3-5 days Newbie friendliness 35/100
Maintainers usually reply within 1 day
-
architecture refactor tech debt
Difficulty 4/5 3-5 days Newbie friendliness 48/100
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 55/100
Maintainers usually reply within 1 day
Similar issues
-
unwrapDatabaseError masks real DB errors with TypeError: Cannot convert object to primitive valueOpen
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
NEARBuilders/everything-dev#798 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
vercel-labs/durable-harness#53 ·
Maintainers usually reply within 1 day
-
[Bug]: Redesign tab bars ignore clicks on Linux: hidden chat layers keep window drag regionsPossibly taken A pull request linked to this issue is open or already merged. Open
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
experiência: a doc manda subir para o Micro do Supabase, mas não diz que exige plano pago nem quanto custaPossibly taken A pull request linked to this issue is open or already merged. Openarea/docs area/ui enhancement
Difficulty 1/5 1-3 hours Newbie friendliness 88/100
melgarafael/DeskcommCRM#4098 ·
Maintainers usually reply within 1 day
-
dependencies platform: ios
Difficulty 1/5 1-3 hours Newbie friendliness 78/100
software-mansion/react-native-executorch#1617 ·
Maintainers usually reply within 1 day