一种在区块链上生成随机数的机制

2023-02-22

区块链本身不允许存在随机数,因为全部节点都需要同步计算结果,如果每次运行的结果不一样,整个网络就会混乱。也就是说,在区块链上,如果有一个函数的作用是生成随机数,这个函数需要符合两点要求:1. 返回值是不可预测的;2. 返回值是确定的。

这两点要求似乎相悖,但目前已经有解决方案了,Chainlink 的预言机提供了使用 VRF 来生成随机数的方法。由于 VRF 的特性,正好适合在区块链的场景中生成随机数。

不过现在要讨论的是另一个问题:矿工作恶。可以参考一下这篇文章的内容:How Not To Run A Blockchain Lottery

假如在区块链上运行一个彩票游戏,而矿工也参与了彩票下注,由于彩票中奖后会获得巨额奖励,只要巨额奖励超过矿工的挖矿所得,矿工就有足够的动机作恶。作恶的方式是,因为一笔交易的执行结果是确定的,而矿工会先知道结果,如果交易结果对自己不利,矿工可以拒绝出块。对于矿工来说,在经济上不一定划算,但是这种情况的存在,不但给彩票游戏增加了不公平的性质,还给了矿工作恶的权利。矿工也有被贿赂的可能性,如果矿工集体作恶,网络就乱套了。

面对这样的情况,我们需要一种方式来生成随机数,要求矿工不能知道这个数字是什么。等区块确认上链后,随机的数字才被公开。

有什么是真正的随机、难以预测呢?未来,未来无法预测。

我们可以尝试使用这样的方式:随机数用本次交易块高度 +2 个块的块哈希作为随机数种子。

比如发起一笔交易,要生成一个随机数,现在的块高度是 1,这笔交易提交后,得到的随机数是 null,真正的随机数将会在块高度达到 3 时才真正显示。因为这个随机数使用 3 的块哈希作为随机数的种子,在块高度达到 3 之前是不可能有人知道,这个数字将会是什么。

在彩票的场景中,抽奖结果在块高度为 1 是已经确定了,用户在块高度为 1 的交易中已经参与了抽奖,只是块高度为 3 时才公布抽奖结果。这样几乎能避免矿工作恶的问题,因为在块高度为 1 时,矿工也不知道结果是什么,在块高度为 3 时,参与抽奖的顺序和结果已经确定了。

那矿工在块高度 3 的时候,不还是可以拒绝出块吗?直接拒绝 1 块或者拒绝 3 块没有差别啊?

这里就需要区分两个情况:

要想达到完全随机的效果,应该使用第二种方式。

那问题又来了,当前块高度是不断变化的,这个随机值不就成变量了吗?用户在块高度是 3 的时候生成随机数,然后想知道这个随机数具体是多少,结果永远没办法得到这个值,因为等块高度是 5 的时候才真正产生这个数,而块高度是 5 的时候去查询,要等到块高度 7……

这里还需要区分两个概念:生成随机数和查询随机数。上面两种情况都是按照查询随机数的机制来描述的。

按照生成随机数的机制来设定,使用第二种方式是必须的,不然随机数就成常量了。那查询呢?不能否认的事实是,只要用户能查到的结果,矿工一定能查到,而且会提前知道。问题回到了一开始的困局,似乎无解了。

不对不对。

为什么要设定为使用块高度 +2,而不是 +1 块高度的块哈希呢?是为了避免矿工提前知道结果,如果是 +1,矿工挖出 1 个块就能知道结果,如果是 +2,矿工一般很难领先网络 2 个块。

所以更好的做法,是在块高度 1 发出生成随机数的请求,然后将块高度 2 和块高度 3 的块哈希,作为随机数种子。在这种情况下,矿工手里的第 3 个块会对随机数产生一定影响,但又不是决定性的影响,有可能第 2 个块就已经确定矿工与中奖无缘了,矿工将没有必要在第 3 个块上进行违规操作。

那如果第 3 个块也能很大程度决定随机数的内容呢?矿工仍然可以拒绝出块。

从这个角度来看,延后的块数越多,矿工的影响力越小。假如随机数由 +10 个块的块哈希决定,前 9 个块已经让所有矿工都出局了,矿工就不作恶了。

还有其他更好的方案吗?好像没有。假如将 +2 个块的块哈希作为对称加密的私钥,在 +2 块产生前随机值已经产生但是无法被解码,问题在于,合约也无法提前把 +2 块作为密钥对随机值进行加密。

只能降低矿工的影响力了。

未来无法预测,但当未来来临的时候,总有人能先知先觉。