llamando a funciones de contrato inteligente desde app.js

Implementé un contrato inteligente en la red de ganache usando trufa de la cuenta 1. El código del contrato inteligente es el siguiente.

pragma solidity ^0.4.0;

import "./strings.sol";
import "./safemath.sol";
contract PublishService {

    using strings for *;
    using SafeMath for uint;
    struct ServiceListStruct {
        string cloudID;
        address gatewayID;
        string serviceProducerID;
        mapping (string => string) serviceProducerMetadata;
        string serviceConsumerMetaAttr;
        string accessControlModel;
    }

    ServiceListStruct[] public BCServiceList;

    uint BCServiceListIndex;

    function PublishService() {
        BCServiceListIndex = 0;
    }

    modifier onlyServiceProducerOwner(address _gatewayID) {
        require(msg.sender == _gatewayID);
        _;
    }

    ServiceListStruct sls;
    uint public maxParams = 0;


    function addEntry(string _cloudID, address _gatewayID, string _serviceProducerID, string _serviceProducerMetadata, string _serviceConsumerMetaAttr, string _accessControlModel) public onlyServiceProducerOwner(_gatewayID) returns (uint) {
        sls.cloudID = _cloudID;
        sls.gatewayID = _gatewayID;
        sls.serviceProducerID = _serviceProducerID;
        sls.serviceConsumerMetaAttr = _serviceConsumerMetaAttr;
        sls.accessControlModel = _accessControlModel;
        BCServiceList.push(sls);
        //
        string memory s1;
        string memory s2 = _serviceProducerMetadata;
        string memory s3;
        bytes memory s2bytes = bytes(_serviceProducerMetadata);
        uint paramCount = 0;
        while(s2bytes.length != 0) {
            (s1,s2) = splitString(s2,";");
            (s1,s3) = splitString(s1,":");
            BCServiceList[BCServiceListIndex].serviceProducerMetadata[s1] = s3;
            paramCount = paramCount.add(1);
            s2bytes = bytes(s2);
        }
        if(maxParams < paramCount) {
            maxParams = paramCount;
        }
        BCServiceListIndex = BCServiceListIndex.add(1);
        return 1;
    }

    function deleteEntry(string _cloudID, address _gatewayID, string _serviceProducerID) public onlyServiceProducerOwner(_gatewayID) returns (uint) {
        require(msg.sender == _gatewayID);
        int pos = -1;
        for(uint index = 0; index < BCServiceList.length; index++) {
            if(compareStringsbyBytes(_cloudID, BCServiceList[index].cloudID)) {
                if(_gatewayID == BCServiceList[index].gatewayID) {
                    if(compareStringsbyBytes(_serviceProducerID, BCServiceList[index].serviceProducerID)) {
                        pos = int(index);
                    }
                }
            }
        }
        if(pos > -1) {
             BCServiceList[index] = BCServiceList[BCServiceList.length -1];
             delete BCServiceList[BCServiceList.length - 1];
             BCServiceList.length--;
             return 1;
        }
        else
            return 0;
    }

    function compareStringsbyBytes(string s1, string s2) internal pure returns(bool) {
        bytes memory s1bytes = bytes(s1);
        bytes memory s2bytes = bytes(s2);
        if(s1bytes.length!=s2bytes.length) {
            return false;
        }
        else {
            for(uint i = 0; i < s1bytes.length; i++) {
                if(s1bytes[i] != s2bytes[i])
                return false;
            }
            return true;
        }
    }

    function splitString(string _s, string _seperator) internal returns(string, string) {
        var s_slice = _s.toSlice();
        var seperator_slice = _seperator.toSlice();
        string memory result = "";
        var result_slice = result.toSlice();
        result_slice = s_slice.split(seperator_slice);
        return (result_slice.toString(), s_slice.toString());
    }
}

Ahora creé un archivo app.js como se muestra a continuación, donde intento llamar a una función de ese contrato inteligente usando PublishService.addEntry (...).

var Web3 = require('web3');
var web3Provider = null;
var PublishService;
var contract = require('./PublishService_abi.js');

function init() {
  //initializing web3 to access blockchain
  initweb3();
}

function initweb3() {
  //To make sure not to overwrite the already set provider when in mist, check first if the web3 is available
  if (typeof web3 !== 'undefined') {
    web3 = new Web3(web3.currentProvider);
  } else {
    // create an instance of web3 using the HTTP provider
    web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545"));
  }
  web3.eth.defaultAccount = web3.eth.accounts[1];
  var PublishServiceContractAddress = "0x6c68d153b9709283e3900e944f1c6677273987c5";
  var PublishServiceContract = new web3.eth.Contract(contract,PublishServiceContractAddress ); 
  PublishService.addEntry("LC1", web3.eth.defaultAccount, "SP1", "location:inside;reading:degree", "scattr", "ngac");
}

