La transacción de Web3 a un contrato falla con la reversión. La misma transacción funciona desde la consola de trufas

Tengo una transacción de contrato simple que crea otro contrato. Esta transacción cuando se llama desde Node.js usando Web3y truffle-contractlanza una reversión.

ContractFactory.deployed().then(function(instance) {
    return instance.createStore({from: accounts[0]}); 
});

Resultado:

2018-05-14T07:34:58.260Z develop:testrpc   Transaction: 0xc93859052bea36bd76c80ab21d30c90a3002303ec7eb1e3ea6d08cd002990d74
2018-05-14T07:34:58.261Z develop:testrpc   Gas usage: 89462
2018-05-14T07:34:58.261Z develop:testrpc   Block Number: 39
2018-05-14T07:34:58.261Z develop:testrpc   Block Time: Mon May 14 2018 13:04:58 GMT+0530 (India Standard Time)
2018-05-14T07:34:58.261Z develop:testrpc   Runtime Error: revert

Cuando llamo a la misma transacción truffle consoleo truffle developla transacción se realiza correctamente.

truffle (develop) > ContractFactory.deployed().then(function (instance) { return instance.createStore() });

Resultado:

2018-05-14T07:30:33.789Z develop:testrpc   Transaction: 0xbdc51bb74de2b59e98ad1b8f38ed4367c2d975a77340d778e44ee2ced969e5b9
2018-05-14T07:30:33.789Z develop:testrpc   Gas usage: 135843
2018-05-14T07:30:33.789Z develop:testrpc   Block Number: 38
2018-05-14T07:30:33.789Z develop:testrpc   Block Time: Mon May 14 2018 13:00:33 GMT+0530 (India Standard Time)
2018-05-14T07:30:33.789Z develop:testrpc
2018-05-14T07:30:33.791Z develop:testrpc eth_getTransactionReceipt

He estado tratando de ponerme truffle debuga trabajar, pero falla al depurar las transacciones que crean otro contrato.

Mi suposición inicial fue que mi transacción Web3 se está quedando sin el límite de gas establecido, pero ¿provocaría una reversión? Intenté establecer el límite de gas en un valor muy alto pero no obtuve mejores resultados.

ContractFactory.defaults({
  gasLimit: "100000000000000000"
});

Código de contrato:

pragma solidity ^0.4.16;

contract SimpleStore {
    uint public value;
    function SimpleStore (uint num) public {
        value = num;
    }

    function setValue (uint num) public {
        value = num;
    }
}

contract ContractFactory {

    address public store;

    function ContractFactory () public {

    }

    function createStore () public {
        store = new SimpleStore(12);
    }
}

Nota: Otras transacciones y llamadas funcionan muy bien con la configuración de Web3. Este problema es común para todas las transacciones que crean un contrato.

¿Lo probaste en alguna otra red que testrpc? prueba rinkeby y luego publica txhash para que la gente lo compruebe.
¿Puedes publicar tu archivo NodeJS?
Haré esta transacción en una red de prueba y proporcionaré un hash hoy, también publicaré el Contrato JSON.

Respuestas (3)

Puedo reproducir el problema al que te enfrentabas. Hice lo siguiente para resolver este problema. Se crearon dos archivos de contratos separados dentro de la carpeta de contratos para SimpleStore y ContrctFactory de la siguiente manera: - archivo SimpleStore.sol -

pragma solidity ^0.4.16;

contract SimpleStore {
    uint public value;
    function SimpleStore (uint num) public {
        value = num;
    }

    function setValue (uint num) public {
        value = num;
    }
}

Archivo ContractFactory.sol -

pragma solidity ^0.4.16;

contract SimpleStore {
    uint public value;
    function SimpleStore (uint num) public {
        value = num;
    }

    function setValue (uint num) public {
        value = num;
    }
}
contract ContractFactory {

    address public store;

    function ContractFactory () public {

    }

    function createStore () public {
        store = new SimpleStore(12);
    }
}

Archivo 2_deploy_contracts.js -

var SimpleStore = artifacts.require("./SimpleStore.sol");
var ContractFactory = artifacts.require("./ContractFactory.sol");
module.exports = function(deployer) {
  deployer.deploy(SimpleStore,10, {gas: 6700000});
  deployer.deploy(ContractFactory,{gas: 6700000});
};

archivo app.js -

