feat: playable arcade — rooms, identity, client, deployment
Round length is now bounded: the multiplier follows a hyperbolic curve diverging at 60s, replacing an exponential one where a 275x crash point produced a two-and-a-half minute round. Fixes seed reveal, which silently failed every round because pgx cannot encode a fixed-size byte array as bytea. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
58
migrations/0002_rounds.sql
Normal file
58
migrations/0002_rounds.sql
Normal file
@@ -0,0 +1,58 @@
|
||||
-- Rounds, bets, and the verification record for every settled outcome.
|
||||
--
|
||||
-- Seeds are stored so that any round can be re-verified indefinitely. The
|
||||
-- server seed column is NULL until the round settles: revealing it early would
|
||||
-- let a player compute the outcome before betting closes.
|
||||
|
||||
CREATE TABLE rounds (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
game TEXT NOT NULL, -- 'rocket', 'orbital', 'tower'
|
||||
nonce BIGINT NOT NULL,
|
||||
commitment BYTEA NOT NULL, -- SHA-256 of the server seed
|
||||
server_seed BYTEA, -- revealed only after settlement
|
||||
client_seed BYTEA, -- derived from participants
|
||||
crash_point BIGINT, -- Q32.32 fixed-point
|
||||
opened_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
locked_at TIMESTAMPTZ,
|
||||
settled_at TIMESTAMPTZ,
|
||||
CONSTRAINT reveal_is_complete CHECK (
|
||||
settled_at IS NULL OR (server_seed IS NOT NULL AND crash_point IS NOT NULL)
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE bets (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
round_id BIGINT NOT NULL REFERENCES rounds(id),
|
||||
account_id BIGINT NOT NULL REFERENCES accounts(id),
|
||||
stake_msat BIGINT NOT NULL CHECK (stake_msat > 0),
|
||||
-- Set when the player cashes out; NULL means they rode it to the crash.
|
||||
cashout_at BIGINT, -- Q32.32 multiplier
|
||||
payout_msat BIGINT,
|
||||
placed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
settled_at TIMESTAMPTZ,
|
||||
UNIQUE (round_id, account_id)
|
||||
);
|
||||
|
||||
CREATE INDEX bets_round_idx ON bets (round_id);
|
||||
CREATE INDEX bets_account_idx ON bets (account_id, id DESC);
|
||||
|
||||
CREATE TABLE scratch_plays (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
account_id BIGINT NOT NULL REFERENCES accounts(id),
|
||||
ticket_id TEXT NOT NULL,
|
||||
nonce BIGINT NOT NULL,
|
||||
commitment BYTEA NOT NULL,
|
||||
server_seed BYTEA NOT NULL,
|
||||
stake_msat BIGINT NOT NULL CHECK (stake_msat > 0),
|
||||
tier_name TEXT NOT NULL,
|
||||
payout_msat BIGINT NOT NULL CHECK (payout_msat >= 0),
|
||||
cells INTEGER[] NOT NULL,
|
||||
played_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX scratch_account_idx ON scratch_plays (account_id, id DESC);
|
||||
|
||||
-- Rounds and plays are historical records; they are never rewritten.
|
||||
CREATE TRIGGER scratch_plays_append_only
|
||||
BEFORE UPDATE OR DELETE ON scratch_plays
|
||||
FOR EACH ROW EXECUTE FUNCTION reject_mutation();
|
||||
Reference in New Issue
Block a user