2

Its possible that this contract have some issue because i see something strange in my contract log. Someone execute another contract function to play with this mini gamble app and in 2 plays he cleans all the money xD.

Thanks in advance :)

pragma solidity ^0.4.11;
contract MetaCoin {

  event FlipCoinEvent(
    uint value,
    address owner
  );

    event PlaySlotEvent(
      uint value,
      address owner
    );

  function() public payable {}

  function flipCoin() public payable {
    assert(msg.value < 100000000000000000);
    uint value = (block.timestamp + uint(block.blockhash(block.number-1)))%100 + 1;
    if (value > 55){
      msg.sender.transfer(msg.value * 2);
    }
    FlipCoinEvent(value, msg.sender);
  }

function playSlot() public payable {
    require(msg.value < 100000000000000000);
    uint r = (block.timestamp + uint(block.blockhash(block.number-1)))%100 + 1;
       if(r >0 && r<3){
             PlaySlotEvent(3,msg.sender);
             msg.sender.transfer(msg.value * 12);
       }else if(r >3 && r<6){
             PlaySlotEvent(2,msg.sender);
             msg.sender.transfer(msg.value * 6);
       }else if(r >6 && r<9){
             PlaySlotEvent(1,msg.sender);
             msg.sender.transfer(msg.value * 3);
       }else{
            PlaySlotEvent(0,msg.sender);
       }

  }

  function getBalance() public constant returns(uint bal) {
    bal = this.balance;
    return bal;
  }

}
4

As per documentation the block.timestamp, the block.blockhash and the block.number stay the same until the next block is added to the blockchain. Since the block time is around 15 to 17 seconds it is easily possible to "get the right block" in order to attack your smart contract.

One could just write a smart contract with a function getChances() that checks the current value of (block.timestamp + uint(block.blockhash(block.number-1)))%100 + 1 and if it is in the right range (e.g. < 3) it calls the playSlot() function of your contract.

The function getChances() then just needs to be invoked by an oracle everytime a new block is added to the blockchain.

No magic.

Hope it helps

EDIT:

I've condensed your smart contract and wrote another one to show better what I meant above:

pragma solidity ^0.4.11;

contract MetaCoin {
    event PlaySlotEvent(
        uint value,
        address owner
    );

    function playSlot() public returns (uint){
        uint r = (block.timestamp + uint(block.blockhash(block.number-1)))%100 + 1;
        PlaySlotEvent(r,msg.sender);
    }
}

contract Test {

    function getCurrentR() constant returns (uint) {
        return (block.timestamp + uint(block.blockhash(block.number-1)))%100 + 1;
    }
}

If you try this in Remix just call getCurrentR() and immediately after that call playSlot(). You will see, that the value differs only to the amount of seconds you wait before calling playSlot(). Therefore a player can check r before starting to play...

  • But the uint(block.blockhash(block.number-1)) is impossible to predict right? – hugofreire Feb 7 '18 at 10:52
  • I have never used these commands in my projects. But as far as I understand the definition with block.number you get the number of the most recent block. So block.number-1 is the number of the block added before the current one. Therefore with block.blockhash(block.number-1) you get something based on information of the past. Am I missing something? – joffi Feb 7 '18 at 11:03
  • if i read block.blockhash(block.number) gives me zero every time, because the current block is not mined right? – hugofreire Feb 7 '18 at 11:14
  • Okay. I just tried it and you are right at this point. So block.number-1 makes sense. Sorry for confusion. But even though you are computing a number based on data already available, right? – joffi Feb 7 '18 at 11:23
  • Yes but the time you execute the transaction the parent hash is already ahead or not? – hugofreire Feb 7 '18 at 11:47
2

Your lottery is not truly random.

Any decision that a user makes which affects the outcome gives that user an unfair advantage. Examples include:

  1. Using a blockhash, timestamp, or other miner-defined value. Keep in mind that the miner has a choice of whether to publish a block or not, so they could conceivably have one chance at the prize per block they mine.

See this answer for a more thorough explanation: How can I securely generate a random number in my smart contract?.

1

assert(msg.value < 100000000000000000); require(msg.value < 100000000000000000);

This means, that I can also play with 0 wei and still win, correct?

Maybe you meant > ?

  • yes but you win 0 * 2 = 0 right? – hugofreire Feb 6 '18 at 22:44
  • hm you're right – smaco Feb 6 '18 at 22:55
0

For generating the random number you use the current block timestamp and the previous block hash. The previous block hash is known so it doesn't add any randomness. The current block timestamp is known to the miner so they can call flipCoin whenever the timestamp is favorable for them.

Note that you cannot get the current block hash in Solidity. As specified in the docs:

block.blockhash(uint blockNumber) returns (bytes32): hash of the given block - only works for 256 most recent blocks excluding current

Instead you should spit the game into 2 stages:

  • in flipCoin you record the block.number and msg.value for the sender.
  • in withdrawReward you transfer the reward if the block hash for the recorded block number makes him the winner. Here you must also validate that the recorded block number is less than the current block number.

It’s ok to use blockhash in this case since the 0.1 ether reward is much lower than the block reward. For generating the random number you should also include the sender’s addres in the seed, otherwise an attacker can send multiple flipCoin requests that will total to more than the block reward, which will give an incentive to manipulate the block hash and give possibility for cheating.

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.