Сайт в разработке

Сайт в разработке: мы создаём его к запуску MainNet. Детали будут меняться.

Этот сайт ещё строится

ZooBC развивается открыто. Всё, что вы здесь видите, актуально и честно, но ещё не завершено: воспринимайте это как картину того, где мы находимся сегодня, а не как окончательное заявление.

До запуска MainNet многое изменится: формулировки, структура, изображения и цифры. Некоторые страницы пока содержат только заглушки.

Экосистема ZooBC появляется поэтапно. Кошелёк, обозреватель и каналы сообщества запускаются по мере приближения MainNet, и этот сайт растёт вместе с ними.

Если что-то написано неверно, выглядит сломанным или кажется вводящим в заблуждение, сообщите нам. Отзыв сейчас для нас ценнее, чем безупречный запуск потом.

ZOOBC / РУКОВОДСТВО

Приложения ZooBC в блокчейне

Руководство по приложениям

Типы транзакций 24, 25, 26, 27, 28 и 39. Тела транзакций, реестр приложений, выплаты и способ самостоятельно проверить результат. Перенесено из исходного кода узла.

Приложение в ZooBC представляет собой игру или пари, правила которых исполняются в консенсусе. Каждый ход является транзакцией,

доска хранится в состоянии блокчейна, а выплату производит протокол. Нет ни сервера, которому надо доверять, ни

оператора, который может отказаться платить, ни результата, который приходится принимать на веру: всё

это может воспроизвести из истории блокчейна кто угодно и когда угодно.

Это руководство служит справочником для интеграторов: шесть типов транзакций, точные тела, реестр

приложений с кодировкой ходов каждого из них, движение денег, а также получение и проверка случайности.

Всё здесь переписано из исходного кода узла, include/zoobc/common/types.h,

src/transaction/app_rules.cpp, а также src/transaction/transaction_executor.cpp, а не из проектных

заметок, которые появились раньше реализации и местами от неё отличаются.

1. Три категории

КатегорияМестаКонтрагентСлучайностьТипы
Соло против казино1пул приложений протоколада, сид блока16–21
Один на один2другой игроктолько если приложение её использует1–8
Групповые3–4другие игрокикости из сида блока32–35

У всех трёх общий движок: те же типы транзакций, то же эскроу ставок, тот же срок на

каждый ход и то же правило: один ход равен одной транзакции.

seats определяет категорию и сверяется с типом приложения. У соло-приложения должно быть seats == 1

и тип в диапазоне 16–31; у многопользовательского приложения должно быть seats 2–4 и тип вне этого диапазона. Ошибка

здесь приводит к отклонению при приёме в мемпул, а не при исполнении.

2. Типы транзакций

Шесть типов. Все тела в порядке little-endian; все суммы в атомарных единицах (для ZBC делите на 1e8).

ТипНазваниеТело
24CreateAppapp_type(1) · stake_token_id(8) · stake_amount(8) · seats(1) · params_len(2) · params · [opponent(36)] · [channel(1)]
25JoinAppapp_id(8)
26AppMoveapp_id(8) · move_len(2) · move_bytes
27ResignAppapp_id(8)
28ClaimAppTimeoutapp_id(8)
39SettleAppapp_id(8) · final_seq(4) · move_count(4) · [seat(1) · move_len(2) · move · signature(64)]*

Два необязательных завершающих поля CreateApp

opponent и channel необязательны, а какие из них присутствуют, определяется по количеству байтов,

оставшихся после params:

Осталось байтовЗначение
0открытое приложение, игра в блокчейне
1channel только
36opponent только
37opponent затем channel

Поле opponent превращает приложение в персональный вызов: присоединиться может только этот адрес. Если его опустить, место

может занять любой. channel = 1 помечает приложение канала состояния и допустимо, только когда seats == 2.

Многопользовательские приложения хранят игроков в фиксированных 36-байтовых слотах, поэтому каждый адрес за столом должен быть в каноническом 36-байтовом виде (адрес ZBC или просто 32-байтовый открытый ключ). Аккаунты не из 36 байтов отклоняются при создании. У соло-приложений такого ограничения нет: там только один игрок.

3. Реестр приложений

