Chainlink VRF 还是 RANDAO?

bbu*_*ver 2 solidity chainlink

    bytes9 private _randomness;

    function getRandomness() public view returns (uint256) {
        return uint256(keccak256(abi.encode(_randomness, address(this))));
    }
    
     modifier updateRandomness() {
        bytes32 randomness = _randomness;
        assembly {
            // Pick any of the last 256 blocks psuedorandomly for the blockhash.
            // Store the blockhash, the current `randomness` and the `coinbase()`
            // into the scratch space.
            mstore(0x00, blockhash(sub(number(), add(1, byte(0, randomness)))))
            // `randomness` is left-aligned.
            // `coinbase()` is right-aligned.
            // `difficulty()` is right-aligned.
            // After the merge, if [EIP-4399](https://eips.ethereum.org/EIPS/eip-4399)
            // is implemented, the randomness will be determined by the beacon chain.
            mstore(0x20, xor(randomness, xor(coinbase(), difficulty())))
            // Compute the new `randomness` by hashing the scratch space.
            randomness := keccak256(0x00, 0x40)
        }
        _randomness = bytes9(randomness);
        _;
    }

    function generateNFT() external updateRandomness {
        uint256 randomNum = getRandomness();
        uint256 remaining = MAX_SUPPLY - totalSupply();
        uint256 newId = (randomNum % remaining);
        // ...
    }

Run Code Online (Sandbox Code Playgroud)

似乎合并后,获得可靠的随机值可能是可行的。

这可能是 chainlink VRF 的一个很好的替代品吗?

Pat*_*ins 5

概括

对于伪随机性,您可以使用类似EIP-4399的东西:

uint256 randomness = uint(keccak256(abi.encodePacked(msg.sender, block.difficulty, block.timestamp)));
Run Code Online (Sandbox Code Playgroud)

(你甚至不需要使用汇编,difficulty直接暴露在solidity中)

但为了真正的随机性,你需要像Chainlink VRF这样的东西。

    function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
        uint256 randomness = _randomWords[0];
    }
Run Code Online (Sandbox Code Playgroud)

为什么合并后的 ETH 中difficulty或 是伪随机的?PREVRANDAO

当验证者打算提出一个区块时,他们会因未能这样做而面临相当小的惩罚。考虑到智能合约试图通过 使其自身变得不可预测/无法控制PREVRANDAO,此选项允许他们通过以下方式廉价地偏向合约的行为。

1.你总是需要一个验证者来连续提出两个区块

PREVRANDAO如果没有提出块,则给定前一个块的值, 的值没有熵。当您提出一个块时,它是用于生成随机数的PREVRANDAO数学方程的一部分。PREVRANDAO因此,如果您不提出区块,您会得到一个“较少”的随机数。

因此,用户PREVRANDAO需要检查验证器自上次调用以来是否已提供块PREVRANDAO。否则,他们不一定会在连续调用 PREVRANDAO 时绘制统计上独立的随机输出。

这意味着致力于提议特定区块的验证者可以有效地将下一个区块的 PREVRANDAO 值设置为两个可能的值:

  • PREVRANDAO由其规定的输入值产生的结果
  • PREVRANDAO如果没有提出块,则确定性地设置为任何内容

仅此选择就允许验证者影响随机数,而不再使数字随机。

即使合约做了一些更聪明的事情,比如PREVRANDAO从某个高度后提议的第一个块中获取输出,该高度后的每个验证器都有相同的选择。无论合约尝试以哪种方式访问PREVRANDAO​​,最后一个贡献的验证者始终对控制合约的随机输出具有可预测的控制权。

对于 Chainlink VRF 来说,这些问题不会出现,因为在给定区块哈希的情况下,输出是确定性的(对于不知道密钥的人来说,计算是不可行的。)

2. 如果数字不利,验证者可以选择不发布

再次,您仍然会在预合并时遇到此问题。PREVRAND不发布区块的惩罚几乎可以忽略不计,因此如果价值不是他们想要的,节点可能会受到经济激励而不在彩票类型的智能合约中提出区块。如果有足够多的节点执行此操作,您就会遇到问题。

仅获取当前PREVRANDAO值而不查看最近的历史记录可以让验证者对合约将使用的输出进行一些控制,即使它不想中止,因为验证者可以决定它提议的块是否包含将要使用的交易。触发使用 PREVRANDAO。唯一涉及的成本是交易费/小费。

3. 如果所有应用程序都PREVRANDAO使用

如果所有应用程序都使用PREVRANDAO作为它们的种子,在某种程度上,您可以基于此将胜利或黑客“链接”在一起。

更多信息

以太坊魔术师论坛上也有一个有趣的话题。

  • 将“block.difficulty”(现在是 prevrandao 值)与“msg.sender”相结合的建议是极其不安全的,如果有人选择遵循该建议,则可能会导致重大漏洞。混合这两个值意味着攻击者可以通过根据合约选择一个导致其期望结果的地址来完全规避 RANDAO 随机性。 (4认同)