抽签:谁产出下一个区块
在参与证明中,没有人为出块而竞速。对于每一个新高度,都会在节点注册表上进行一次随机抽签,按顺序指定出块者:第一次抽签指定第 1 轮的出块者,第二次抽签指定第 2 轮的出块者,依此类推。每个节点都在相同的数据上运行同一次抽签,得到同一份名单,因此每个节点都知道谁可以产出下一个区块,并拒绝来自其他任何节点的区块。
人人都能重现的抽签
公平的抽签需要一种无人能控制、而人人都能重现的随机性。ZooBC 从前一个区块中获取这种随机性。每个区块都携带一个 64 字节的种子,这个值是其出块者无法选择的(见 区块种子(VRF))。种子用来初始化一个伪随机数生成器,生成器产生的每个数都从可被抽中的节点名单中选出一项。
由于一个区块的种子只有在该区块产生之后才存在,没有人能提前知道再下一个区块的顺序:顺序通常只能提前一个区块知道。(持有大量席位的攻击者偶尔能看得更远;见 区块种子(VRF)。)又由于每个节点持有相同的前一区块和相同的注册表,每个节点算出的名单都相同。这里没有要解的谜题,没有公布的轮值表,也没有协调者。
抽签所用的名单
抽签从可选集合中选取:
- 以前一区块为准的活跃注册表,即已准入(已注册)的节点;排队中的节点不在其中;
- 按节点 id 从小到大排序(节点的 id 取自其节点密钥的前 8 个字节);
- 去掉每一个正处于暂停状态的节点(见 错过轮次、暂停与除名)。如果去掉它们后一个节点都不剩,则改用整个活跃集合。
如果所有活跃节点都被暂停,队列中一直保持出勤的最佳节点会作为恢复候选者加入(见 队列),使链总能重新启动;它产出的区块会立即让它获得准入。
区块严格按照前一区块时的注册表来判定,不会退而参照其他任何高度。来自一个未在其轮次被抽中的节点的区块,会被每个节点拒绝。
生成器
确切的算法如下,每一种实现都必须逐位遵循:
h = SHA3-256("zbc-blocksmith" ‖ seed of the previous block)
v = bytes 24 to 31 of h, read as a big-endian 64-bit number
Splitmix64(v) seeds a xoroshiro128+ generator
each draw: r = the next non-negative 63-bit number
the draw names entry (r mod n) of the selectable set, n = its size
第 1 次抽签指定第 1 轮的出块者,第 2 次抽签指定第 2 轮的出块者,依此类推(见 轮次、时间与窗口)。各次抽签相互独立,因此同一个节点可能在一份名单中被指定不止一次。
标签 zbc-blocksmith 使这次抽签与从区块种子得出的其他随机选择相互区分,每种选择都使用自己的标签:coinbase 抽奖 用 zbc-coinbase,回执与网络拓扑 用 zbc-receipt 和 zbc-receipt-datum,对等节点拓扑用 zbc-topology-v2,ZooBC 上的应用 用 zbc-apps。
每个席位的机会都相同
每次抽签以相同的概率选取可选集合中的每一项。其他任何因素都不参与:不看节点的硬件,不看其所有者的余额,不看其质押,也不看其参与分数。在 30 个活跃席位中持有 3 个的运营者,大约每十个区块产出一个。
这是参与证明的首要设计目标:均等的出块权力。获得更多权力的唯一途径是更多席位,而席位只能通过队列获得,一次准入一个,节奏由协议设定(见 准入节奏)。让分数不参与抽签是有意为之:分数高的节点赚得更多,但它产出的区块不会更多,选择的种子不会更多,把交易排除在外的机会也不会更多。
两项细化规则
- 前一个出块者。 产出前一区块的节点仍留在可选集合中,但它的抽签结果被视为不早于第 10 轮,因此它只能作为较晚的后备者产出下一个区块。见 优先轮次、空区块与前一个出块者。
- 后期轮次。 从第 11 轮起的出块者只能产出不含交易的区块。同样见 优先轮次、空区块与前一个出块者。