app_type занимает один байт. Известны только эти значения; всё остальное отклоняется.

Один на один (2 места)

ТипПриложениеДоска / состояниеБайты хода
1Крестики-нолики9 клеток[cell 0..8]
2Шахматы64 поля[from, to], полная проверка правил, шах, мат, пат, автоматическое превращение в ферзя
3Connect-442 клетки (7×6)[column 0..6], гравитация, 4 в ряд
4Шашки64 клетки + блокировка серии взятий[from, to], обязательное взятие, продолжение серии взятий, дамки
5Реверси64 клетки[cell 0..63], нужно перевернуть хотя бы одну фишку; сторона без хода пропускает; побеждает тот, у кого больше фишек
6Гомоку225 клеток (15×15)[x, y], 5 в ряд
7Морской бой6400 на обязательство + 200 на раскрытиеcommit-reveal, см. ниже
8Точки и квадраты24 ребра + 9 квадратов[edge 0..23], замкнувший квадрат ходит ещё раз

Соло против казино

ТипПриложениеparamsВыплата
16Две кости[bet_type 0..3, total]меньше 7 / больше 7 2.28×, счастливая 7 5.7×, точная сумма 3420/ways %
17Подбрасывание монеты[choice 0/1]1.98×
18Рулетка[bet_type, value]одно число 36×, цвет 2×
19Слотынеттри одинаковых 15×, три семёрки 50×, любая пара 1.8×
20Лотерея[pick 0..99]90×
21Краш[target ×100, 2 bytes LE]target ×, от 1,01× до 10,00×

Типы ставок для костей: 0 меньше 7, 1 счастливая 7, 2 больше 7, 3 точная сумма. Для точной суммы

множитель равен 3420 / ways в сотых, где ways = 6 - |7 - total|, поэтому 7 выплачивает 5,70×, а 2 или

12 выплачивают 34,20×. В рулетке 37 ячеек; 0 зелёная и проигрывает для обоих цветов.

Групповые (3–4 места)

ТипПриложениеСостояниеБайты хода
32Лудоseats×4 позиции фишек + ожидающий бросок костив две фазы: бросок, затем выбор фишки
33Свиньяseats очки + сумма за ход[0 roll, 1 hold]
34Гонка («Змеи и лестницы»)seats позиции[0], бросок
35Монополия-лайтденьги, позиции, собственность, банкротство, фазав две фазы: бросок, затем покупка по желанию

4. Деньги

Ставки. CreateApp помещает ставку создателя в эскроу. Каждый JoinApp помещает в эскроу такую же ставку. Банк

равен их сумме. stake_token_id со значением 0 означает ZBC; любое другое значение означает ставку в этом цветном токене, и

всё приложение (банк, рейк, выплата) рассчитывается в этом токене.

Рейк. При результативном завершении 1% банка уходит в пул приложений, а победитель получает

остальное. При ничьей или отмене приложения все ставки возвращаются, и рейк не взимается.

Пул приложений представляет собой аккаунт протокола с отдельным балансом для каждого токена. Он пополняется за счёт рейка в 1% и

преимущества казино в соло-приложениях. Он выступает контрагентом по каждой соло-ставке, поэтому именно его баланс

вообще делает соло-игру возможной; посмотреть его можно в любой момент:


GET https://zoobc.network/api/v1/apps/pool

Лимит банкролла. Максимально возможная выплата по одной соло-ставке не может превышать 5% пула для

этого токена. Проверка идёт по худшему для казино исходу самой ставки, а не по среднему, поэтому ни

один выигрыш не может опустошить пул. Ставка, нарушающая лимит, отклоняется; если крупная ставка отклонена,

обычно причина именно в этом.

5. Случайность и как её проверить

Соло-приложения определяют исход по сиду блока, который в ZooBC вычисляется как

block_seed = blocksmith_signature(SHA3(previous_block.block_seed)): он детерминирован, публично

проверяем по открытому ключу создателя блока и не может быть известен до появления блока.

Ставка, сделанная в блоке на высоте H, разрешается на высоте H + 2:


r = SHA3-256( block_seed[H+2] ‖ app_id )   →   the low 8 bytes, little-endian, as a uint64

