Error de Truffle TestRPC: Excepción de VM al ejecutar eth_call: código de operación no válido

He creado un proyecto a partir de una caja de trufas. He creado mi propio contrato para votar. En este punto, quiero poder votar, lo que parece estar funcionando, y devolver el total de votos para todos los candidatos, pero recibo un error, aquí hay un código.

pragma solidity ^0.4.2;

contract Voting {

mapping (bytes32 => uint8) public votesReceived;

uint8[] public totalVotes;

bytes32[] public candidateList;

function Voting(bytes32[] candidateNames) {
    candidateList = candidateNames;
}

// This function returns the total votes a candidate has received so far
function totalVotesFor(bytes32 candidate) returns (uint8) {
    if (validCandidate(candidate) == false) revert();
    return votesReceived[candidate];
}

//returns totalVotes
function getAllVotes() constant returns (uint8[]) {
    for(uint i = 0; i < candidateList.length; i++) {
        bytes32 candidate = candidateList[i];
        totalVotes[i] = votesReceived[candidate];
    }
    return totalVotes;
}

// This function returns all candidates
function getCandidateList() returns (bytes32[]) {
    return candidateList;
}

// This function increments the vote count for the specified candidate. This
// is equivalent to casting a vote
function voteForCandidate(bytes32 candidate) {
    if (validCandidate(candidate) == false) revert();
    votesReceived[candidate] += 1;
}

function validCandidate(bytes32 candidate) returns (bool) {
    for(uint i = 0; i < candidateList.length; i++) {
        if (candidateList[i] == candidate) {
            return true;
        }
    }
    return false;
}
}

y aquí está mi código javascript

        const voting = contract(VotingContract)
        voting.setProvider(web3.currentProvider)

        // Declaring this for later so we can chain functions on it.
        var votingInstance;

        // Get current ethereum wallet.
        web3.eth.getCoinbase((error, coinbase) => {
            // Log errors, if any.
            if (error) {
                console.error(error);
            }

            voting.deployed().then(function (instance) {
                votingInstance = instance

                // Attempt to vote.
                votingInstance.voteForCandidate(candidate, {from: coinbase})
                    .then(function (result) {
                        //your vote is cast
                        return votingInstance.getAllVotes()
                    })
                    .then(function(result){
                        console.log(result)
                    })
                    .catch(function (error) {
                        // If error...
                        console.log(error)
                    })
            })
        })

Cuando llamo a voteInstance.getAllVotes() me sale este error

Error: Error: VM Exception while executing eth_call: invalid opcode
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:59368:17
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:69306:5
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:11335:9
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:7895:16
at replenish (/usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:8415:25)
at iterateeCallback (/usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:8405:17)
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:8380:16
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:11332:13
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:69302:9
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:63982:7
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:59368:17
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:69306:5
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:11335:9
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:7895:16
at replenish (/usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:8415:25)
at iterateeCallback (/usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:8405:17)
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:8380:16
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:11332:13
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:69302:9
at /usr/local/lib/node_modules/ethereumjs-testrpc/build/cli.node.js:63982:7
at Object.InvalidResponse (http://localhost:3000/static/js/bundle.js:54358:17)
at http://localhost:3000/static/js/bundle.js:43504:37
at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/inpage.js:9899:9
at completeRequest (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/inpage.js:9950:9)
at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/inpage.js:673:16
at replenish (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/inpage.js:1193:25)
at iterateeCallback (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/inpage.js:1183:17)
at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/inpage.js:1158:16
at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/inpage.js:9827:7
at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/scripts/inpage.js:9923:18

No puedo encontrar una solución en ninguna parte, ¡alguien por favor AYUDA!

Respuestas (2)

El problema aquí es que está tratando de cambiar una variable de estado totalVotes de una función constante ( getAllVotes ).

Una función constante solo puede leer datos. Si necesita realizar cálculos dentro de la función en una matriz o estructura, puede usar la palabra clave memory. Pero no puede cambiar una variable de estado (variable declarada globalmente en el contrato inteligente)

//returns totalVotes
function getAllVotes() constant returns (uint8[]) {
    uint8[] memory totalVotes = new uint8[](candidateList.length);

    for(uint i = 0; i < candidateList.length; i++) {
        bytes32 candidate = candidateList[i];
        totalVotes[i] = votesReceived[candidate];
    }
    return totalVotes;
}

Sólo un par de cosas. Declaras totalVotesen contrato de almacenamiento

uint8[] public totalVotes;

La función getallVotesse declara constante pero se intenta modificartotalVotes

//returns totalVotes
function getAllVotes() constant returns (uint8[]) {
    for(uint i = 0; i < candidateList.length; i++) {
        bytes32 candidate = candidateList[i];
        totalVotes[i] = votesReceived[candidate];
    }
    return totalVotes;
}

Y a partir de esta respuesta https://ethereum.stackexchange.com/a/3590 , no puede devolver una matriz dinámica.