A continuación se muestra un caso de prueba de trufas en javascript, donde estaba tratando de agregar el costo del gas al saldo de una cuenta para confirmar la suma de la transacción, donde la suma debería ser igual al saldo anterior.
¡Pero no pude hacerlo funcionar!
El rcpt.cumulativeGasUsed, web3.eth.gasPrice, getBalance(accounts[1]) son todos correctos, pero la aritmética no lo es, ¿se necesita algo de Wei, a Wei kung-fu?
¿Qué estoy haciendo mal aquí?
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)));
});
Después de muchos experimentos, parece que el siguiente método funciona bien, ¡pero no pudo explicar la lógica del costo de transacción! Cualquier idea es más que bienvenida.
¡De todos modos, la prueba unitaria está pasando ahora!
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");
});
});
Nota: Esta respuesta solo es válida para Truffle v4.
Probé esta prueba con el ejemplo MetaCoin de truffle (es decir, ejecutar truffle unbox metacoin
en un directorio vacío)
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");
});
});
La salida correspondiente es:
Contract: MetaCoin
Initial: 99971803600000000000
GasUsed: 23497
GasPrice: 100000000000
Final: 99969453900000000000
✓ Test gas (199ms)
1 passing (217ms)
Una diferencia es que estoy leyendo el precio del gas de la transacción ( getTransaction(hash).gasPrice
) en lugar de la red eth.gasPrice()
.
getTransaction(hash).gasPrice
es 100000000000 y eth.gasPrice()
es 20000000000 en mis pruebas.El siguiente código es el mismo código que el código de Ismael , con los cambios para trabajar con Truffle v5, como getBalance
tipo de retorno, al lado gasUsed
y gasPrice
los valores no son BN por defecto:
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");
});
});
ismael
gasUsed * gasPrice + value
. Si los contratos hacen una transferencia al remitente que cambiará el saldo final.jimson james
rcpt.cumulativeGasUsed * web3.eth.gasPrice
para obtener el costo de transacción. ¡Pero no funcionó! Si tiene una consola abierta, puede verificar rápidamente lo mismo con Metacoin en un caso de prueba de trufa. ¿Parece alguna prueba mágica de trufas?