1

Suppose your contract has a function which generates a random treasure, as illustrated below:

function generateTreasure() returns (Treasure) {
    if (msg.value < 1 ether) return; // cost of calling the message
    uint8 rnd = randomUint8();
    if (rnd ==  0) return rareTreasure;
    if (rnd <=  4) return averageTreasure;
    if (rnd <= 16) return commonTreasure;
    return garbage;
};

I want to guarantee that an user calling generateTreasure will not be able to cheat the result by any external means - i.e., I want it to cost, in average, 256 ether for any user to acquire a rareTreasure. That wouldn't be true if an attacker found a way to get a rareTreasure more than 1/256 times in average per generateTreasure call.

I am aware an miner could cheat it by discarding a mined block - but, on this case, the situation is different. A single user could call generateTreasure many times in a single block, and multiple users could call it. Of course I don't want to give the same treasure for all users, so, that would need some form of stateful nonce (lastRandom) so each caller gets a different number. But, then, that would mean an user could create a contract that reads that nonce and only calls generateTreasure if it provides a good treasure with said block hash! Is that correct?

So, all things considered, what is the most appropriate randomization for that function?

  • Wouldn't using a nonce ensure that the same number can't be returned twice in a row? If so, haven't you lost some degree of randomness? (i.e. True randomness would allow the same number to returned any number of times.) – Richard Horrocks Jul 27 '16 at 20:44
  • Probable duplicate of this thread: ethereum.stackexchange.com/questions/191/… – Richard Horrocks Jul 27 '16 at 20:45
  • @RichardHorrocks I have read this whole thread before asking, none of those questions address this issue if I understand correctly. – MaiaVictor Jul 27 '16 at 22:26
2

But, then, that would mean an user could create a contract that reads that nonce and only calls generateTreasure if it provides a good treasure with said block hash! Is that correct?

Correct. The variables needed to create the random number will be either available directly to an evil contract (eg your contract can read the block hash, but my evil contract can read it too) or knowable before the transaction is sent (eg if you have a nonce in your contract then my evil contract can't read it, but I can read directly from storage and send it to my evil contract).

See Martin Swende's blog for the details of how to do it.

What would be somewhat less bad would be to split this into two steps, so the player funds the contract first, then it pays out in another transaction based on the hash x blocks after it was funded. This can still be gamed, but I can't think of a way to game it without the help of the miner.

If you're the house in this contract (ie participants are betting against you not each other), you might like to consider a commit-and-reveal scheme, where you first provide a hash and promise to reveal its nonce, and the player gets paid if you fail to reveal it.

Alternatively RandomDAO does the same with multiple bonded participants. I'm not sure if it's usable yet in practice.

Finally you can use an external data source, but you'll be trusting someone.

  • Thank you, I'm curved towards the first solution. So, let me double check: as long as I wait for the next block to generate the random numbers, and the etherCostPerPrize / prizeRate * 5 < prizeValue, then it is clear of attacks, right? After all, for the rareTreasure case, it would take 256 discarded blocks for the miner to get one. As long as a rareTreasure is worth less than 1280 eth, it is economically unpractical to cheat for it. Correct? – MaiaVictor Jul 27 '16 at 22:36
  • I'm not 100% confident but I think that pretty-much works in practice for the particular prize you describe. One complication is that there are sometimes other reasons for orphaning blocks that could be used in combination with an attack on your contract. For example, if your block would normally be orphaned, but it just drew a winning lottery ticket, you might mine on top of it in preference to the one that would normally have orphaned the lottery ticket... Equally, if you were considering doing Selfish Mining, the cost of withholding a block may not equal the block reward... – Edmund Edgar Jul 28 '16 at 1:24
  • Sorry I don't think that solution actually works. I forgot to consider that there could be an unbounded number of bets in a single block. So the miner could opt to retake thousands of ETH worth of bets for just 5 eth. Of course that is very favorable to him and puts the odds against the house. – MaiaVictor Jul 28 '16 at 3:47

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.