init();

Pero esto da un error

TypeError: no se puede leer la propiedad 'addEntry' de undefined

Seguí muchos tutoriales y sugirieron lo mismo, pero no entiendo el motivo del fracaso en mi caso.

¡Gracias!

Respuestas (3)

Está llamando a un método en un objeto que no existe.

Modifica tu código para

PublishServiceContract.addEntry("LC1",web3.eth.defaultAccount,"SP1","ubicación:dentro;lectura:grado","scattr","ngac");
Mi error. pero ahora me sale este errorTypeError: PublishServiceContract.addEntry is not a function

Ahora lo probé de esta manera, siguiendo el tutorial de la tienda de mascotas de trufas

var Web3 = require('web3');
var web3Provider = null;
var contract = require('./PublishService_abi.js');
var PublishServiceContract;

function init() {
  //initializing web3 to access blockchain
  initweb3();
}

function initweb3() {
  //To make sure not to overwrite the already set provider when in mist, check first if the web3 is available
  if (typeof web3 !== 'undefined') {
    web3 = new Web3(web3.currentProvider);
  } else {
    // create an instance of web3 using the HTTP provider
    web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545"));
  }
  web3.eth.defaultAccount = web3.eth.accounts[1];
  var PublishServiceContractAddress = "0x6c68d153b9709283e3900e944f1c6677273987c5";
 PublishServiceContract = new web3.eth.Contract(contract,PublishServiceContractAddress); 
  addServiceProducer("LC1","SP1","location:inside;reading:degree","scattr","ngac");
}

function addServiceProducer(s1,s2,s3,s4,s5) {
    var psinstance;
    PublishServiceContract.deployed().then(function(instance) {
        psInstance = instance;
        psinstance.addEntry(s1,web3.eth.defaultAccount,s2,s3,s4,s5);
    }).then(function(print) {
        console.log("sp details added successfully")
    }).catch(function(err) {
        console.log(err.message);
    });
}

init();

entonces me sale el siguiente error.

TypeError: PublishServiceContract.deployed no es una función

¿Alguna idea sobre el motivo de este error?

gracias de antemano

Si PublishServicees su contrato, no puede llamar a funciones así. Debe instanciar su contrato, y es una función asíncrona, por lo que tendrá que esperar la devolución de la llamada o la variable del contrato será undefined.

Supongo que está tratando de llegar a un contrato por dirección. Hay dos pasos para esto.

  • inicia el contrato, como en el tutorial de trufas. (Eso no debe hacerse en initWeb3(), debe tener una initContract()función.

  • Cree una instancia del contrato. En el tutorial usan App.contracts.myContract.deployed()pero puedes usar App.contracts.myContract.at("0x6c68d153b9709283e3900e944f1c6677273987c5").

En el tutorial usan un init como este:

    initContract: function() {
        $.getJSON('Adoption.json', function(data) {
          // Get the necessary contract artifact file and instantiate it with truffle-contract
          var AdoptionArtifact = data;
          App.contracts.Adoption = TruffleContract(AdoptionArtifact);

          // Set the provider for our contract
          App.contracts.Adoption.setProvider(App.web3Provider);

          // Use our contract to retrieve and mark the adopted pets
          return App.markAdopted();
        });

        return App.bindEvents();
      },

Deberías hacer lo mismo con tu contrato. Pregúntame si hay algo mal.

El tuyo debería verse así:

  initContract: function() {
    $.getJSON('PublishService.json', function(data) {
      var PublishServiceArtifact = data;
      App.contracts.PublishService = TruffleContract(PublishServiceArtifact);

      App.contracts.PublishService.setProvider(App.web3Provider);

      // you don't need to return anything specific so that should work
      return true
    });

    return App.bindEvents();
  },

Y no olvides llamar truffle compiley truffle migrateen tu consola.

Hola, los pasos que mostraste a continuación son básicamente para leer el archivo json y configurar el proveedor, lo cual hice en el siguiente fragmento de código. var contract = require('./PublishService_abi.js');y ` var PublishServiceContractAddress = "0x6c68d153b9709283e3900e944f1c6677273987c5"; PublishServiceContract = new web3.eth.Contract(contrato,PublishServiceContractAddress); `, Traté de hacer una llamada asíncrona como en la respuesta a continuación, pero aparece un error que dice que la implementación no es una función.
@KKolluru No lo entiendo, ¿por qué no empiezas con el tutorial de la tienda de mascotas y construyes desde aquí? Reemplace la initContactfunción para presentar su contrato y reemplace sus llamadas de función por su función.
@KKolluru También debe hacer que la creación de su contrato sea asíncrona. En el tutorial, usan App.contracts.Adoption.deployed(), pero pueden hacerlo porque el contrato se ha instanciado correctamente a través de JSON abi.