0

I've been wreaking my brain on this for a while, could use some help. Bottomline, the newProposal function throws an VM Exception while processing transaction: invalid opcode error. The puzzling thing is that this function was working fine with Solidity 0.5, but not with 0.6. Here is what I've attempted so far, any further insight is greatly appreciated.

  1. According to the breaking changes in Solidity 0.6, I suspect that the issue is about the resizing of the proposals array to add a new Proposal struct, which is somewhat supported by this issue.
  • Member-access to length of arrays is now always read-only, even for storage arrays. It is no longer possible to resize storage arrays by assigning a new value to their length. Use push(), push(value) or pop() instead, or assign a full array, which will of course overwrite the existing content. The reason behind this is to prevent storage collisions of gigantic storage arrays.

So I have attempted a number of variations here (i.e., proposals.push(), hard coding proposalID). No luck. I don't believe the struct and its properties are the problem, but I can't be 100% sure of that either. So I feel like I'm missing something relatively obvious here, and I thank you for any assistance.

The function that returns an invalid opCode error

    /**
     * Add Proposal
     *
     * Propose to send `weiAmount / 1e18` ether to `beneficiary` for `jobDescription`. `transactionBytecode ? Contains : Does not contain` code.
     *
     * @param beneficiary who to send the ether to
     * @param weiAmount amount of ether to send, in wei
     * @param jobDescription Description of job
     * @param transactionBytecode bytecode of transaction
     */
    function newProposal(
        address beneficiary,
        uint weiAmount,
        string memory jobDescription,
        bytes memory transactionBytecode
    )
        public onlyShareholders
        returns (uint proposalID)
    {
        proposalID = proposals.length+1; //I suspect the problem is here...
        // I've tried proposals.push(); proposalID = proposals.length; instead, no luck
        Proposal storage p = proposals[proposalID]; //...or here
        p.recipient = beneficiary;
        p.amount = weiAmount;
        p.description = jobDescription;
        p.proposalHash = keccak256(abi.encodePacked(beneficiary, weiAmount, transactionBytecode));
        p.minExecutionDate = now + debatingPeriodInMinutes * 1 minutes;
        p.executed = false;
        p.proposalPassed = false;
        p.numberOfVotes = 0;
        emit ProposalAdded(proposalID, beneficiary, weiAmount, jobDescription);
        numProposals = proposalID+1;

        return proposalID;
    }

The Proposal struct and proposals array

    Proposal[] public proposals;

    struct Proposal {
        address recipient;
        uint amount;
        string description;
        uint minExecutionDate;
        bool executed;
        bool proposalPassed;
        uint numberOfVotes;
        bytes32 proposalHash;
        Vote[] votes;
        mapping (address => bool) voted;
    }

EDIT: This fixed it, see comments below with @goodvibration

proposalID = proposals.length;
proposals.push();
Proposal storage p = proposals[proposalID];

1 Answer 1

1

You are obviously trying to access the array at an illegal index:

proposalID = proposals.length+1;
Proposal storage p = proposals[proposalID]; 

Valid indexes in any array are between 0 and array.length - 1.

Most people get it wrong trying to access the array at array.length.

You got it wrong trying to access the array at array.length + 1!


Note that trying to access array using array.length or higher is designated to fail by definition no matter how many elements you push into array beforehand, because while pushing those elements, array.length grows along with it.

7
  • Thank you for your response. Yes, arrays are zero indexed, however the intent here is to resize the array in order to add the Proposal struct. I've attempted a number of different variations here, all resulting in the same problem (i.e., proposals.push(); proposalID = proposals.length;). Same error. How would you re-write this in order to add the Proposal struct to the array?
    – FugueWeb
    Commented Jul 3, 2020 at 18:04
  • @FugueWeb: With proposals[proposalID], you are not resizing the array, you are accessing it! Commented Jul 3, 2020 at 18:05
  • 1
    @FugueWeb: And no matter how many items you push into it, if at the end of the day you try to access it using its own length or higher (for example, arr[arr.length]), then your code is designated for failure, as arr.length has grown with your array (i.e., it is an illegal index by definition). Commented Jul 3, 2020 at 18:06
  • 1
    @FugueWeb: You're welcome. And BTW, there's no proposalID = proposals.length++ in your code anyway. One could indeed wonder what the problem was in that case. But you wrote proposalID = proposals.length+1, which clearly leads to an error. Please accept the answer if it has answered your question. Commented Jul 3, 2020 at 18:21
  • 1
    @FugueWeb: No. Postfix ++ returns the value of the operand prior to incrementing it. Commented Jul 3, 2020 at 18:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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