Solidity: Resolving Invalid Opcode Errors During Truffle Migration for Voting Contracts

contract-developmentsoliditytruffletruffle-migrationvoting

I'm just getting started with Solidity and ran into a problem that I can't solve. The error below displays when you try to migrate

truffle migrate --reset
2_deploy_contracts.js
=====================

   Replacing 'Election'
   --------------------

Error:  *** Deployment Failed ***

"Election" hit an invalid opcode while deploying. Try:
   * Verifying that your constructor params satisfy all assert conditions.
   * Verifying your constructor code doesn't access an array out of bounds.
   * Adding reason strings to your assert statements.

I do not understand why this is happening, I have tried many solutions, but still without effect. Updating the truffle version did not help, and neither did the subsequent changes to the Election.sol structure. I am using ganache v2.5.4

Election.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.8.20;
pragma experimental ABIEncoderV2;
contract Election {
    struct Elections {
        uint id;
        string title;
        string description;
        uint creationDate;
        uint expirationDate;
        Candidate[] candidates;
    }
    uint public electionsCount;
    Elections[] elections;

    struct Candidate {
        uint id;
        string name;
        uint voteCount;
    }
    uint public candidatesCount;

    function addElections (string memory _title, string memory _description, uint _amountOfHours, string[] memory _names) private {
        electionsCount ++;
        elections[electionsCount].id = electionsCount;
        elections[electionsCount].title = _title;
        elections[electionsCount].description = _description;
        elections[electionsCount].creationDate = block.timestamp;
        elections[electionsCount].expirationDate = block.timestamp + _amountOfHours;

        Candidate[] memory candidates;
        for (uint i = 0; i < _names.length; i++) {
            candidatesCount ++;
            string memory name = _names[i];
            candidates[candidatesCount] = Candidate(candidatesCount, name, 0);
            elections[electionsCount].candidates.push(candidates[i]);
        }
    }
    string[] names= ["AAAA", "BBBBB", "CCCCCC"];

    constructor () public {
        addElections("Voted", "vote for your candidate", 8, names);
    }
}

Best Answer

The function addElections has some issues:

  1. The function appends an item to the elections array. To do so you have to use the array's push() operation.

    // Push an empty an item
    elections.push();
    
    // Get a reference to the new item
    electionsCount = elections.length - 1;
    
    // Update the reference
    elections[electionsCount].id = electionsCount;
    elections[electionsCount].title = _title;
    elections[electionsCount].description = _description;
    elections[electionsCount].creationDate = block.timestamp;
    elections[electionsCount].expirationDate = block.timestamp + _amountOfHours;
    
  2. The second part uses the array candidates but it is never initialized. It is really not necessary so we can drop it.

    for (uint i = 0; i < _names.length; i++) {
        candidatesCount ++;
        string memory name = _names[i];
        elections[electionsCount].candidates.push(Candidate(candidatesCount, name, 0));
    }