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);
// ...
}似乎在合并之后,获得一个固定的随机值可能是可行的。
这可能是链式vrf的一个很好的替代品?
发布于 2022-10-13 13:09:03
摘要
对于伪随机性,您可以使用类似于EIP-4399的东西
uint256 randomness = uint(keccak256(abi.encodePacked(msg.sender, block.difficulty, block.timestamp)));(您甚至不需要使用程序集,difficulty是直接公开的)
但是对于真正的随机性,你需要一些类似链式VRF的东西。
function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
uint256 randomness = _randomWords[0];
}为什么difficulty或PREVRANDAO在合并后的ETH中是伪随机的?
当验证器将提议一个块时,他们将面临一个相当小的惩罚,因为它没有这样做。如果一个智能契约试图通过PREVRANDAO使自己不可预测/无法控制,则此选项允许他们以以下方式对契约的行为进行低成本的偏差。
1.您总是需要一个验证器来连续提出两个块。
如果没有建议块,PREVRANDAO的值就没有熵,给出了前一个块的PREVRANDAO值。当您提议一个块时,这是PREVRANDAO用来生成随机数的数学方程的一部分。因此,如果不提议块,就会得到一个“较少”的随机数。
因此,PREVRANDAO的用户需要检查验证器自上次调用PREVRANDAO以来是否提供了一个块。否则,他们不一定会在对PREVRANDAO的连续调用中绘制统计独立的随机输出。
这意味着,致力于提议特定块的验证器可以有效地将下一个块的PREVRANDAO值设置为两个可能的值:
PREVRANDAO输入值产生的PREVRANDAO设置为仅此选择就允许验证器影响随机数,不再使数字随机。
即使契约做了一些更聪明的事情,比如在某个高度之后从提议的第一个块获取PREVRANDAO输出,那么在该高度之后的每个验证器都有相同的选项。无论契约试图访问PREVRANDAO的哪种方式,最后一个提交文件的验证器总是对控制契约的随机输出具有可预测的控制。
Chainlink VRF不会出现这些问题,因为给定块散列,输出是确定性的(对于任何不知道秘密密钥的人来说,计算都是不可行的)。
2.如果数字不利,验证器可以选择不投递。
再次,您仍然会从预合并中遇到这个问题。不张贴一个块的惩罚几乎可以忽略不计,因此如果PREVRAND值不是他们想要的,那么节点可能会在财政上被激励不要在彩票类型的智能合同中提议块。足够多的节点这样做,您就会遇到问题。
仅在不查看最近历史的情况下获取当前的PREVRANDAO值,就可以让验证器控制契约将使用的输出,即使它不想中止,因为验证器可以决定它提议的块是否包含将触发使用PREVRANDAO的事务。唯一涉及的费用是交易费/小费。
3.如果所有应用程序都使用PREVRANDAO作为种子
如果所有的应用程序都使用PREVRANDAO作为种子,那么在某种程度上,您可以在此基础上“链接”胜利者或黑客。
更多信息
在以太术士论坛上也有一条有趣的帖子。
https://stackoverflow.com/questions/73938799
复制相似问题