Игрок делает ставку за два блока до появления сида, по которому она разрешается, поэтому он не может

ни предсказать, ни выбрать его. Любой может затем пересчитать r по сиду блока и id приложения и

тем самым пересчитать исход. Результат не зависит ни от каких данных, которых нет в блокчейне.

Краш вычисляет точку краха из того же r:


u = r mod 1e6
C = 99_000_000 / (1_000_000 - u)      clamped to [100, 1000], i.e. 1.00× .. 10.00×

Ставка выигрывает stake × target / 100, если C >= target. 99 в числителе отражает преимущество

казино, 1%. Ограничение 10,00× служит потолком, поэтому максимальный выигрыш в Краше равен десятикратной ставке.

Мультиигра. Любое соло-приложение можно сыграть до 100 раз за одну ставку. Добавьте завершающий байт

счётчика N к params после байтов выбора этого приложения. Ставка делится поровну между N играми,

а выплаты суммируются, так что одна транзакция и одно раскрытие дают N независимых исходов без

ожидания блока для каждого. Отсутствие N означает одну игру, и одна игра побитово совпадает с тем, чем она

была бы до появления мультиигры. N должен быть в диапазоне 1–100, а ставка должна делиться так, чтобы на каждую игру

приходилась хотя бы одна единица.

6. Ходы, сроки и завершение

Приложение становится активным, когда занято последнее место. С этого момента каждый принятый ход устанавливает


deadline_height = current_height + 240        (~1 hour at 15 s per block)

Ход принимается только от игрока, чья сейчас очередь, только пока приложение активно и только

до истечения срока. Приложение может завершиться четырьмя способами:

  • Победа или ничья по правилам. Расчёт происходит сразу: победителю выплачивается выигрыш, а при ничьей все ставки возвращаются.
  • ResignApp. Вы сдаётесь; ваша доля банка переходит сопернику.
  • ClaimAppTimeout. Ваш соперник пропустил срок в 240 блоков. Вы подаёте требование и выигрываете банк.

Требование должны подать вы сами: ничего не происходит автоматически только потому, что срок истёк.

  • Никто не присоединился. Открытое приложение, которое никто не принял, отменяется, а ставка возвращается.

7. Каналы состояния и SettleApp

В приложении один на один игра в блокчейне стоит транзакции и блока на каждый ход.

Канал состояния заменяет это одним расчётом: создайте приложение с channel = 1 и seats = 2, играйте

вне блокчейна, причём каждая сторона подписывает каждый ход, и отправьте всю партию один раз как SettleApp (тип 39).

Блокчейн воспроизводит упорядоченные подписанные ходы от начального состояния приложения через тот же

движок правил, проверяет каждую подпись и очерёдность ходов и выплачивает выигрыш победителю. Расчёт может быть переопределён

другим расчётом с более высоким final_seq в течение 240 блоков после его включения в блок; когда это окно оспаривания

закрывается, расчёт становится окончательным.

К телу применяются три ограничения, и интегратор должен соблюдать все три:

  • final_seq должно равняться move_count.
  • move_count не может превышать 1024 записей.
  • move_count не может превышать того, что физически помещается в оставшуюся часть тела. Каждая запись занимает не менее 67

байтов, seat(1) + move_len(2) + signature(64), поэтому количество больше remaining / 67

отклоняется до выделения хотя бы одного байта.

Лимит в 1024 записи считается в полуходах, а не в парах ходов: одна запись соответствует одному полуходу, поэтому расчёт из 1024 записей покрывает партию в 512 ходов. Самая длинная из зафиксированных шахматных партий длилась 269 ходов, то есть 538 полуходов, так что лимит примерно вдвое превышает самую длинную партию, когда-либо сыгранную на самом деле.

8. Морской бой (тип 7)

Из всех приложений один на один только Морскому бою нужна скрытая информация, поэтому в нём используется схема commit-reveal.

Поле имеет размер 10×10. Для каждой из 100 клеток игрок выбирает случайную 32-байтовую соль и фиксирует

SHA3(is_ship ‖ salt); обязательство представляет собой конкатенацию этих 100 хешей, 3200 байтов, и передаётся как

