¿Cómo obtener el costo de transacción en una prueba unitaria de Trufa?

¿Cómo puedo obtener el gas real consumido por un sendTransactioninterior de una prueba de trufa?

En la siguiente prueba, buyerenvía un an amountde 50 ETH a un contrato:

const EmptyContract = artifacts.require("EmptyContract");
const BigNumber = web3.BigNumber;

contract('Test', function(accounts) {   
    it("should work", async () => {
        let contract = await EmptyContract.new({ from: accounts[1] });
        let amount = web3.toWei(50, 'ether');
        let buyer = accounts[2];

        // BALANCE BEFORE TX
        let balanceBefore = web3.eth.getBalance(buyer);

        // SEND TX
        let hash = await contract.buy.sendTransaction({from: buyer, value: amount});

        // BALANCE AFTER TX
        const balanceAfter = web3.eth.getBalance(buyer);

        let tx = await web3.eth.getTransaction(hash);
        const gasUsed = tx.gas;
        const gasCost = tx.gasPrice.mul(gasUsed);
        console.log("BEFORE", balanceBefore.toNumber());
        console.log("amount sent", amount);
        console.log("gas price", tx.gasPrice.toNumber());
        console.log("gas used", gasUsed);
        console.log("gas cost", gasCost.toNumber());
        console.log("AFTER", balanceAfter.toNumber());
        console.log("CHECKSUM", balanceAfter.add(gasCost).add(amount).toNumber());

        assert.equal(balanceBefore.toNumber(), balanceAfter.add(gasCost).add(amount).toNumber());
    });
});

Entonces buyerse comprueba el saldo de . Debería ser

[saldo antes de tx] = [saldo después de tx] + [cantidad enviada] + [costo de gasolina]

Pero falla, imprimiendo:

BEFORE 100000000000000000000
amount sent 50000000000000000000
gas price 100000000000
gas used 6721975
gas cost 672197500000000000
AFTER 49997862200000000000
CHECKSUM 100670059700000000000       
   :    
AssertionError: expected 100000000000000000000 to equal 100670059700000000000

El contrato es muy básico:

pragma solidity ^0.4.18;

contract EmptyContract {
    function buy() public payable  { }
}

Parece que la transacción costó 0,6700597 ETH menos que el valor devuelto por tx.

Seguí el costo del gas de transacción en el caso de prueba de trufas, pero no ayudó.

¿Alguna idea?

Respuestas (2)

Tienes que multiplicar el gasUsedpor el gasPrice. El gasUsedestá contenido en el recibo de la transacción. Mientras que el gasPriceestá en la transacción en sí. De hecho, en su caso, está tratando de multiplicar el gasPricepor el gas, que es el proporcionado por el remitente (que puede ser mayor que el gasUsed). ref: getTransaction , getTransactionReceipt

Entonces, así es como su código debería verse para ser correcto

const hash = await contract.buy.sendTransaction({from: comprador, valor: cantidad});

// SALDO DESPUÉS DE TX
const balanceDespués = web3.eth.getBalance(comprador);
const tx = espera web3.eth.getTransaction(hash);
const recibo = espera web3.eth.getTransactionReceipt(hash);
const gasCost = tx.gasPrice.mul(receipt.gasUsed);

o también puede guardar la getTransactionReceiptllamada en caso de que llame a su método directamente (en este caso, debería darle un resultado que contenga también la referencia del recibo de la transacción )

const txInfo = await contract.buy({from: comprador, valor: cantidad});

// SALDO DESPUÉS DE TX
const balanceDespués = web3.eth.getBalance(comprador);
const tx = espera web3.eth.getTransaction(txInfo.tx);
const gasCost = tx.gasPrice.mul(txInfo.receipt.gasUsed);
¡Gracias! No entiendo por qué web3.eth.getTransaction(hash).gasy web3.eth.getTransactionReceipt(hash).gasUsedson diferentes. ¿Cuál es el significado de la primera?
Como he explicado en el post web3.eth.getTransaction(hash).gases el valor aportado por el usuario. Mientras que web3.eth.getTransactionReceipt(hash).gasUsedes el gas utilizado por la transacción. Entonces gasdebe ser >= gasUsedpara ejecutar la transacción. Por supuesto, no podría saber antes cuánto gas usará su transacción, es por eso que el usuario debe aumentar el gas para estar seguro de que la transacción se ejecutará. gasUsedes a menudo <= gasy la diferencia (gas no utilizado) se reembolsa inmediatamente.

Alternativa: puedes usar truffle-cost . Le permite registrar los costos de transacción en lugar de la duración de la prueba, con una sintaxis como esta:

result = await truffleCost.log(
  yourContract.yourFunction()
);

Consulte el enlace para la instalación (¿o debería explicarlo aquí?).

Descargo de responsabilidad: soy el desarrollador de truffle-cost.