30 lines
1.4 KiB
Python
30 lines
1.4 KiB
Python
"""Pausing the lottery from code (B-78, DAT-69, AUD-11).
|
|||
|
|
|
||
|
|
A pause only stops the *next* round from opening (rounds/service.py:rounds_can_open); a
|
||
|
|
round in progress still closes, draws and pays. Besides the operator's own switch there
|
||
|
|
are pauses the system raises itself when something needs a human look — a transaction
|
||
|
|
given up for dead that confirmed after all (`resurrected_tx`, B-78) and, in later
|
||
|
|
findings, a deep reorg (`reorg`, B-85) and a payout whose winning bet left the chain
|
||
|
|
(`payout_blocked`, B-82).
|
||
|
|
"""
|
||
|
|
|
||
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
|
|
||
|
|
from app.audit.log import write_audit_log
|
||
|
|
from app.rounds.config import get_round_config
|
||
|
|
|
||
|
|
OPERATOR_REASON = "operator"
|
||
|
|
AUTOMATIC_REASONS = ("reorg", "payout_blocked", "resurrected_tx")
|
||
|
|
|
||
|
|
|
||
|
|
async def pause_automatically(session: AsyncSession, reason: str) -> None:
|
||
|
|
"""Pause the lottery for an automatic `reason` in the caller's transaction and write
|
||
|
|
the `lottery_paused` row. An automatic reason is written even over a pause that is
|
||
|
|
already active (DAT-69): the cause that needs checking must not be hidden behind an
|
||
|
|
earlier one, and an operator pause is never what overrides it."""
|
||
|
|
if reason not in AUTOMATIC_REASONS:
|
||
|
|
raise ValueError(f"not an automatic pause reason: {reason!r}")
|
||
|
|
config = await get_round_config(session)
|
||
|
|
config.paused = True
|
||
|
|
config.paused_reason = reason
|
||
|
|
await write_audit_log(session, "lottery_paused", {"reason": reason})
|