Почему в Dice нет шага коммита?
Crash нужен зафиксированный секрет, потому что его результат должен быть определён, но скрыт, пока идёт раунд. У броска кубиков такой фазы нет: результат используется в той же инструкции, которая его вычисляет. Поэтому вместо коммита секрета вычисление просто не использует никаких данных от оператора: нечего фиксировать, нечего раскрывать, и нет сида, который оператор мог бы подобрать в свою пользу. Энтропия берётся из самой сети Solana и смешивается со значениями, которые идентифицируют вашу ставку:slothash: самая свежая запись sysvarSlotHashesсети Solana в момент исполнения транзакции вашей ставки. Это энтропия, созданная сетью, и при сборке транзакции она неизвестна (отправитель не может знать, в какой именно слот попадёт транзакция).user: 32-байтный адрес вашего пользовательского аккаунта в блокчейне (аккаунта, который программа выводит из вашего кошелька). Благодаря этому броски разных игроков независимы: две ставки, попавшие в один слот, получат разные броски.nonce: ваш личный счётчик ставок, который хранится в блокчейне и увеличивается с каждой игрой. Благодаря ему ваши собственные ставки подряд независимы даже внутри одного слота, а заодно он защищает от повторной отправки.
Какова точная формула броска в Dice?
- Вход хеша — это конкатенация строго в таком порядке: ASCII-метка
"dice", хеш слота, адрес пользовательского аккаунта, затем nonce, закодированный как 8 байт little-endian. - Выборка — это первые 16 байт результата SHA-256, прочитанные как беззнаковое 128-битное целое в порядке big-endian и взятые по модулю 10,000.
- Взятие 128-битной выборки по модулю 10,000 даёт теоретическое смещение меньше 2⁻¹¹⁴ — на десятки порядков меньше преимущества казино. Поэтому оно задокументировано, а не исправлено.
Условие выигрыша и выплата
edge_bps = 150):
Ожидаемый возврат одинаков для любой цели:
шанс × множитель ≈ 98.5% от ставки (округление вниз даёт перевес в пользу казино не более чем на один базисный пункт). Текущее преимущество и лимиты указаны на странице Комиссии и лимиты.
Что гарантировано, а что нет
Обеспечивается программой:- Бросок вычисляется и рассчитывается внутри одной инструкции в блокчейне, из данных, которые программа считывает сама. Бэкенд не передаёт бросок и не может исказить его.
- Оператор не вносит никаких данных в вычисление: нет серверного сида, который можно было бы перебирать ради выгодного результата.
- Ваш nonce должен быть передан в точности, поэтому одну и ту же ставку нельзя случайно (или намеренно) сыграть дважды.
- Каждая игра публикует все входные данные вычисления и результат, поэтому любой может пересчитать каждый бросок в истории.
N−1 становится публичным в начале слота N, так что оператор с очень низкой задержкой мог бы оценить, какой бросок получит ставка, если попадёт в текущий слот, и задержать отправку, чтобы перебросить. Схема признаёт это, а не делает вид, что проблемы нет (её устранение потребовало бы VRF-оракула, стоимость которого на одну ставку превышает ожидаемую прибыль казино на небольших ставках). Что сдерживает этот риск:
- Включение в блок нельзя полностью контролировать: точный слот, в который попадёт транзакция, определяет сеть, а не отправитель.
- Все входные данные публикуются, поэтому закономерности в задержке отправки и любое отклонение общей доли выигрышей от заявленных шансов может измерить кто угодно по публичным данным. Систематическое злоупотребление невозможно скрыть.
Как проверить бросок в Dice?
Каждая игра порождает событиеDiceBetSettled в собственной транзакции ставки со всем необходимым: slothash, user, nonce, target_bps, direction, win_chance_bps, roll, multiplier_bps и is_win, а также полной разбивкой расчёта. Чтобы проверить:
- Откройте транзакцию ставки в обозревателе Solana и считайте поля события (экран Dice в приложении показывает входные данные честности для вашей сессии, а история ставок содержит ссылку на транзакцию).
- Пересчитайте
sha256("dice" ‖ slothash ‖ user ‖ nonce), возьмите первые 16 байт в порядке big-endian по модулю 10,000 и сравните сrollиз события. - Проверьте определение выигрыша или проигрыша (
roll < targetдля «Меньше»,roll > targetдля «Больше») и множитель по формуле выше.