0

I've been doing some research on gasleft() (used to be msg.gas but is now deprecated) and was unable to find any specifics on how or where this value is defined. I was able to find another detailed ethereum stack exchange post talking about gasleft decrementing after every step in a function call.

If gasleft is only calculated and available DURING an EVM instruction execution, does that mean that it's non-deterministic and can be used for random number generation? If not, how would one even be able to calculate the cost of an instruction to try and exploit this in the scenario that it's used to generate random numbers? Anyone can change the gasLimit when sending a transaction and this would lead to non-deterministic in my understanding.

src: How is msg.gas calculated?

//gasLimit => 1000000

Random Instructions Costing GAS
gasleft(); => 870000
Random Instructions Costing GAS
gasleft(); => 820000
uint256 randomNumber = random();
Do Something With randomNumber

function random() internal returns (uint256) {
    return uint256(keccak256(abi.encodePacked(gasleft())));
}

To add on to this, I wrote a simple script that would mean the gas cost changes based on the number of people that decided to "mint" during a wave.

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.0;

contract TimebasedRNG {
    mapping (address => uint256) addressToTimestamp;
    address[] currentWaveMinters;
    uint256 currentWaveTime;
    uint256[] public randoms;

    function mint() external {
        require(addressToTimestamp[msg.sender] == 0, "already minted within a minute");
        if (currentWaveTime == 0) {
            currentWaveTime = block.timestamp;
            delete randoms;
        }
        currentWaveMinters.push(msg.sender);
        addressToTimestamp[msg.sender] = block.timestamp;

        if (hasBeenOneMinute()) {
            uint256 seed = 0;
            uint256 random;
            for (uint i = 0; i < currentWaveMinters.length; i++) {
                seed = uint256(keccak256(abi.encodePacked(
                    seed,
                    currentWaveMinters[i],
                    addressToTimestamp[currentWaveMinters[i]],
                    currentWaveTime,
                    gasleft()
                )));
            }

            for (uint i = 0; i < currentWaveMinters.length; i++) {
                random = uint256(keccak256(abi.encodePacked(
                    seed,
                    currentWaveMinters[i],
                    addressToTimestamp[currentWaveMinters[i]],
                    currentWaveTime
                )));
                randoms.push(random);
                delete addressToTimestamp[currentWaveMinters[i]];
            }
            delete currentWaveMinters;
            delete currentWaveTime;
        }
    }

    function hasBeenOneMinute() public view returns (bool) {
        return (block.timestamp - currentWaveTime) > 20 seconds;
    }
}

Could this be good enough of a pseudo-random number generator that it would be too difficult to exploit?

1
  • Just did some testing and found two transactions that run the same exact steps will cost exactly the same amount of gas. Which debunks my code above. However what if the code included some logic like statements and loops and would not be determinable. Would it still be possible to generate a provably random number? Nov 30, 2021 at 10:47

2 Answers 2

0

does that mean that it's non-deterministic

Everything is deterministic on a blockchain. Otherwise they would not function. Thus, your idea does not make sense.

0

Check out this on-chain Gaussian RNG here. I think although there is no true randomness on chain, the type of randomness can be more than just uniform.

Gaussian randomness can provide unique central tendency that will open up new possibilities.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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