Стоимость транзакционного газа в тестовом примере с трюфелем

Ниже приведены тестовые примеры трюфелей в javascript, где я пытался добавить стоимость газа к балансу счета, чтобы подтвердить сумму транзакции, где сумма должна быть равна предыдущему балансу.

Но я не мог заставить его работать!

rcpt.cumulativeGasUsed, web3.eth.gasPrice, getBalance(accounts[1]) все верно, а арифметика нет, какие-то fromWei, toWei кунг-фу нужны?

Что я здесь делаю неправильно?

            return instance.bailOut({ from: accounts[1] }).then(function (resp) {
            var rcpt = web3.eth.getTransactionReceipt(resp.tx);
            console.log("Sum: " + ((rcpt.cumulativeGasUsed * web3.eth.gasPrice) + web3.eth.getBalance(accounts[1]).toString(10)));

});

После множества экспериментов оказалось, что приведенный ниже метод работает нормально, но не может объяснить логику стоимости транзакции! Любая идея приветствуется.

В любом случае модульный тест проходит!!!

return contractInstance.withdraw({ value: web3.toWei(1, "ether"), gas: 1000000 }).then(function () {
          var contractAddressBalance = web3.fromWei(web3.eth.getBalance(contractAddress).toString(10));
          console.log("contractAddress balance after withdraw: " + contractAddressBalance);
          return contractInstance.bailOut({ from: accounts[1] }).then(function (resp) {
            var rcpt = web3.eth.getTransactionReceipt(resp.tx);

            console.log("cumulativeGasUsed: " + rcpt.cumulativeGasUsed);
            console.log("gasPrice: " + web3.eth.gasPrice);

            var transactionCost = (rcpt.cumulativeGasUsed / 10000000); // How come this works???

            console.log("transactionCost: " + transactionCost);
            console.log("Account[1] balance after withdraw: " + web3.eth.getBalance(accounts[1]));

            contractWalletAfter = web3.fromWei(web3.eth.getBalance(accounts[1]).add(web3.fromWei(rcpt.cumulativeGasUsed)));
            assert.equal(((contractWalletAfter.minus(contractWalletBefore)).add(transactionCost)).valueOf(), 6, "6 wasn't in the contract wallet");
          });
        });
Правильная формула для эфира, оплаченного транзакцией, должна быть gasUsed * gasPrice + value. Если контракты делают перевод отправителю, который изменит окончательный баланс.
да, это то, что я тоже понимаю. Вы можете видеть это в моем первоначальном вопросе, где я сделал, rcpt.cumulativeGasUsed * web3.eth.gasPriceчтобы получить стоимость транзакции. Но это не сработало! Если у вас открыта консоль, вы можете быстро проверить то же самое с помощью Metacoin в тестовом примере с трюфелем. Похоже на какое-то волшебство с тестом на трюфели???

Ответы (2)

Примечание. Этот ответ действителен только для Truffle v4.


Я пробовал этот тест на примере MetaCoin из трюфеля (т.е. запускал truffle unbox metacoinв пустой директории)

var MetaCoin = artifacts.require("./MetaCoin.sol");

contract('MetaCoin', function(accounts) {
  it("Test gas", async () => {
    const meta = await MetaCoin.deployed();

    // Initial balance of the second account
    const initial = await web3.eth.getBalance(accounts[1]);
    console.log(`Initial: ${initial.toString()}`);

    // Obtain gas used from the receipt
    const receipt = await meta.sendCoin(accounts[2], 1, { from: accounts[1] });
    const gasUsed = receipt.receipt.gasUsed;
    console.log(`GasUsed: ${receipt.receipt.gasUsed}`);

    // Obtain gasPrice from the transaction
    const tx = await web3.eth.getTransaction(receipt.tx);
    const gasPrice = tx.gasPrice;
    console.log(`GasPrice: ${tx.gasPrice}`);

    // Final balance
    const final = await web3.eth.getBalance(accounts[1]);
    console.log(`Final: ${final.toString()}`);
    assert.equal(final.add(gasPrice.mul(gasUsed)).toString(), initial.toString(), "Must be equal");
  });
});

Соответствующий вывод:

  Contract: MetaCoin
Initial: 99971803600000000000
GasUsed: 23497
GasPrice: 100000000000
Final: 99969453900000000000Test gas (199ms)

  1 passing (217ms)

Одно отличие состоит в том, что я читаю gasPrice из транзакции( getTransaction(hash).gasPrice), а не из сети eth.gasPrice().

хорошо, это объясняет, getTransaction(hash).gasPrice100000000000 и eth.gasPrice()20000000000 в моих тестах.
Для меня tx.gasPrice не является BN (string), tx.gasPrice является int - оба требуют: new BN( n );
@TheBurgerKing Прошлогодний ответ был для Truffle v4, в котором используется web3 v0.20, в котором используется форк BigNumber.js. Вероятно, вы используете новый Truffle v5, в котором используется web3 v1.0, который, в свою очередь, использует BN.js. Я бы предложил создать новый ответ с решением для Truffle v5. Я бы отредактировал свой ответ, указав, что он был протестирован с Truffle v4.

Следующий код является тем же кодом, что и код Ismael , с изменениями для работы с Truffle v5, поскольку getBalanceтип возвращаемого значения, кроме того, gasUsedи gasPriceзначения по умолчанию не являются BN:

var MetaCoin = artifacts.require("./MetaCoin.sol");

const { toBN } = web3.utils;

contract('MetaCoin', function(accounts) {
  it("Test gas", async () => {
    const meta = await MetaCoin.deployed();

    // Initial balance of the second account
    const initial = toBN(await web3.eth.getBalance(accounts[1]));
    console.log(`Initial: ${initial.toString()}`);

    // Obtain gas used from the receipt
    const receipt = await meta.sendCoin(accounts[2], 1, { from: accounts[1] });
    const gasUsed = toBN(receipt.receipt.gasUsed);
    console.log(`GasUsed: ${receipt.receipt.gasUsed}`);

    // Obtain gasPrice from the transaction
    const tx = await web3.eth.getTransaction(receipt.tx);
    const gasPrice = toBN(tx.gasPrice);
    console.log(`GasPrice: ${tx.gasPrice}`);

    // Final balance
    const final = toBN(await web3.eth.getBalance(accounts[1]));
    console.log(`Final: ${final.toString()}`);
    assert.equal(final.add(gasPrice.mul(gasUsed)).toString(), initial.toString(), "Must be equal");
  });
});