params при создании. seats должно быть равно 2, а обязательство должно занимать ровно 3200 байтов, иначе создание

отклоняется.

В игре чередуются два вида ходов:

  • Выстрел [0, cell]: вы стреляете по клетке на поле соперника. Ход переходит к нему для раскрытия.
  • Раскрытие [1, cell, is_ship, salt(32)]: соперник доказывает, что там было, открывая обязательство

этой одной клетки. Поскольку каждая клетка зафиксирована отдельно, игрок не может солгать ни об одной клетке.

Попадание или промах записывается, и следующим стреляет раскрывший.

Попадите во все 17 клеток кораблей, и вы победили. Игрок, отказывающийся раскрывать, ограничен временем, как и при любом другом ходе,

поэтому применяется ClaimAppTimeout.

Комиссия зависит от размера. Создание на 3200 байтов является крупной транзакцией, а минимальная комиссия растёт с размером транзакции. В действующем блокчейне комиссия 0,1 ZBC была отклонена как слишком низкая, а около 5 ZBC была принята. Заложите это в бюджет при создании; ходы с выстрелом и раскрытием маленькие и дешёвые.

9. Чтение состояния приложения

Пять эндпоинтов обслуживает API узла; обратите внимание, что это эндпоинты узла, а не архивного узла:

Базовый URL https://zoobc.network/api/v1. Это публичный шлюз ZooBC TestNet, а не MainNet.

ЭндпоинтВозвращает
GET /api/v1/appsлобби; фильтрация через status=, category=solo|pvp|party, limit=
GET /api/v1/apps/openоткрытые вызовы один на один, к которым может присоединиться любой
GET /api/v1/apps/:idполное состояние одного приложения
GET /api/v1/apps/poolбалансы пула приложений по каждому токену
GET /api/v1/apps/statsтекущие показатели: всего, открытых, активных, завершённых, игроков, банк на кону

Строка приложения содержит id, app_type, status (0 открыто, 1 активно, 2 завершено, 3 отменено), seats,

creator_address, players, opponent_address, stake_token_id, stake_amount, pot,

state_blob, turn, created_height, last_move_height, deadline_height, resolve_height,

winner_address, persist_height и channel.

state_blob содержит текущую вычисленную доску, которая хранится, чтобы узлу не приходилось воспроизводить историю в каждом блоке.

Это удобство, а не первоисточник: первоисточником служат транзакции ходов, и клиент может воспроизвести

их для аудита или анимации. Текущая строка завершённого приложения удаляется после льготного периода; его ходы навсегда

остаются в истории блокчейна, поэтому приложение всегда можно восстановить.

10. Из командной строки

zoobc-cli поддерживает все шесть типов. Первым параметром всегда идёт закрытый ключ отправителя.

КомандаТип
app-create24
app-join25
app-move26
app-resign27
app-claim28
app-settle39

# a coin-flip against the house: type 17, 1 ZBC, seats=1, choice 0
zoobc-cli app-create <privkey> 17 0 100000000 1 00 --api $API

# tic-tac-toe, open to anyone, 1 ZBC
zoobc-cli app-create <privkey> 1 0 100000000 2 --api $API

# take the middle square
zoobc-cli app-move <privkey> <app_id> 04 --api $API

zoobc-cli help app-create выводит поля для любой из них. Полный набор команд описан в Руководстве по CLI,

а побайтовая структура всех 50 типов транзакций в Руководстве по транзакциям.

11. Константы

КонстантаЗначениеНа что влияет
Рейк1% банкав пул приложений, только при результативном завершении
Срок хода240 блоков~1 час; сбрасывается каждым принятым ходом
Разрешение соло-ставкивысота ставки + 2~30 секунд
Лимит банкролла5% пуламаксимальная выплата по одной соло-ставке
Лимит мультиигры100игр на одну соло-ставку
Лимит ходов в расчёте1024записей на SettleApp, ≥67 байтов каждая
Окно оспаривания расчёта240 блоков~1 час, в течение которого побеждает более высокий final_seq
Места1 или 2–41 для соло; 2–4 для мультиплеера
Обязательство Морского боя3200 байтовровно, иначе создание отклоняется