¿Cómo estimar el costo de llamar a un método de contrato inteligente?

Después de implementar con éxito este contrato inteligente en la red de prueba de Ethereum

https://testnet.etherscan.io/address/0x27c042342C9ba937214117e11A4970A6145034cB

¿Es posible calcular cuánto gas se necesitará para invocar un método determinado del contrato inteligente?

Lectura ¿Cómo estimar el gas para una función sin ningún parámetro de entrada? y ¿Cuánto cuesta usar un contrato? y ¿Cuáles son las limitaciones para estimar Gas y cuándo su estimación sería considerablemente incorrecta? no me ayudo como esperaba...

Así es como se crea una instancia del contrato inteligente en la línea de comando de la consola geth:

// creation of contract object
var aContract = web3.eth.contract([ { "constant": true, "inputs": [], "name": "queryNumEscrows", "outputs": [ { "name": "", "type": "uint256", "value": "0" } ], "type": "function" }, { "constant": true, "inputs": [ { "name": "escrowId", "type": "uint256" } ], "name": "queryStatus", "outputs": [ { "name": "status", "type": "uint256", "value": "0" } ], "type": "function" }, { "constant": false, "inputs": [ { "name": "seller", "type": "address" }, { "name": "thirdParty", "type": "address" } ], "name": "start1", "outputs": [ { "name": "escrowId", "type": "uint256" } ], "type": "function" }, { "constant": false, "inputs": [ { "name": "escrowId", "type": "uint256" } ], "name": "revoke", "outputs": [ { "name": "amount", "type": "uint256" } ], "type": "function" }, { "constant": false, "inputs": [ { "name": "escrowId", "type": "uint256" } ], "name": "release", "outputs": [ { "name": "amount", "type": "uint256" } ], "type": "function" }, { "constant": false, "inputs": [ { "name": "seller", "type": "address" }, { "name": "thirdParty", "type": "address" } ], "name": "start", "outputs": [ { "name": "", "type": "uint256" } ], "type": "function" }, { "constant": false, "inputs": [], "name": "kill", "outputs": [], "type": "function" } ]);

// initiate contract for an address
var sc = aContract.at('0x27c042342C9ba937214117e11A4970A6145034cB');

// view code
eth.getCode(sc.address);

Ahora, quiero enviar esta transacción al Smart Contract, pero me gustaría saber previamente cuánto gas va a tomar:

sc.start.sendTransaction("0x90e8682b63d7922a3e942d4bbd4c88095634a17b", "0x47978a69f410d0f61850c92acdb0d4c464d70937", {from:"0x3b877e80b5c0b29d88f3768ed4292b35fdd93a9d", value:"0x3b9aca00"});

para evitar este mensaje:

"Warning! Error encountered during contract execution [Out of gas]".

Supongo que se debe usar el siguiente método json-rpc:

https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_estimategas

He leído en docs que:

When calling SCs => data: DATA - (optional) Hash of the method signature and encoded parameters.

Pero no entienda cómo codificar el nombre del método, los parámetros y el ABI en el campo de datos. ¿Alguna idea?

¿O hay alguna otra forma de abordar este problema?

Gracias.

Hay un ejemplo resuelto en ethereum.stackexchange.com/questions/7557/… . Luego busque en este sitio ABI para calcular la codificación.
Gracias, ese es un buen punto de partida...

Respuestas (2)

La documentación es escasa en detalles y me tomó una eternidad descubrir la forma correcta con la ayuda de sus enlaces, de todos modos, esto es lo que funciona para mí:

Probado en Geth: 1.6.7 -stable, web3.js: 0.20.2 Parity/v1.7.2 y Kovan testnet.

Usaré el token mínimo como ejemplo:

pragma solidity ^0.4.0;

contract minimalToken {

     mapping (address => uint256) public balanceOf;

    function minimalToken(uint256 initialSupply) {
        balanceOf[msg.sender] = initialSupply;
    }

    function transfer(address _to, uint256 _value) {
        require(balanceOf[msg.sender] >= _value);
        require(balanceOf[_to] + _value >= balanceOf[_to]);
        balanceOf[msg.sender] -= _value;
        balanceOf[_to] += _value;
    }
}

Me centraré en el método de transferencia que requiere 2 argumentos (dirección, cantidad) para transferir:

    var contract = web3.eth.contract(contractABI).at("0x8caaa1f263ff14d0276ff1a1a6ed15c51159d6e0");
    var receiverAddress = '0x00Ce6C92856A657979E7728005DBc9acD002Eb09';
    var callData = contract.transfer.getData(receiverAddress, 2000);

    var gasEstimate = web3.eth.estimateGas({
        from: web3.eth.coinbase,
        to: "0x8caaa1f263ff14d0276ff1a1a6ed15c51159d6e0",
        data: callData
    });

    var gasPrice = web3.eth.gasPrice;

    console.log('gas Price: ' + gasPrice);
    console.log('Estimated Transaction gas: ' + gasEstimate);

// gas Price: 21000000000
// Estimated Transaction gas: 34207

Una cosa que me desconcertó fue que seguía recibiendo errores de transacción debido a que no incluía el campo de: en la transacción.

Espero que esto ayude.

Si desea saber esto en desarrollo , puede obtener una buena estimación utilizando testrpc para simular la cadena de bloques. Después de enviar una transacción, le indicará el uso de gas en la terminal.

Si está experimentando errores de falta de gas, también puede considerar usar testrpc (o la solidez del navegador) para determinar que en realidad es un error de falta de gas. Otros errores (lanzamientos, búsquedas de matrices incorrectas, etc.) aparecerán como OOG en la mayoría de los nodos. testrpc y browser-solidity le dirán si es otra cosa.