1

I see that this has been a widely discussed topic in the past but I still don't understand why the future block hashes shouldn't be used for lottery-type games. As long as the incentive for a miner to not publish a given block (in order to alter the results of the game) is less than the difference in uncle vs main block reward, this should work. Given, that in case of losing in the game, the miner can choose to publish as an uncle so that the block hash does not determine the outcome of the game.

It's true that the game won't be completely shielded from miner influence, but considering that blockchains in general are based on incentives to keep everyone honest, this seems like a decent solution. Is there something that I'm missing?

0

This explains it pretty well: https://hackernoon.com/building-a-raffle-contract-using-oraclize-e746e5edff6b?gi=8ca2440bbace

Basically, all calculations on Ethereum network have to be deterministic so they can be validated by different nodes on the network, which doesn't work if they're all coming up with different numbers

Your statement considering that blockchains, in general, are based on incentives to keep everyone honest is incorrect - the blockchain is trustless - it doesn't need to depend on anyone being honest, that's why every transaction is being verified on all the nodes in the network and that's why you need confirmations for every transaction.

  • Well, there are incentives to keep miners honest - in many cases they get more rewards for being honest – Lauri Peltonen Feb 27 '18 at 21:08
  • But the idea is -the blockchain is setup as such that you don't need to rely on miners being honest. Thus it's impossible to generate a random number in a smart contract. – Andrey Feb 27 '18 at 21:12
  • @Andrey It seems that the question is not about using random numbers in a contract (there's already a lot of answers about this on this site) but about using a block hash as an unpredictable number. Hash is not known beforehand. But once calculated it's the same for everyone. So let's say you create a contract that makes you win if the Hask of block n+10 is greater than X, then no one can predict if this hash will be greater than X before it's generated but once the block n+10 is generated, everyone can verify if you won or not. Tell me if I misunderstood the question. – Nicolas Massart Feb 27 '18 at 23:37
  • I took the question as a more general one, about why block hash can't be used in a randomizer, as well as the statement that the miners are encouraged to be honest. If I misunderstood, my apologies. – Andrey Feb 28 '18 at 0:37
  • I agree, I meant to say is that given a sufficient amount of resources a blockchain can be attached (a 51% attack for example). However the attacked will have to spend a lot of money doing so. It's not that the miners are honest, but that there is an incentive to play by the rules and so the majority do. – H A Feb 28 '18 at 19:36
0

The notion that the future block hash can't be guessed overlooks the possibility that the attacker can be a purpose-built smart contract that will call the victim contract. The attacker doesn't need to know the "future" block hash, or anything else that might be a variable, because it can know the present block hash.

Consider this little example I created for a different question about "random(ish)" numbers.

pragma solidity 0.5.1;

contract Guess {
  function guessMe(uint guess) public returns(bool success) {
    return uint(blockhash(block.number)) == guess;
  }
}

So, it looks like someone has to send a guess, and the only way they can guess correctly (returns true) is if they somehow know the future.

It might be instructive to think hard about how to game this little contract with miraculous knowledge of the future. The method of doing so follows.

SPOILER ALERT

Now, if the attacker is a contract (or, a contract under the control of a human attacker) that calls this function then it is trivial to know the block hash of the current block (whenever it happens to be mined). It is:

uint(blockhash(block.number))

which can be copied from the contract to attack. Trivial.

Keep in mind that a chain of contract calls always completes in the same block as a single atomic transaction. Therefore, the attacker knows that it will execute in the exact same context as the victim, and it has access to the same variables. So ... it can perform the same calculation.

contract Attack {
    Guess g;
    event LogSuccess(address sender, bool success);
    constructor(address guessIt) public {
        g = Guess(guessIt);
    }
    function nostrodamus() public {
        if(g.guessMe(uint(blockhash(block.number)))) {
            emit LogSuccess(msg.sender, true);
        }
    }
}

That attacker will be able to generate correct guesses every time. The author needed to do nothing more than copy/paste an expression from the contract it wants to attack.

TL;DR;

Smart contracts are deterministic and generating something that others can't confirm is, by definition, harder than it looks. Exercise extreme caution with such assumptions and seek peer-review and formal audits to avoid grief.

I would argue that relying on block hash is insufficient for this sort of thing and relying on it could lead to grief unless you know what you're doing, but it's not the sort of thing that is incompatible. In other words, don't notice it in an expression and assume the process is automatically wrong.

One method to explore is a commit/reveal process, wherein the competitors must make a choice in one block, followed by the addition of more randomness (additional blocks go by). In many cases, truly random numbers are not a strict requirement. Numbers that are impossible to guess (including miner collusion) may be sufficient.

In any case, do not underestimate the difficulty level.

Hope it helps.

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.