¿Cómo puedo obtener el gas real consumido por un sendTransaction
interior de una prueba de trufa?
En la siguiente prueba, buyer
envía un an amount
de 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 buyer
se 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?
Tienes que multiplicar el gasUsed
por el gasPrice
. El gasUsed
está contenido en el recibo de la transacción. Mientras que el gasPrice
está en la transacción en sí. De hecho, en su caso, está tratando de multiplicar el gasPrice
por 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 getTransactionReceipt
llamada 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);
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.
Roberto
web3.eth.getTransaction(hash).gas
yweb3.eth.getTransactionReceipt(hash).gasUsed
son diferentes. ¿Cuál es el significado de la primera?mirg
web3.eth.getTransaction(hash).gas
es el valor aportado por el usuario. Mientras queweb3.eth.getTransactionReceipt(hash).gasUsed
es el gas utilizado por la transacción. Entoncesgas
debe ser >=gasUsed
para 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á.gasUsed
es a menudo <=gas
y la diferencia (gas no utilizado) se reembolsa inmediatamente.