建设中

建设中:我们正在 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. 交易类型

共六种类型。所有主体均为小端序;所有金额均以原子单位表示(除以 1e8 即为 ZBC)。

类型名称主体
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国际跳棋64 格 + 连跳锁定[from, to],强制吃子、连跳续走、王棋
5黑白棋64 格[cell 0..63],必须至少翻转一枚;无子可走的一方跳过;棋子最多者获胜
6五子棋225 格(15×15)[x, y],五子连线
7海战棋6400 承诺 + 200 揭示承诺-揭示,见下文
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×,三个 7 50×,任意一对 1.8×
20彩票[pick 0..99]90×
21爆点[target ×100, 2 bytes LE]目标 ×,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 棋子位置 + 待用骰子点数两阶段:掷骰,然后选择一枚棋子
33Pig 骰子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

玩家在用于开奖的种子产生之前两个区块就已提交,因此无法

预测或挑选种子。任何人事后都可以根据区块种子和应用 id 重新计算 r,

从而重新计算结果。结果不依赖任何链上没有的数据。

爆点游戏的爆点也取自同一个 r:


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

当 C >= target 时,下注赢得 stake × target / 100。分子中的 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)提交。

链会从应用的初始状态出发,通过同一个规则

引擎按顺序重放已签名的走法,核验每个签名和每个回合,并向获胜者付款。一次结算在上链后

的 240 个区块内,可被携带更高 final_seq 的结算覆盖;一旦挑战窗口

结束,结算即告完成。

主体上强制执行三项限制,集成者必须全部遵守:

  • final_seq 必须等于 move_count.
  • move_count 不得超过 1024 个条目。
  • move_count 不得超过剩余主体实际能容纳的数量。每个条目至少 67

字节(seat(1) + move_len(2) + signature(64)),因此大于 remaining / 67 的计数

会在分配任何字节之前就被拒绝。

1024 个条目是按单步(ply)计算的限制,而不是按回合计算:一个条目即一步,因此 1024 个条目的结算可覆盖一局 512 回合的对局。有记录以来最长的国际象棋对局为 269 回合、538 步,因此这一上限大约是实际对局最长纪录的两倍。

8. 海战棋(类型 7)

海战棋是唯一需要隐藏信息的一对一对战应用,因此采用承诺-揭示机制。

棋盘为 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 字节必须恰好为此值,否则创建会被拒绝