Как сгенерировать случайное число в массиве?

У меня есть пара 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

Но солидность просто не может этого сделать. Есть ли что-нибудь дешевое, что могло бы сработать?


person Garry Plays    schedule 18.02.2018    source источник
comment
проверьте здесь stackoverflow.com/questions/52467248/   -  person Alberto Perez    schedule 24.10.2020


Ответы (5)


Контракты Solidity детерминированы. Любой, кто выясняет, как ваш контракт создает случайность, может предвидеть его результаты и использовать эту информацию для эксплуатации вашего приложения.

Один из вариантов - создать случайность вне сети (где ее нельзя предсказать ) и используйте его в своем смарт-контракте. 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);
    }

}
person Community    schedule 28.05.2020

Вы не можете создать действительно случайное число, но можете псевдослучайное число. поскольку твердость развивается очень быстро, другие ответы устарели. Этот ответ однажды устареет, но на данный момент вы можете реализовать генератор псевдо-чисел следующим образом:

  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;
    }
person Yilmaz    schedule 30.04.2021

Вот моя лучшая попытка. Из-за другой проблемы я больше не могу найти. Если сделаю, то свяжу.

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;
}
person Garry Plays    schedule 18.02.2018

Чтобы сгенерировать псевдослучайное число, вы можете сделать что-то вроде

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

Если у вас, например, доступно другое поле типа array, вы можете передать его длину функции keccak256 в качестве дополнительного аргумента.

(Весь код был скомпилирован с помощью v0.4.17).

person Marteng    schedule 23.02.2018

Чтобы предотвратить манипуляцию, вам понадобится более чем псевдослучайное число.

Взгляните на смарт-контракт randao. Он предоставляет фактические случайные числа, которыми злоумышленник не может легко манипулировать.

person der_michael    schedule 10.03.2018