import { default as Web3} from 'web3';
import { default as contract } from 'truffle-contract'
import SimpleStore_artifacts from '../../build/contracts/SimpleStore.json'
import ContractFactory_artifacts from '../../build/contracts/ContractFactory.json'

var SimpleStore = contract(SimpleStore_artifacts);
var ContractFactory = contract(ContractFactory_artifacts);
$( document ).ready(function() {
  if (typeof web3 !== 'undefined') {
    console.warn("Using web3 detected from external source like Metamask")
    // Use Mist/MetaMask's provider
    window.web3 = new Web3(web3.currentProvider);
  } else {
    console.warn("No web3 detected. Falling back to http://localhost:8545. You should remove this fallback when you deploy live, as it's inherently insecure. Consider switching to Metamask for development. More info here: http://truffleframework.com/tutorials/truffle-and-metamask");
    // fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
    window.web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

  }
  SimpleStore.setProvider(web3.currentProvider);
  ContractFactory.setProvider(web3.currentProvider);
  ContractFactory.deployed().then(function(instance) {
    return instance.createStore({from: web3.eth.accounts[0],gas: 6700000}); 
    console.log("******");
  });
});

Agregar el costo del gas como argumento ha resuelto el problema de la excepción de VM.

instancia.createStore({de: web3.eth.accounts[0],gas: 6700000});

También puedo ejecutar transacciones desde la consola de trufas:

truffle(development)> ContractFactory.deployed().then(function (instance) { return instance.createStore({from: web3.eth.accounts[0],gas: 6700000});})
{ tx: '0x4d34e45cddbfa6f087f5dcb02bb5e7dc0fa18a0f7d24e87f8fff8702dd3e53bc',
  receipt: 
   { transactionHash: '0x4d34e45cddbfa6f087f5dcb02bb5e7dc0fa18a0f7d24e87f8fff8702dd3e53bc',
     transactionIndex: 0,
     blockHash: '0xf77b2baa3cacc941a8376376425c642c6db580e4a26918a0905ed589a618bfe7',
     blockNumber: 26,
     gasUsed: 123078,
     cumulativeGasUsed: 123078,
     contractAddress: null,

La respuesta podría ser realmente simple: la gascantidad que envía la trufa por defecto en una llamada de función es 90000. Puede ver que su transacción se cancela en un consumo que se cancela cerca de ese valor. La transacción tiene éxito con un valor más alto aunque desde la consola de trufas, que usa la estimación de gas, creo. Lo que planteaste fue el gasLimit, que != gas.

Entonces, en realidad es muy simple (la solución de mirgi ya lo tiene, solo que no es realmente conciso)

ContractFactory.deployed().then(function(instance) {
    return instance.createStore({from: accounts[0], gas:150000}); 
});
Eso es todo. Lo resolví durante el último fin de semana y no pude actualizar aquí porque he estado viajando. Realmente aprecio tu ayuda :)
Llegó otra respuesta antes de la tuya, pero ya te había otorgado la recompensa, así que soy la otra respuesta válida para ser justos. <sonrisa>

No sé por qué will no funciona truffle-contract, ya que no está el código completo, pero puede evitar usarlo y simplemente crear su instancia usando web3.

var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

web3.eth.getAccounts(function(error, accounts) {
    var myContract = new web3.eth.Contract([
        {
          "constant": true,
          "inputs": [],
          "name": "store",
          "outputs": [
            {
              "name": "",
              "type": "address"
            }
          ],
          "payable": false,
          "stateMutability": "view",
          "type": "function"
        },
        {
          "inputs": [],
          "payable": false,
          "stateMutability": "nonpayable",
          "type": "constructor"
        },
        {
          "constant": false,
          "inputs": [],
          "name": "createStore",
          "outputs": [],
          "payable": false,
          "stateMutability": "nonpayable",
          "type": "function"
        }
      ]);
    myContract.deploy({
        data: '[bytecode]',
    })
    .send({
        from: accounts[0],
        gas: 1500000,
        gasPrice: '30000000000000'
    }, function(error, transactionHash){ console.log(error, transactionHash); })
    .on('error', console.log)
    .then(function(newContractInstance){
        console.log(newContractInstance.options.address);
        newContractInstance.methods.createStore().send({from: accounts[0], gas: "1500000"}).then(console.log).catch(console.log);
    });
});

simplemente cambie esta línea data: '[bytecode]'con el código de bytes y funcionará.