VEP 12: VITE 中随机数的实现

背景

在当前 VITE 链中,有许多地方需要使用随机数,例如共识和竞猜合约。 共识在决定下一轮由那一个节点获得出块权时,会做一定的随机选取策略,这种随机能够有效的避免出块顺序的可预测,提高了系统整体的健壮性。 而竞猜类合约是一个依靠竞猜随机而产生的游戏,如果在竞猜的过程中随机数被预知和被操控的话,对所有参与合约的人来说都是不公平的。 由此,VITE 协议需要实现随机数,并且能满足以下几个要求:

  1. 不可以被操控;
  2. 不可以被预测;

随机数实现目标

  1. 不可以被操控;
  2. 不可以被预测;

方案

VITE 随机数的方案是从现实生活中猜骰子的游戏中演化出来的。 假设玩猜骰子游戏,会经历以下步骤;

  1. 庄家在使用骰子筒来摇骰子;
  2. 玩家猜测骰子大小,并进行下注;
  3. 庄家揭开骰子筒,展示结果;

对于上面的小游戏,庄家可以使用两种方式进行作弊:

  1. 庄家在玩家下注后,暗中改变骰子点数;
  2. 庄家提前控制摇骰子结果,使用马甲伪装成玩家进行下注;

现实生活中,通过如下方式来防止庄家进行作弊,但这些都不能保证庄家不进行作弊。

  1. 对庄家使用器具 (包括骰子筒和骰子) 进行检查;
  2. 对庄家要骰子的过程进行严格的监督;
  3. 庄家使用自己的信誉作为担保;

对于区块链世界,可以使用更加安全有效的方式来防止庄家操控骰子点数 (即生成随机数);

  1. 引入多个庄家,使用多个庄家生成随机数结果汇总为最后的结果,只要有一个庄家不参与作弊,整体结果就随机(大大提升了作弊的成本,降低了作弊的概率);
  2. 庄家生成随机数后,需要公布随机数的 hash,然后玩家才进行下注,庄家最后公布的随机数需要和前面的 hash 对应(有效的防止了庄家篡改随机数);

将上面的方案具体映射到 VITE 中实现如下图 1:

figure

图 1

每个随机数从产生到应用经历三个阶段:

  1. 随机数的 公布阶段;(类比摇骰子)
  2. 公布随机数 阶段;(类比揭露骰子结果)
  3. 随机数 的应用;(类比依据骰子结果确定输赢)

上图中,从 分别是有 3 个 SBP 生产的区块(当然,实际环境下不止有 3 个 SBP),每个 SBP 生产两个 block。 每个 SBP 在生产一个区块的时候,需要发布这一轮随机数的 hash 和上一轮的随机数,例如 中发布的随机数 hash 为 ,发布的上一轮随机数为 ,其中要求 ,即 " 对 取 Hash 之后要等于上一次发布的,否则 无效 "。

这样,每个 block 生产出来之后就可以结合上一轮的其他人发布的随机数,生成一个随机数种子。例如以 可以计算出随机数种子为: , , 的聚合。 而这个随机数结果在 发布之前不可预知的,且 的生产这也不能改变这一结果。 满足了随机数的两个条件:

  1. 不可以被操控;
  2. 不可以被预测;

在实际实现中,为了节约存储, 的类型为 uint64 的长度为 32byte .

同时,从安全性方面考虑,为了防止 uint64 的 hash 被穷举,hash 的规则是对随机数以及 block 的 prevHash 和时间戳进行 Hash:

上面说明了每一个 snapshot block 都可以计算出一个 random seed 来生成随机数,那么对于合约而言,如何确定 random seed 呢?

在 VITE 中,一个合约调用分为一个 request 和一个 response,如果合约运行需要随机数进行参与,合约需要等到 request 被快照之后再进行运行生成 response,使用 request 被快照的快照块计算出随机数种子,然后结合 requestHash 进行使用,这样就能保证合约使用随机数不可操控和预测。

总结

随着随机数在区块链世界中应用场景的增加,一个不可被操控和预测的随机数对链的整体安全有着极大的促进作用。 VITE 随机数的实现,为 DAPP 中使用随机数来拓展应用场景打下了基础。