7

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();
    }
}

6 Answers 6

5

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!

2

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

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.

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

In my case, I had to switch from solc version 0.8.7 to 0.8.0 and it works.

0

You're getting a gas estimation failed error, this means:

  1. You don't have enough ETH to perform this transaction
  • If this is the case, get more ETH
  1. You don't have enough ERC20 token to perform this transaction (like LINK, DAI, etc)
  • If this is the case, get more of the ERC20 token, or fund your contract with LINK.
  1. You have some other issue with your logic breaking.
  • If this is the case, please update the question with comments.
0

I did face this issue recently and I have been tryna figure out what really was going wrong with my contract, then figured that only the owner had the perms to call that specific function and I had to enable the perms for all to let anyone address call the function, due to which the transaction was being reverted, of course internally this could be one of the many reasons we might come across, not the only definitive solution or aspect to look at when confronting such an error.

Hope this helps!

2
  • To correctly answer an old question you've to be more specific about the issue. This answer is more like a comment. Also the contract doesn't handle permissions so it doesn't apply directly to the contract.
    – Ismael
    Commented Dec 21, 2022 at 6:00
  • Your reasoning is correct but it doesn't apply to the question asked. It isn't an Ownable contract, it doesn't manage permissions.
    – Ismael
    Commented Jul 4, 2023 at 3:36

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