【问题标题】:How to generate a random number in solidity?如何在solidity中生成随机数?
【发布时间】:2018-07-28 16:07:23
【问题描述】:

我有几个 keccaks,如果我能找到一种便宜的方法来获取创建的 uint 的一部分,可以减少到一个。

pragma solidity ^0.4.19;

contract test {
  function test() {

  }

function sup() returns (uint test) {
    uint _test = uint(keccak256("wow"));
    return _test;
  }
}

这返回给我一个甜蜜的随机数:13483274892375982735325

现在的计划是,与其用不同的“种子”调用 keccak 5 次,我可以把这个数字拆开,得到类似的东西: 1348、3274、8923 等 然后我将其用作我的随机数,例如:1348 % 10

但solidity 不能仅仅做到这一点。有什么便宜的可以用吗?

【问题讨论】:

标签: string split ethereum solidity smartcontracts


【解决方案1】:

这是我最好的尝试。基于一个不同的问题,我再也找不到了。如果我这样做,我会链接它。

pragma solidity ^0.4.19;

contract test {

event randomNumbers(uint[8] numbers, uint[8] randomNumbers);

function testa() public returns (uint[8] bla) {

    //uint something = 12345678123456781234567812345678;
    uint something = uint(keccak256("rockandroll"));

    uint[8] memory array;
    uint[8] memory random;

    for(uint i=0; i<8; i++) {
        uint digit = something % 10000;
        // do something with digit
        array[i] = digit;
        something /= 10000;
        random[i] =digit % 10;
    }

    randomNumbers(array,random);

    return array;
}

【讨论】:

    【解决方案2】:

    要生成一个伪随机数,您可以执行类似的操作

    function random() private view returns (uint) {
        return uint(keccak256(block.difficulty, now));
    } 
    

    如果您需要特定范围内的随机数,例如,您可以使用模数。例如,要获取 0 到 999(包括)之间的随机数,您可以按如下方式进行:

    function random() private view returns (uint) {
        uint randomHash = uint(keccak256(block.difficulty, now));
        return randomHash % 1000;
    } 
    

    如果你有例如另一个可用的数组类型字段,您可以将其长度作为附加参数传递给keccak256 函数。

    (所有代码均使用v0.4.17编译)。

    【讨论】:

      【解决方案3】:

      为了防止操纵,您需要一个多于伪随机数。

      看看randao smart contract。它提供了攻击者无法轻易操纵的实际随机数。

      【讨论】:

        【解决方案4】:

        Solidity 合约是确定性的。任何了解您的合约如何产生随机性的人都可以预测其结果并使用此信息来利用您的应用程序。

        一种选择是produce randomness off-chain(无法预测)并在您的智能合约中使用它。 Chainlink VRF 是一个易于实现的解决方案,用于在智能合约中使用随机数据。这是一个请求和接收随机数据的示例 sn-p:

        requestRandomness(keyHash, fee, seed);
        

        您的合约请求在回调函数中完成:

        function fulfillRandomness(bytes32 requestId, uint256 randomness) external override {
          // Do something with randomness
        }
        

        实现随机数的完整合约示例如下:

        pragma solidity 0.6.2;
        
        import "https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/VRFConsumerBase.sol";
        
        contract Verifiable6SidedDiceRoll is VRFConsumerBase {
            using SafeMath for uint;
        
            bytes32 internal keyHash;
            uint256 internal fee;
        
            event RequestRandomness(
                bytes32 indexed requestId,
                bytes32 keyHash,
                uint256 seed
            );
        
            event RequestRandomnessFulfilled(
                bytes32 indexed requestId,
                uint256 randomness
            );
        
            /**
             * @notice Constructor inherits VRFConsumerBase
             * @dev Ropsten deployment params:
             * @dev   _vrfCoordinator: 0xf720CF1B963e0e7bE9F58fd471EFa67e7bF00cfb
             * @dev   _link:           0x20fE562d797A42Dcb3399062AE9546cd06f63280
             */
            constructor(address _vrfCoordinator, address _link)
                VRFConsumerBase(_vrfCoordinator, _link) public
            {
                vrfCoordinator = _vrfCoordinator;
                LINK = LinkTokenInterface(_link);
                keyHash = 0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205; // hard-coded for Ropsten
                fee = 10 ** 18; // 1 LINK hard-coded for Ropsten
            }
        
            /** 
             * @notice Requests randomness from a user-provided seed
             * @dev The user-provided seed is hashed with the current blockhash as an additional precaution.
             * @dev   1. In case of block re-orgs, the revealed answers will not be re-used again.
             * @dev   2. In case of predictable user-provided seeds, the seed is mixed with the less predictable blockhash.
             * @dev This is only an example implementation and not necessarily suitable for mainnet.
             * @dev You must review your implementation details with extreme care.
             */
            function rollDice(uint256 userProvidedSeed) public returns (bytes32 requestId) {
                require(LINK.balanceOf(address(this)) > fee, "Not enough LINK - fill contract with faucet");
                uint256 seed = uint256(keccak256(abi.encode(userProvidedSeed, blockhash(block.number)))); // Hash user seed and blockhash
                bytes32 _requestId = requestRandomness(keyHash, fee, seed);
                emit RequestRandomness(_requestId, keyHash, seed);
                return _requestId;
            }
        
            function fulfillRandomness(bytes32 requestId, uint256 randomness) external override {
                uint256 d6Result = randomness.mod(6).add(1);
                emit RequestRandomnessFulfilled(requestId, randomness);
            }
        
        }
        

        【讨论】:

        • 请记住,以这种方式生成随机数需要付费(在 LINK 中支付)。
        • 您在以太坊上的每个请求将花费 10 LINK。 1 个链接 = 今天 22.5 美元。如果您的项目是一个具有 1000 个 NFT 的 NFT 项目,并且您想确保在每个铸币厂都使用了“无法预测的随机数”。你可以算算。
        【解决方案5】:

        您不能创建真正的随机数,但可以创建伪随机数。由于solidity发展非常迅速,其他答案已经过时。这个答案有一天会过时,但现在你可以像这样实现一个伪数生成器:

          function random() private view returns (uint) {
                // sha3 and now have been deprecated
                return uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp, players)));
                // convert hash to integer
                // players is an array of entrants
                
            }
        

        这将返回非常非常大的数字。但是我们使用模运算符。

        random() % players.length
        

        这将返回一个介于 0 和 player.length 之间的数字。我们为此编写了一个函数:

        function pickWinner() public {
                uint index=random()%players.length;
            }
        

        【讨论】:

        • 如果此函数被快速连续调用多次,由于在中间调用中 block.difficult 和 block.timestamp 没有改变而返回相同数字的可能性有多大?
        • @GGizmos 正如我提到的“你不能创建真正的随机数,但你可以创建伪随机数”。你可以改变参数
        • 您可以添加对将在每次调用之间更改的状态变量之一的引用。最简单的例子是uint randomCallCount
        猜你喜欢
        • 2022-11-10
        • 1970-01-01
        • 2022-12-18
        • 2018-10-08
        • 2010-11-14
        • 2016-12-11
        • 2012-11-06
        • 2011-09-15
        • 2012-07-25
        相关资源
        最近更新 更多