只读函数迭代成本

Meh*_*ğan 2 ethereum solidity

我正在为一些用例开发智能合约,目前我正在努力优化智能合约.我对Hitchiker指南中有趣的东西感到困惑.在第4节中,迭代合同代码

// returns true if proof is stored
// *read-only function*
function hasProof(bytes32 proof) constant returns (bool) {
for (uint256 i = 0; i < proofs.length; i++) {
    if (proofs[i] == proof) {
        return true;
    }
}
return false;
}
Run Code Online (Sandbox Code Playgroud)

对于上面的代码,他表示"请注意,每次我们要检查文档是否经过公证时,我们都需要遍历所有现有的证据.这使得合同在每次检查时花费越来越多的气体,因为添加了更多文档. "

毫无疑问,实现它的正确方法是使用映射而不是数组结构.这一点让我感到困惑.它是只读函数,它不是影响区块链的事务.当我观察我的netstats时,调用此函数时它不显示任何事务(实际上,这是我在调用此函数之前所期望的).

我不认为他误解了这个机制,有人可以清楚我对这个评论的看法吗?

Ada*_*nis 5

罗曼的答案是不正确的.常数功能仍然消耗气体.但是,当您在本地EVM中运行时,您不需要支付燃气使用费.如果从事务中调用常量函数,则它不是免费的.无论哪种方式,你仍然消耗气体和循环是消费很多的好方法.

编辑 - 这是一个例子来说明这一点

pragma solidity ^0.4.19;

contract LoopExample {
  bytes32[] proofs;

  function addProof(bytes32 proof) public {
    if (!hasProof(proof))
      proofs.push(proof);
  }

  function hasProof(bytes32 proof) public constant returns (bool) {
    for (uint256 i = 0; i < proofs.length; i++) {
      if (proofs[i] == proof) {
        return true;
      }
    }

    return false;
  }
}
Run Code Online (Sandbox Code Playgroud)

以下是调用addProof4次的耗气量结果:

addProof("a"):41226

addProof("b"):27023

addProof("c"):27820

addProof("d"):28617

你必须忽略第一个电话.一个人比其他人花费更多的原因是因为第一次推动proofs将花费更多(在第一次通话之前没有使用存储槽,所以推动将花费20000气体).因此,此问题的相关部分是查看addProof("b")之后每次调用的成本然后增加.你添加的物品越多,循环使用的气体就越多,最终你会遇到燃气异常.

这是另一个示例,您只从客户端调用常量函数:

pragma solidity ^0.4.19;

contract LoopExample {
  function constantLoop(uint256 iterations) public constant {
    uint256 someVal;

    for (uint256 i = 0; i < iterations; i++) {
      someVal = uint256(keccak256(now, i));
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在这里,如果你通过Remix调用它,你会在输出中看到这样的东西(注意关于燃气使用的评论):

重新混合输出Screencap

最后,如果您尝试使用过多的迭代从客户端运行此常量方法,您将收到错误:

$ truffle console
truffle(development)> let contract;
undefined
truffle(development)> LoopExample.deployed().then(function(i) { contract = i; });
undefined
truffle(development)> contract.constantLoop.call(999);
[]
truffle(development)> contract.constantLoop.call(9999);
[]
truffle(development)> contract.constantLoop.call(99999);
Error: VM Exception while processing transaction: out of gas
    at Object.InvalidResponse (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\errors.js:38:1)
    at C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\requestmanager.js:86:1
    at C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\truffle-provider\wrapper.js:134:1
    at XMLHttpRequest.request.onreadystatechange (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\httpprovider.js:128:1)
    at XMLHttpRequestEventTarget.dispatchEvent (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:64:1)
    at XMLHttpRequest._setReadyState (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:354:1)
    at XMLHttpRequest._onHttpResponseEnd (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:509:1)
    at IncomingMessage.<anonymous> (C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:469:1)
    at emitNone (events.js:91:20)
    at IncomingMessage.emit (events.js:185:7)
Run Code Online (Sandbox Code Playgroud)