Llamar a la función Smart Contract devuelve el objeto tx en lugar del valor de retorno esperado en la prueba de Truffle

Empecé a escribir un contrato inteligente para un registro de regalos.

Cuando escribo pruebas usando Truffle Framework, obtengo valores de retorno inesperados.

Por ejemplo, al llamar a la función offerGift desde dentro de la prueba, devuelve un objeto tx en lugar de la identificación.

Si uso offerGift.call(...) devuelve la identificación, pero cuando llamo a getGift, no se puede encontrar el regalo y aparece el error.

Error: error devuelto: excepción de máquina virtual al procesar la transacción: revertir el regalo no encontrado

Probé las respuestas proporcionadas en Returns TX Object en lugar de dar como resultado la prueba Truffle , pero no funcionaron para mí.

Uso de
Truffle v5.0.18 (núcleo: 5.0.18)
Solidity v0.5.0 (solc-js)
Node v10.15.3
Web3.js v1.0.0-beta.37
Ganache v1.3.1
truffle-assertions 0.9.0

¿Qué estoy haciendo mal?

El Código de Contrato

pragma solidity >=0.4.21 <0.6.0;

contract GiftRegistry {

  uint256 idCounter = 0;
  enum GiftStatus { Offered }

  struct Gift {
    string description;
    uint256 value;
    GiftStatus status;
    address giftGiver;
    address giftReceiver;
    address giftApprover;
  }

  mapping(uint256 => Gift) public giftMap;

  function doesGiftExist(uint256 _giftId) private view returns(bool){
    Gift memory gift = giftMap[_giftId];
    bytes memory giftAsBytes = bytes(gift.description);

    return giftAsBytes.length > 0;
  }

  function getGift(uint256 _giftId) public view returns(string memory, uint256, GiftStatus, address, address, address){
    require(doesGiftExist(_giftId), 'Gift not found');
    Gift memory gift = giftMap[_giftId];

    return (
      gift.description,
      gift.value,
      gift.status,
      gift.giftGiver,
      gift.giftReceiver,
      gift.giftApprover
    );
  }

  function offerGift(string memory _description, uint256 _value, address _giftReceiver) public returns(uint256) {
    uint256 currentId = idCounter;
    giftMap[currentId] = Gift(_description, _value, GiftStatus.Offered, msg.sender, _giftReceiver, address(0));

    idCounter = idCounter + 1;

    return currentId;
  }
}

La prueba de la trufa

const GiftRegistry = artifacts.require('GiftRegistry');
const truffleAssert = require('truffle-assertions');

contract('The Gift Registry contract', accounts => {
  let contract;
  const giftGiverAddress = accounts[1];
  const giftReceiverAddress = accounts[2];

  beforeEach(async () => {
    contract = await GiftRegistry.new({from: accounts[0]});
  });

  describe('given offerGift is called', () => {
    const OfferedStatus = 0;

    it('the status should be set to offered', async () => {
      const fiveDollars = 500;
      // Calling like this returns a tx instead of the id, the gift can be found with a hard coded index of 0
      const giftId1 = await contract.offerGift('coffee', fiveDollars, giftReceiverAddress, {from: giftGiverAddress});
      // This call returns the new giftId, however the gift can't be found and the call to getGift throws the error
      // Error: Returned error: VM Exception while processing transaction: revert Gift not found
       const giftId2 = await contract.offerGift.call('coffee', fiveDollars, giftReceiverAddress, {from: giftGiverAddress});

      const gift = await contract.getGift.call(0);

      assert.equal(OfferedStatus, gift[2]);
    });

  });
});
Una función no constante (ya puresea o view) devuelve el hash de la transacción cuando se ejecuta fuera de la cadena (es decir, por una cuenta de propiedad externa). Tal función debe devolver algo solo si está destinado a ser ejecutado desde la cadena (es decir, por este contrato o por algún otro contrato). Cuando se les llama desde fuera de la cadena, siempre devolverán el hash de la transacción (incluso si no están declarados para devolver nada). Entonces, a menos que tenga la intención de llamarlo desde la cadena, no tiene sentido que esta función devuelva nada.
@goodvibration al eliminar la vista de getGift me da el mismo resultado.
¿Qué tiene que ver el cambio getGiftcon su pregunta y qué quiere decir con "mismo resultado"? ¿El mismo resultado que qué?

Respuestas (1)

.call()finge hacer la transacción y le da el resultado, pero no vuelve a enviar ningún cambio a la cadena de bloques.

Puede encontrar más detalles en Truffle docs pero básicamente dirá que

Cuando ejecuta una función de contrato a través de una llamada, recibirá el valor de retorno inmediatamente

Ejecutar getGiftdespués offerGift.call(...)no funcionará porque idCounterno se actualizó.

Tienes que hacerlo contract.offerGift('coffee', fiveDollars, giftReceiverAddress, {from: giftGiverAddress});y obtendrás el objeto tx. Luego, debe verificar si se extrajo y luego obtener el registro y, del evento de registro, obtener la identificación del regalo que esperaba. No obtendrá el valor de retorno.

Parece más código del que esperaba escribir para una prueba simple :(
Bueno, depende de lo que quieras probar. En este caso, si yo fuera usted, simplemente haría público idCounter (o crearía una función de vista para obtener su valor) y luego verificaría su valor y lo compararía con lo que espera. Algo como esto:contract.idCounter({from: giftGiverAddress})