Tener problemas para interactuar con un contrato simple

Soy un principiante que intenta interactuar con un contrato simple a través de web3 y tengo algunos problemas que no puedo resolver.

He escrito un contrato básico con una estructura y dos funciones. Esto básicamente se copia de aquí: Devolver una estructura y leer a través de Web3

contract MyContract {
    struct MyStruct {
        address a;
        uint b;
    }

    MyStruct[] public MyStructs;

    function getStruct(uint index) public constant returns (address, uint) {
        return (MyStructs[index].a, MyStructs[index].b);
    }

    function addStruct(address _a, uint _b) public returns (uint){
        MyStruct memory a = MyStruct(_a, _b);
        MyStructs.length++;
        MyStructs.push(a);
        return MyStructs.length;
    }
}

Tengo dos funciones de prueba que invoco usando la función de prueba de truffle. Estos se copian básicamente de http://truffleframework.com/docs/getting_started/javascript-tests

var MyContract = artifacts.require("MyContract");


contract('MyContract', function() {
  it("should create a stuct", function() {
    return MyContract.deployed().then(function(instance) {
      return instance.addStruct.call(0xf17f52151EbEF6C7334FAD080c5704D77216b732, 1000);
    }).then(function(length) {
       console.log(length);
       assert.equal(length, 1, "length is not 1");

    });
  });

  it("get the struct that was previously created", function() {
    return MyContract.deployed().then(function(instance) {
      return instance.getStruct.call(0);
    }).then(function(values) {
      console.log(values);
      assert.equal(values, (0xf17f52151EbEF6C7334FAD080c5704D77216b732, 1000));
    });
  });
});

Cuando ejecuto esto, obtengo lo siguiente:

  Contract: MyContract { [String: '2'] s: 1, e: 0, c: [ 2 ] }
    1) should create a stuct
    > No events were emitted
    2) get the struct that was previously created
    > No events were emitted


  0 passing (190ms)   2 failing

  1) Contract: MyContract should create a stuct:
     AssertionError: length is not 1: expected { Object (s, e, ...) } to equal 1
      at test/mycontract.js:10:15
      at process._tickCallback (internal/process/next_tick.js:103:7)

  2) Contract: MyContract get the struct that was previously created:
     Error: Invalid JSON RPC response: {"id":21,"jsonrpc":"2.0"}
      at Object.InvalidResponse (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:41483:16)
      at /usr/local/lib/node_modules/truffle/build/cli.bundled.js:330353:36
      at /usr/local/lib/node_modules/truffle/build/cli.bundled.js:326008:9
      at XMLHttpRequest.request.onreadystatechange (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:329052:7)
      at XMLHttpRequestEventTarget.dispatchEvent (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:176427:18)
      at XMLHttpRequest._setReadyState (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:176717:12)
      at XMLHttpRequest._onHttpResponseEnd (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:176872:12)
      at IncomingMessage.<anonymous> (/usr/local/lib/node_modules/truffle/build/cli.bundled.js:176832:24)

En otras palabras, cuando llega a console.log(longitud), que debería ser la respuesta de la función addStruct, en su lugar obtiene { [String: '2'] s: 1, e: 0, c: [ 2 ] }y luego obtiene los errores de estructura conError: Invalid JSON RPC response: {"id":21,"jsonrpc":"2.0"}

¿Alguna idea de por qué sucede esto? Ambas cosas no significan nada para mí, así que ni siquiera sé qué buscar en Google. Revisé la documentación de Truffle and Solidity y, por lo que sé, estoy haciendo todo correctamente.

Tal vez no esté relacionado, pero lo incluyo en caso de que no lo esté; anteriormente, había implementado esto en Ganache con éxito y estaba jugando en la consola del navegador. Pude llamar a web3.eth.contract(abi) y obtener lo que parece ser la respuesta correcta, pero cuando agregué la dirección como argumento, se negó a darme nada excepto "dirección no válida". Confirmé en la documentación de web3 y ganache que lo estaba haciendo bien unas 10 veces, así que estoy pensando que tal vez algo más esté mal. O tal vez no, siéntete libre de ignorar esta parte.

Respuestas (2)

En el primer escenario, su resultado es BigNumber , por lo que solo necesita agregar .toNumber()a length:

  it("should create a stuct", function() {
    return MyContract.deployed().then(function(instance) {
      return instance.addStruct.call(0xf17f52151EbEF6C7334FAD080c5704D77216b732, 1000);
    }).then(function(length) {
       console.log(length.toNumber());
       assert.equal(length.toNumber(), 1, "length is not 1");
    });
  });

Relacionado: ¿Cuáles son las propiedades C , E y S en el objeto de devolución de llamada de mensaje?


En el segundo escenario, modifiqué un poco tu prueba:

it("get the struct that was previously created", function() {
    return MyContract.deployed().then(function(instance) {
      instance.addStruct.sendTransaction("0xf17f52151ebef6c7334fad080c5704d77216b732", 1000);
      return instance.getStruct.call(1);
    }).then(function(values) {
      console.log(values[0].toString(), values[1].toNumber());
      assert.equal(values[0].toString(), "0xf17f52151ebef6c7334fad080c5704d77216b732", 'blah-blah');
      assert.equal(values[1].toNumber(), 1000, 'blah-blah');
    });
  });

Ejecutaremos sendTransactionpara agregar una nueva estructura a la matriz. Luego lo haremos cally la matriz devuelta se leerá con .toString()y .toNumber()para normalizar la salida.


También es bueno notar que si estamos call getStructcon 0 regresa 0x0000000000000000000000000000000000000000 0.

Y la solución es:

function addStruct(address _a, uint _b) public returns (uint){
    MyStruct memory a = MyStruct(_a, _b);
    MyStructs.push(a);
    // delete this line (MyStructs.length++;)
    return MyStructs.length;
}

Después de esta edición, puede cambiar callel valor de 0 a 1 aquí:

return instance.getStruct.call(0);

@roman-frolov resolvió el primer problema.

Para el segundo problema, creo que el problema es que usó callen lugar de sendTransactioncuando invocó addStruct. Las llamadas en realidad no envían transacciones a la red; simplemente ejecutan la función localmente y luego descartan los efectos secundarios. Entonces, en realidad no se agregó ninguna estructura a MyStructs. La llamada posterior a getStructfallará porque usa un índice no válido en la matriz. (Intenta el índice 0, pero la longitud de la matriz sigue siendo 0).