只读函数迭代成本 [英] Read-only Functions Iteration Cost

查看:92
本文介绍了只读函数迭代成本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为某些用例开发智能合约,目前我正在优化智能合约。我对在


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

  $松露控制台
块菌(开发)>让合同;
undefined
松露(开发)> LoopExample.deployed()。then(function(i){contract = i;});
undefined
松露(开发)> contract.constantLoop.call(999);
[]
松露(开发)> contract.constantLoop.call(9999);
[]
松露(开发)> contract.constantLoop.call(99999);
错误:处理事务时VM异常:Object.InvalidResponse(C:$ Users\adamk\AppData\Roaming\npm\node_modules\truffle\build \webpack:\〜\web3\lib\web3\errors.js:38:1)
在C:\Users\adamk\AppData\Roaming\npm\ node_modules\truffle\build\webpack:\〜\web3\lib\web3\requestmanager.js:86:1
at C:\Users\adamk\AppData\漫游-npm-node_modules-truffle-buildwebpack:\〜\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)
在XMLHttpRequestEventTarget.dispatchEvent(C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\〜\xhr2\lib\xhr2.js :64:1)XMLHttpRequest._setReadyState上的
(C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\〜\xhr2 \lib\xhr2.js:354:1)XMLHttpR上的
equest._onHttpResponseEnd(C:\Users\adamk\AppData\Roaming\npm\node_modules\truffle\build\webpack:\〜\xhr2\lib\xhr2.js:509 :1)IncomingMessage处的
。< anonymous> (C:\用户\adamk\AppData\漫游\npm\node_modules\松露\构建\webpack:\〜\xhr2\lib\xhr2.js:469:1)
在emitNone(events.js:91:20)
在IncomingMessage.emit(events.js:185:7)


I am developing smart contracts for some use-cases and currently I'm working on optimization of smart contracts. I am confused with something that I found interesting on Hitchiker's Guide. In the section 4- Iterating the contract code

// 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;
}

For this code above, He states that "Note that every time we want to check if a document was notarized, we need to iterate through all existing proofs. This makes the contract spend more and more gas on each check as more documents are added. "

There is no doubt that the proper way of implementing it is to use mapping instead of array structure. Here is the point that makes me confused. It's read-only function and it is not a transaction that affects blockchain. When I observed my netstats, it does not show any transaction when this function is called(Actually, it is what I expected before calling this function).

I don't think that he misunderstood the mechanism, could someone clean my mind about this comment?

解决方案

Roman’s answer is not correct. Constant functions still consume gas. However, you don’t pay for the gas usage when it runs in the local EVM. If a constant function is called from a transaction, it is not free. Either way, you are still consuming gas and loops are a good way to consume a lot.

EDIT - Here is an example to illustrate the point

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;
  }
}

And here are the gas consumption results for calling addProof 4 times:

addProof("a"): 41226

addProof("b"): 27023

addProof("c"): 27820

addProof("d"): 28617

You kind of have to ignore the very first call. The reason that one is more expense than the rest is because the very first push to proofs will cost more (no storage slot is used before the 1st call, so the push will cost 20000 gas). So, the relevant part for this question is to look at the cost of addProof("b") and then the increase with each call afterwards. The more items you add, the more gas the loop will use and eventually you will hit an out of gas exception.

Here is another example where you are only calling a constant function from the client:

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

Here, if you call this through Remix, you'll see something like this in the output (Notice the comment on gas usage):

Finally, if you try to run this constant method from a client using too many iterations, you will get an error:

$ 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)

这篇关于只读函数迭代成本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