使用 Truffle 计算以太坊合约中的交易费用

Accounting for transaction fees in Ethereum contract using Truffle

我正在为以太坊使用 Truffle 测试框架 (v4.0.1)。我不明白为什么以下简单合约的交易费用加起来不等于 gasPrice*gasUsed

contract MinTest {
    function run() public returns(bool) {
        return true;
    }
}

我使用的 mocha 测试是:

contract('Minimum Test', function (accounts) {

  it("min test", function () {
    var initial = web3.eth.getBalance(accounts[1]);
    var final;

    return MinTest.deployed().then(function(instance) {
        return instance.run({from: accounts[1]});
    }).then(function(result) {
        final =  web3.eth.getBalance(accounts[1]);

        var gasPrice = new BigNumber(web3.eth.gasPrice);
        var gasUsed = new BigNumber(result.receipt.gasUsed);
        var gasCost = gasPrice.times(gasUsed);

        console.log("gasPrice       : " + gasPrice);
        console.log("gasUsed        : " + gasUsed);
        console.log("gasCost        : " + gasCost);
        console.log("initial        : " + initial);
        console.log("initial-gasCost: " + initial.minus(gasCost));
        console.log("final          : " + final);
        console.log("unaccounted    : " + initial.minus(gasCost).minus(final));
    });
  });

});

上面的测试产生以下输出:

gasPrice       :            20000000000
gasUsed        :                  21478
gasCost        :        429560000000000
initial        :  100000000000000000000
initial-gasCost:   99999570440000000000
final          :   99997852200000000000
unaccounted    :       1718240000000000

我预计调用合约的 MinTest.run 函数会导致 accounts[1] 被扣除正好等于 gasPrice*gasUsed 的金额,但事实并非如此这个例子。还有一个额外的1718240000000000 wei我记不起来了。为什么这里多了一个1718240000000000 wei?

web3.eth.gasPrice不是您在交易调用中指定的价格。来自文档:

This property is read only and returns the current gas price. The gas price is determined by the x latest blocks median gas price.

它是用来告诉你别人付的钱,所以你可以动态地确定"going rate"。如果您想随时间更改交易的汽油价格,则可以使用它。我猜 testrpc 只是将此设置为 20000000000。

另一方面,当您在事务调用中未指定 gasPrice 时,它默认为 10000000000。下面是更新的测试用例,其中传入 gasPrice 并输出(我测试用了 15 Gwei)。

contract('Minimum Test', function (accounts) {

  it("min test", function () {
    var initial = web3.eth.getBalance(accounts[1]);
    var final;
    var gasPrice = new BigNumber(15000000000);

    return MinTest.deployed().then(function(instance) {
      return instance.run({from: accounts[1], gasPrice: gasPrice});
    }).then(function(result) {
      final =  web3.eth.getBalance(accounts[1]);

      var gasUsed = new BigNumber(result.receipt.gasUsed);
      var gasCost = gasPrice.times(gasUsed);

      console.log("gasPrice       : " + gasPrice);
      console.log("gasUsed        : " + gasUsed);
      console.log("gasCost        : " + gasCost);
      console.log("initial        : " + initial);
      console.log("initial-gasCost: " + initial.minus(gasCost));
      console.log("final          : " + final);
      console.log("unaccounted    : " + initial.minus(gasCost).minus(final));
    });
  });

});
  Contract: Minimum Test
gasPrice       : 15000000000
gasUsed        : 21431
gasCost        : 321465000000000
initial        : 100000000000000000000
initial-gasCost: 99999678535000000000
final          : 99999678535000000000
unaccounted    : 0
    √ min test (773ms)


  1 passing (922ms)

编辑 - web3js 文档确实说 gasPrice 的默认值应该是相同的:

gasPrice: Number|String|BigNumber - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price.

这可能是 Truffle 中的一个错误。无论如何,如果您传入自己的汽油价格,数字就会计算出来。