Solidity

如何測量程式碼塊中使用的氣體?

  • April 1, 2020

這個答案很好地解釋瞭如何測量程式碼塊中使用的氣體。

在找到答案之前,我實際上一直在使用這種方法:

pragma solidity 0.4.26;

import './IERC20Token.sol';

contract Tester {
   uint256 public gasUsed;

   function transfer(IERC20Token _token, address _to, uint256 _value) public {
       uint256 bgn = gasleft();
       require(_token.transfer(_to, _value));
       uint256 end = gasleft();
       gasUsed = bgn - end;
   }
}

然後,簡單地從 Truffle 4.1.16 測試:

const token = await ERC20Token.new('name', 'symbol', 18, SUPPLY);
const tester = await Tester.new();
await token.transfer(tester.address, AMOUNT);
await tester.transfer(token.address, accounts[0], AMOUNT);
const gasUsed = await tester.gasUsed();
console.log(gasUsed.toFixed());

但是,它似乎沒有考慮將儲存變數從非零更改為零的氣體退款。

稍微了解一下這個退款,我相信它會被退回給寄件人(msg.sender),甚至是一路退回給原始寄件人(tx.origin)。

所以我正在尋找一種更準確的方法。

我不介意解決方案是否涉及鏈下,例如(使用 web3.js):

const balanceBefore = await web3.eth.getBalance(myAccount);
const response = await myContract.methods.myFunc().send({from: myAccount, gasPrice: myGasPrice});
const balanceAfter = await web3.eth.getBalance(myAccount);
const gasUsed = response.receipt.gasUsed;
// now do something with balanceBefore, balanceAfter, myGasPrice and gasUsed

但結果應該只反映合約中實際程式碼塊的 gas 成本。

例如,它應該避免將交易本身的成本考慮在內。

有人對此有主要線索嗎?

謝謝!

好的,我意識到我可以簡單地使用它,而不必依賴gasleft()

pragma solidity 0.4.26;

import './IERC20Token.sol';

contract Tester1 {
   address public to;
   uint256 public value;

   function transfer(IERC20Token _token, address _to, uint256 _value) public returns (bool) {
       to = _to;
       value = _value;
       return _token.transfer(_to, _value);
   }
}

contract Tester2 {
   address public to;
   uint256 public value;

   function transfer(IERC20Token _token, address _to, uint256 _value) public returns (bool) {
       to = _to;
       value = _value;
       return true; // _token.transfer(_to, _value);
   }
}

然後,從 Truffle 4.1.16 測試:

const token = await ERC20Token.new('name', 'symbol', 18, SUPPLY);
const tester1 = await Tester1.new();
const tester2 = await Tester2.new();
await token.transfer(tester1.address, AMOUNT);
await token.transfer(tester2.address, AMOUNT);
const response1 = await tester1.transfer(token.address, accounts[1], AMOUNT);
const response2 = await tester2.transfer(token.address, accounts[2], AMOUNT);
console.log(response1.receipt.gasUsed - response2.receipt.gasUsed);

引用自:https://ethereum.stackexchange.com/questions/82038