2017-08-07 73 views
3

我正在使用testrpc,web3 1.0和solidity构建一个简单的Dapp,但我总是收到此错误,而且我找不到错在哪里。请帮忙。虚拟机在处理事务时异常:无法使用

我的JavaScript文件:

const Web3 = require('web3'); 
const fs = require('fs'); 

const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 

const code = fs.readFileSync('Voting.sol').toString(); 
const solc = require('solc'); 
const compiledCode = solc.compile(code); 

// deploy contract 
const abiDefinition = JSON.parse(compiledCode.contracts[':Voting'].interface); 
const VotingContract = new web3.eth.Contract(abiDefinition); 
const byteCode = compiledCode.contracts[':Voting'].bytecode; 
const deployedContract = VotingContract 
.deploy({data: byteCode, arguments: [['a','b','c']]}) 
.send({ 
    from: '0x386fd5fbe3804f24b35477f06aa78a178ce021bd', 
    gas: 4700000, 
    gasPrice: '2000000000' 
}, function(error, transactionHash) {}) 
.on('error', function(error){}) 
.on('transactionHash', function(transactionHash){}) 
.on('receipt', function(receipt){ 
    console.log(receipt.contractAddress); 
}) 
.then(function(newContractInstance) { 
    newContractInstance.methods.getList().call({from: '0x386fd5fbe3804f24b35477f06aa78a178ce021bd'}).then(console.log); 
}); 

我的合同文件:

pragma solidity ^0.4.11; 
// We have to specify what version of compiler this code will compile with 

contract Voting { 
    /* mapping field below is equivalent to an associative array or hash. 
    The key of the mapping is candidate name stored as type bytes32 and value is 
    an unsigned integer to store the vote count 
    */ 

    mapping (bytes32 => uint8) public votesReceived; 

    /* Solidity doesn't let you pass in an array of strings in the constructor (yet). 
    We will use an array of bytes32 instead to store the list of candidates 
    */ 

    bytes32[] public candidateList; 

    /* This is the constructor which will be called once when you 
    deploy the contract to the blockchain. When we deploy the contract, 
    we will pass an array of candidates who will be contesting in the election 
    */ 
    function Voting(bytes32[] candidateNames) { 
    candidateList = candidateNames; 
    } 

    function getList() returns (bytes32[]) { 
    return candidateList; 
    } 

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

    // This function increments the vote count for the specified candidate. This 
    // is equivalent to casting a vote 
    function voteForCandidate(bytes32 candidate) { 
    require(validCandidate(candidate) == false); 
    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; 
    } 
} 

而且,我用下面的命令启动testrpc:

testrpc --account =“0xce2ddf7d4509856c2b7256d002c004db6e34eeb19b37cee04f7b493d2b89306d ,2000000000000000000000000000000“

任何帮助,将不胜感激。

回答

5

您不应该使用gas来调用getter方法。请记住,从区块链阅读是免费的 - 这是写数据花费金钱(天然气),因为写作必须经过验证并达成共识。

因此,您的getter方法应该标记为constant属性,例如,

function getList() constant returns (bytes32[]) { 
    return candidateList; 
} 

所有的二,你甚至不需要一个getter方法candidateList因为属性可以直接访问,如newContractInstance.candidateList()

第三,您应该使用映射而不是数组,例如mapping(bytes32 => bool) public validCandidates,因为您的合同只关心候选人是否有效。你真的,真的不想在你的合同中出现循环,因为你希望你的函数调用具有恒定的天然气成本。如果你使用循环,你耗尽气体。

把上述所有的在一起你会得到这样的合同

pragma solidity ^0.4.11; 
// We have to specify what version of compiler this code will compile with 

contract Voting { 
    /* mapping field below is equivalent to an associative array or hash. 
    The key of the mapping is candidate name stored as type bytes32 and value is 
    an unsigned integer to store the vote count 
    */ 

    mapping (bytes32 => uint8) public votesReceived; 
    mapping (bytes32 => bool) public validCandidates; 

    /* This is the constructor which will be called once when you 
    deploy the contract to the blockchain. When we deploy the contract, 
    we will pass an array of candidates who will be contesting in the election 
    */ 
    function Voting(bytes32[] candidateList) { 
    for (uint i = 0; i < candidateList.length; i++) { 
     validCandidates[candidateList[i]] = true; 
    } 
    } 

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

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

    function isValidCandidate(bytes32 candidate) constant returns (bool) { 
    return validCandidates[candidate]; 
    } 

    modifier onlyForValidCandidate(bytes32 candidate) { 
    require(isValidCandidate(candidate)); 
    _; 
    } 
} 
+0

非常感谢,兄弟! –

+0

我知道这花了我一段时间:D为什么构造函数中的循环比另一个函数更好? – Chiptus

+0

在这个特定的合约中,你必须在构造函数中有循环。如果它在另一个函数中,任何人都可以调用它,除非你实现了权限。循环本身并不坏,但您必须了解气体成本 – gaiazov