Die Gaskosten summieren sich im einfachen Transaktionsvertrag nicht

Ich habe einen einfachen Vertrag, der hilft, eine Zahlung auf ein anderes Konto vorzunehmen. Nehmen wir an, ich beginne den Vertrag mit Wert V, Vertragsgaskosten Gund Wert, der in das andere Konto umgerechnet wird X. Ich gehe davon aus, dass folgendes zutreffen wird:

V = G + X.

Es ist jedoch nicht.

Nach einem einfachen truffle initSchritt arbeite ich mit dem folgenden Vertrag.

Pay.sol

pragma solidity ^0.4.17;

/// @title Pay - Facilitates payments.
contract Pay {
    event Payment(
        address _from,
        address _to,
        uint amount
    );

    /// @dev Makes a payment.
    /// @param _to Address to pay to.
    function pay(address _to) public payable {
        require(msg.value > 0);
        // Does this transfer the right amount of ether (msg.value measured in wei)?
        _to.transfer(msg.value);
        Payment(msg.sender, _to, msg.value);
    }
}

Und die folgende Testdatei.

pay.js

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

contract('Pay', function(accounts) {
    it("should put money in the first account", function() {
        return Pay.deployed().then(function(instance) {
            pay = instance;
            return web3.eth.getBalance(accounts[1]);
        }).then(function(balance){
            startingBalance = balance.toNumber();
            gasPrice = 200000;
            payAmount = 2500000;
            return pay.pay(accounts[1], {from: accounts[0], value: payAmount, gasPrice: gasPrice });
        }).then(function() {
            return pay.pay.estimateGas(accounts[1], {from: accounts[0], value: payAmount });
        }).then(function(gasCost) {
            gasSpent = gasCost * gasPrice;
            console.log(gasCost);
            console.log(gasPrice);
            console.log(gasSpent);
            return web3.eth.getBalance(accounts[1]);
        }).then(function(balance) {
            endingBalance = balance.toNumber();
            assert.equal(endingBalance - startingBalance, payAmount);
        })
    });
});

Die Ausgabe ist die folgende:

  Contract: Pay
32001
200000
6400200000
    1) should put money in the first account

    Events emitted during test:
    ---------------------------

    Payment(_from: 0x627306090abab3a6e1400e9345bc60c78a8bef57, _to: 0xf17f52151ebef6c7334fad080c5704d77216b732, amount: 2500000)

    ---------------------------


  0 passing (476ms)
  1 failing

  1) Contract: Pay should put money in the first account:
     AssertionError: expected 2506752 to equal 2500000
      at test/pay.js:23:20
      at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:118:7)

Insbesondere, wie Sie der Ausgabe entnehmen können:

V-X=-6752(kann es auch negativ sein?)G=6400200000

UPDATE : Richtige Antwort als Referenz.

pay.js

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

contract('Pay', function(accounts) {
    it("should put money in the first account", function() {
        return Pay.deployed().then(function(instance) {
            pay = instance;
            return web3.eth.getBalance(accounts[1]);
        }).then(function(balance){
            startingBalance = balance;
            gasPrice = 200000;
            payAmount = 2500000;
            return pay.pay(accounts[1], {from: accounts[0], value: payAmount, gasPrice: gasPrice });
        }).then(function(result) {
            gasUsed = result.receipt.gasUsed;
            return pay.pay.estimateGas(accounts[1], {from: accounts[0], value: payAmount });
        }).then(function(gasCost) {
            gasSpent = gasCost * gasPrice;
            return web3.eth.getBalance(accounts[1]);
        }).then(function(balance) {
            endingBalance = balance;
            assert.equal(endingBalance.sub(startingBalance).toNumber(), payAmount);
        })
    });

    it("should pay gas costs from the second account", function() {
        return Pay.deployed().then(function(instance) {
            pay = instance;
            return web3.eth.getBalance(accounts[0]);
        }).then(function(balance){
            startingBalance = balance;
            gasPrice = 200000;
            payAmount = 2500000;
            return pay.pay(accounts[1], {from: accounts[0], value: payAmount, gasPrice: gasPrice });
        }).then(function(result) {
            gasUsed = result.receipt.gasUsed;
            return pay.pay.estimateGas(accounts[1], {from: accounts[0], value: payAmount });
        }).then(function(gasCost) {
            gasSpent = gasCost * gasPrice;
            return web3.eth.getBalance(accounts[0]);
        }).then(function(balance) {
            endingBalance = balance;
            assert.equal(startingBalance.sub(endingBalance).toNumber(), payAmount + gasSpent);
        })
    });
});

Antworten (1)

Sie nehmen die Differenz mit den Zahlen von Javascript

startingBalance = balance.toNumber();
...
endingBalance = balance.toNumber();
assert.equal(endingBalance - startingBalance, payAmount);

Aber JavaScript-Zahlen haben nicht genug Genauigkeit, um große Werte zu verarbeiten.

Sie sollten das Guthaben als BigNums speichern und die Umwandlung in Zahlen als letzte Operation vornehmen.

startingBalance = balance;
...
endingBalance = balance;
assert.equal(endingBalance.sub(startingBalance).toNumber(), payAmount);

Auch Sie bezahlen die Operationen, mit account[0]denen Sie Guthaben von diesem Konto verwenden müssen, um das verbrauchte Gas zu messen.


Verwenden Sie estimateGaszur Bestimmung des Verbrauchsgases das gasUsedFeld aus dem Beleg der Transaktion .

Aus der eth_estimategas- Dokumentation

Beachten Sie, dass die Schätzung aus verschiedenen Gründen, einschließlich der EVM-Mechanik und der Knotenleistung, erheblich höher sein kann als die tatsächlich von der Transaktion verbrauchte Gasmenge.

Es gibt Vorgänge, die negative Kosten verursachen, zum Beispiel wird das Löschen des Speichers Gas zurückgeben, aber es muss zuerst erfolgreich sein.

Danke dafür, aber beim Laufen result.receiptbekomme ich einen Gasverbrauch von 32001 was der obigen Schätzung entspricht. Allerdings muss ich das mit dem von mir eingestellten gasPrice von 200.000 multiplizieren. Die sich daraus ergebende Gesamtgasgebühr von 6.400.200.000 stimmt nicht mit dem aus dem Vertrag gezahlten zusätzlichen Betrag überein.
@Peteris Ich habe meine Antwort aktualisiert, Sie haben in Ihrem Test die Zahlen von Javascript verwendet, aber es hat nicht genug Genauigkeit, um das richtige Ergebnis zu erhalten.