2

I got the "Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending? Internal JSON-RPC error." in remix while using the drawWinner function

    pragma solidity ^0.4.18;

    contract RecurringLottery {
         struct Round {
            uint deployBlock;
            uint endBlock;
            uint drawBlock;
            Entry[] entries;
            uint totalQuantity;
            address winner;
       }
struct Entry {
    address buyer;
    uint quantity;
}

uint constant public TICKET_PRICE = 1e15;

mapping(uint => Round) public rounds;
uint public round;
uint public duration;
mapping (address => uint) public balances;

// duration is in blocks. 1 day = ~5500 blocks
function RecurringLottery (uint _duration) public {
    round = 1;
    duration = _duration;
    rounds[round].deployBlock = block.number;
    rounds[round].endBlock = block.number + duration;
    rounds[round].drawBlock = block.number + duration + 5;
}

function buy () payable public {
    require(msg.value % TICKET_PRICE == 0);

    if (block.number > rounds[round].endBlock) {
        round += 1;
        rounds[round].deployBlock = block.number;
        rounds[round].endBlock = block.number + duration;
        rounds[round].drawBlock = block.number + duration + 5;
    }

    uint quantity = msg.value / TICKET_PRICE;
    Entry memory entry = Entry(msg.sender, quantity);
    rounds[round].entries.push(entry);
    rounds[round].totalQuantity += quantity;
}

function drawWinner (uint roundNumber) public {
    Round storage drawing = rounds[roundNumber];
    require(drawing.winner ==  address(0));
    require(block.number > drawing.drawBlock);
    require(drawing.entries.length > 0);

    // pick winner
    bytes32 rand = keccak256(
        block.blockhash(drawing.drawBlock)
    );
    uint counter = uint(rand) % drawing.totalQuantity;
    for (uint i=0; i < drawing.entries.length; i++) {
        uint quantity = drawing.entries[i].quantity;
        if (quantity > counter) {
            drawing.winner = drawing.entries[i].buyer;
            break;
        }
        else
            counter -= quantity;
    }

    balances[drawing.winner] += TICKET_PRICE * drawing.totalQuantity;
}

function withdraw () public {
    uint amount = balances[msg.sender];
    balances[msg.sender] = 0;
    msg.sender.transfer(amount);
}

function deleteRound (uint _round) public {
    require(block.number > rounds[_round].drawBlock + 100);
    require(rounds[_round].winner != address(0));
    delete rounds[_round];
}

function () payable public {
    buy();
}

}

1

You usually get that error when code execution fails, this can be because of regular execution or because one of the reverts is catching an error, in your case, problem were the reverts, here is how you can find out:

This feature is not yet on nodes, only in in javascriptVM which you can use in remix, or in your truffle tests/ganache, but it's recommended that you start using it now; you can add an error message to your reverts, this is the easiest way to get better comprehensive errors, IE:

require(condition, "string returned if condition fails");

Note that I'm using javascript vm for this example instead of injected web3. When I execute your code, the first error we can find is in the second require:

require(block.number > drawing.drawBlock, "Can't draw yet");

We can't draw until some blocks have passed, I forced the generation of some blocks in the VM by calling other functions, if you are doing this on ethereum, you just need to wait.

After solving this problem, it crashed in the next line:

require(drawing.entries.length > 0, "No entries for that round");

So I called buy() a couple of times sending the amount of ether specified in TICKET_PRICE, then I checked that the entries where added by calling rounds(numberOfRound), and after calling drawWinner(numberOfRound) with a valid round, the function worked correctly.

You should create a call that will tell you if that function will work or it will fail by checking those conditions, that way you can solve a ton of headaches, remember to put error messages on require, and if you want to see everything step by step, the debugger provided in remix is pretty useful.

TLDR: For your code to work, you need to make sure that enough blocks have passed, and that the round has at least one entry.

By the way, there are a couple of vulnerabilities in your drawWinner() function, don't use it on production!

0

I executed your code on remix, everything is fine. Maybe you forgot to select appropriate compiler version.

    0.4.25+commit.59dbf8f1

This was mine! Hope it helps.

  • Thank you, however i still got this error "Transaction mined but execution failed" with the drawWinner function – Nguyễn Thái Phương Nov 20 '18 at 9:10
  • This happens when one of your assert() or revert() condition returned false. Hence transaction mined but execution failed. – Harsh Nov 20 '18 at 9:39
  • how can i fix it ? – Nguyễn Thái Phương Nov 20 '18 at 9:43
  • Try changing this line: require(drawing.winner == address(0)); to this line: require(drawing.winner != address(0)); in the drawWinner() function. – Harsh Nov 20 '18 at 9:48
  • still the same error :(( – Nguyễn Thái Phương Nov 20 '18 at 10:04
0

When using the REMIX IDE, I had to make sure that I set the value to the TICKET_PRICE. See image, where to set it.

enter image description here

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.