ethereum - 处理事务 : out of gas 时出现 VM 异常

标签 ethereum solidity smartcontracts web3js

我正在使用 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);
});

我的契约(Contract)文件:
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, 20000000000000000000000000000

任何帮助,将不胜感激。

最佳答案

你不应该使用gas来调用getter方法。请记住,从区块链读取是免费的——写入数据需要花费金钱(gas),因为写入必须经过验证并达成共识。

所以,你的 getter 方法应该被标记为 constant属性,例如

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

其次,您甚至不需要 candidateList 的 setter/getter 。因为可以直接访问该属性,例如newContractInstance.candidateList()
第三,您应该使用映射而不是数组,例如 mapping(bytes32 => bool) public validCandidates因为你的契约(Contract)只关心候选人是否有效。你真的,真的不想在你的合约中有循环,因为你希望你的函数调用具有恒定的 gas 成本。如果您使用循环,您将耗尽气体。

将以上所有内容放在一起,您将获得这样的契约(Contract)
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));
    _;
  }
}

关于ethereum - 处理事务 : out of gas 时出现 VM 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45539031/

相关文章:

python - 使用Python从以太坊区 block 链中提取信息

blockchain - 以去中心化方式从 Chainlink 获取代币历史价格数据的最佳方式是什么?

ethereum - 我可以通过另一个合约的构造函数将 eth 发送到合约吗?

node.js - 类型错误 : Explicit type conversion not allowed from "int_const -1" to "uint256"

blockchain - 'mining'在智能合约中是什么意思?

constructor - ChainID Solidity 版本 0.6.12

ethereum - 在以太坊中,我如何与区 block 链上的合约交互?

javascript - 如何在 Solidity 中构建 HTML 解决方案

solidity - 在 ERC20.transferFrom 上恢复

smartcontracts - 为什么像signer_account_id这样的Env变量会导致错误: ProhibitedInView?