Files
plm-lottery/migrations/versions/d3e8b15a7c42_commit_reveal_draw_columns.py
T

68 lines
3.1 KiB
Python
Raw Normal View History

"""commit-reveal draw: round secret, participant order and draw height (B-73)
Revision ID: d3e8b15a7c42
Revises: b7d2e41c9a05
Create Date: 2026-10-14 16:40:00.000000
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'd3e8b15a7c42'
down_revision: Union[str, Sequence[str], None] = 'b7d2e41c9a05'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
_ACTIVE = "'open', 'closing', 'drawing', 'paying_out'"
def upgrade() -> None:
"""Upgrade schema.
B-73 (DAT-61 … DAT-66): the round's secret (`server_seed_enc`, `server_seed`,
`server_seed_hash`), the fixed participant list (`participants_hash`, `draw_height`,
`round_participants.draw_position`) and the number of confirmations the draw block
needs (`draw_confirmations` on the round, copied from `round_config` at open).
`bet_vout` records which output of a bet pays the pool; every existing bet pays it
with its first output.
Rounds that already exist keep NULL in the three secret columns (they were drawn,
or are drawn, on the block hash alone) and take the default of 3 confirmations.
Plain add_column / create_index calls — never batch_alter_table, which on SQLite
rebuilds the table and silently drops the expression indexes (B-97, DAT-56).
"""
op.add_column("rounds", sa.Column("draw_confirmations", sa.Integer(), server_default="3", nullable=False))
op.add_column("rounds", sa.Column("server_seed_enc", sa.Text(), nullable=True))
op.add_column("rounds", sa.Column("server_seed", sa.String(length=64), nullable=True))
op.add_column("rounds", sa.Column("server_seed_hash", sa.String(length=64), nullable=True))
op.add_column("rounds", sa.Column("participants_hash", sa.String(length=64), nullable=True))
op.add_column("rounds", sa.Column("draw_height", sa.Integer(), nullable=True))
op.add_column("round_participants", sa.Column("bet_vout", sa.Integer(), server_default="0", nullable=False))
op.add_column("round_participants", sa.Column("draw_position", sa.Integer(), nullable=True))
op.create_index(
"ux_round_participants_round_draw_position",
"round_participants",
["round_id", "draw_position"],
unique=True,
)
op.add_column("round_config", sa.Column("draw_confirmations", sa.Integer(), server_default="3", nullable=False))
def downgrade() -> None:
"""Downgrade schema."""
op.drop_column("round_config", "draw_confirmations")
op.drop_index("ux_round_participants_round_draw_position", table_name="round_participants")
op.drop_column("round_participants", "draw_position")
op.drop_column("round_participants", "bet_vout")
for column in ("draw_height", "participants_hash", "server_seed_hash", "server_seed", "server_seed_enc", "draw_confirmations"):
op.drop_column("rounds", column)
# drop_column on SQLite is a table rebuild: recreate the expression index (B-97).
op.execute("DROP INDEX IF EXISTS ix_rounds_single_active")
op.execute(f"CREATE UNIQUE INDEX ix_rounds_single_active ON rounds ((1)) WHERE status IN ({_ACTIVE})")