How to generate a random number in solidity?

|▌冷眼眸甩不掉的悲伤 提交于 2020-07-16 04:36:30

问题


I have a couple of keccaks, which could be reduced to one, if I would find a cheap way to get parts of the created uint.

pragma solidity ^0.4.19;

contract test {
  function test() {

  }

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

This returns me a sweet random number: 13483274892375982735325

Now the plan is that instead of calling keccak 5 times with different "seeds", I could take that number apart and get something like: 1348, 3274, 8923 etc. which I then use for my random number e.g.: 1348 % 10

But solidity can't just do that. Is there anything cheap that could work?


回答1:


Solidity contracts are deterministic. Anyone who figures out how your contract produces randomness can anticipate its results and use this information to exploit your application.

One option is to produce randomness off-chain (where it cannot be predicted) and use it in your smart contract. Chainlink VRF is an easy-to-implement solution for using random data in smart contracts. Here's an example snippet to request & receive random data:

requestRandomness(keyHash, fee, seed);

Your contract's request is fulfilled in a callback function:

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

An example of a full contract that implements a random number would be:

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

}



回答2:


Here my best attempt. Based on a different problem I can't find anymore. If I do I'll link it.

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



回答3:


To generate a pseudo-random number you could do something like

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

If you need a random number in a specific range you can e.g. use modulo. For instance to get a random number between 0 and 999 (both incl.) you can do it as follows:

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

If you have e.g. another field of type array available, you could pass its length to the keccak256 function as an additional argument.

(All code was compiled with v0.4.17).




回答4:


In order to prevent a manipulation you need a more than pseudorandom number.

Have a look at the randao smart contract. It provides actual random numbers that an attacker can not easily manipulate.



来源:https://stackoverflow.com/questions/48848948/how-to-generate-a-random-number-in-solidity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!