处理交易时出现虚拟机异常:气体不足

Posted

技术标签:

【中文标题】处理交易时出现虚拟机异常:气体不足【英文标题】:VM Exception while processing transaction: out of gas 【发布时间】:2018-01-14 07:04:26 【问题描述】:

我正在使用 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"

任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

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

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

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

其次,您甚至不需要 candidateList 的 getter,因为可以直接访问该属性,例如newContractInstance.candidateList()

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

将以上所有内容放在一起,您将获得这样的合同

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));
    _;
  

【讨论】:

非常感谢,兄弟! 我知道我花了一段时间 :D 为什么构造函数中的循环比另一个函数中的循环更好? 在这个特定的合约中,你必须在构造函数中有循环。如果它在另一个函数中,任何人都可以调用它,除非你实现了权限。循环本身还不错,但您必须了解 gas 成本

以上是关于处理交易时出现虚拟机异常:气体不足的主要内容,如果未能解决你的问题,请参考以下文章

python异常处理

Java基础(13) - Error与Exception

用VMware虚拟机安装mac时出现这个样提示,怎么解决?

虚拟机 VMware8安装Fedora16时出现一下提示,怎么办?谢谢

Error与Exception的区别

虚拟机Linux下解决ping时出现 unknown host问题