From 6ef40a5739f1723ec26cc32dfc48fe764f776dca Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Wed, 16 Sep 2026 19:57:45 -0400 Subject: fix: durable payouts survive journal failure, cap bank withdrawals, hash passwords off the owner loop. --- internal/game/game.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'internal/game/game.go') diff --git a/internal/game/game.go b/internal/game/game.go index 096e070..7255042 100644 --- a/internal/game/game.go +++ b/internal/game/game.go @@ -291,6 +291,20 @@ func (g *Game) HandleSessionOnOwner(sess *net.Session, input string) { if g.isShuttingDown() { return } + // Password work is expensive (Argon2id, ~64 MiB and tens of + // milliseconds per call) and must never run on the owner goroutine: + // the owner serializes every command and tick, so a burst of logins + // would stall the whole world. Verify/hash on the caller's connection + // goroutine, then submit one owner task for the (cheap) state + // transition. + switch sess.State { + case net.StatePassword: + g.handlePasswordOffOwner(sess, input) + return + case net.StateNewAccount: + g.handleNewAccountOffOwner(sess, input) + return + } g.RunOnOwner(func() { // Re-checked at task execution: the flag may flip between // submission and execution, and RunOnOwner must never fall back -- cgit v1.2.3