0

I was looking at generating some psuedo-random numbers in an Etheresum smart contract and understand that it is possible for miners to manipulate the blockhash and block.timestamp. The Solidity documentation says the following

Do not rely on block.timestamp or blockhash as a source of randomness, unless you know what you are doing.

Both the timestamp and the block hash can be influenced by miners to some degree. Bad actors in the mining community can for example run a casino payout function on a chosen hash and just retry a different hash if they did not receive any money.

The current block timestamp must be strictly larger than the timestamp of the last block, but the only guarantee is that it will be somewhere between the timestamps of two consecutive blocks in the canonical chain.

My question is if this is still possible with PoS, and if there is a way to create a safer pseudo-random number without the use of an oracle (aka paying LINK).

edit: Just found this that explains each block MUST be 12 seconds after the previous one- so I suppose using block.timestamp wouldn't be helpful even if it wasn't manipulatable since it can be predicted.

2 Answers 2

2

The best way would probably be using "prevrandao". It can be accessed in solidity using block.difficulty.

However, it can still be manipulated a little, see this blog for details https://soliditydeveloper.com/prevrandao

0

The question was answered thanks to 0xSanson.

TL;DR - as of solidity 0.8.17, use block.difficulty as it now = prevrandao = ~random number provided by the beacon chain.

EIP-4399 supplanted the DIFFICULTY opcode with PREVRANDAO. So the return value of the DIFFICULTY (0x44) instruction is now the output of the randomness beacon provided by the beacon chain.

As 0xSanson said, https://soliditydeveloper.com/prevrandao has a really nice, in-depth overview of how it works and how to implement it.

There is currently a pull request to add block.prevrandao so this may change in future versions.

edit: Another way to do this is to use a password no one knows until it is time for the random number to be generated. This relies on a non-malicious contract creator as well as a decent password, however.

generate the hashedPassword using keccak256(abi.encodePacked(password))

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract RandStuff {
    
    bytes32 public hashedPassword;

    constructor(bytes32 hashedPassword_) {
        hashedPassword = hashedPassword_;
    }

    function isPassword(string memory password) public view returns (bool) {
        if (keccak256(abi.encodePacked(password)) == hashedPassword) {
            return true;
        }
        return false;
    }

    function random(string memory password, uint256 maxRand)
        public
        view
        returns (uint256)
    {
        require (isPassword(password), "password incorrect");
        return uint256(keccak256(abi.encodePacked(password, blockhash(block.number)))) % maxRand;
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.