如何生成随机数

时间:2018-02-18 06:03:33

标签: string split solidity uint

我有几个keccak,可以减少到一个,如果我找到一种便宜的方式来获取部分创建的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

但坚固不能做到这一点。有什么便宜可行吗?

5 个答案:

答案 0 :(得分:2)

实体合约具有确定性。弄清楚合同如何产生随机性的任何人都可以预期其结果,并使用此信息来利用您的应用程序。

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

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);
    }

}

答案 1 :(得分:1)

你不能创建真正的随机数,但你可以创建伪随机数。由于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() % player.length

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

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

答案 2 :(得分:0)

这是我最好的尝试。根据不同的问题,我找不到了。如果我这样做,我会链接它。

Array
(
    [0] => 56

    [1] => 98

    [2] => 53

    [3] => 49

    [4] => 7

    [5] => 50

    [6] => 56

    [7] => 63

)

答案 3 :(得分:0)

要生成伪随机数,您可以执行类似

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

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

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

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

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

答案 4 :(得分:0)

为了防止操作,您需要一个超过伪随机数。

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