Вызов функции Smart Contract возвращает объект tx вместо ожидаемого возвращаемого значения в тесте Truffle

Я начал писать смарт-контракт для реестра подарков.

Когда я пишу тесты с использованием Truffle Framework, я получаю неожиданные возвращаемые значения.

Например, при вызове функции offerGift из теста она возвращает объект tx вместо идентификатора.

Если я использую offerGift.call(...), он возвращает идентификатор, но когда я вызываю getGift, подарок не может быть найден, и я получаю сообщение об ошибке

Ошибка: Возвращенная ошибка: Исключение виртуальной машины при обработке транзакции: отменить Подарок не найден

Я пробовал ответы, представленные в «Возвращает объект TX», вместо этого приводит к тесту «Трюфель» , но они не сработали для меня.

Использование
Truffle v5.0.18 (ядро: 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

Что я делаю не так?

Кодекс контракта

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;
  }
}

Трюфельный тест

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]);
    });

  });
});
Непостоянная функция (любая pureили view) возвращает хэш транзакции, когда она выполняется вне цепочки (т. е. учетной записью, принадлежащей извне). Такая функция должна что-то возвращать только в том случае, если она предназначена для выполнения из ончейна (то есть по этому контракту или по какому-то другому контракту). При вызове из офчейна они всегда будут возвращать хэш транзакции (даже если они не объявлены как возвращающие что-либо). Поэтому, если вы не собираетесь вызывать ее из ончейна, эта функция не имеет смысла что-либо возвращать.
@goodvibration удаление представления из getGift дает мне тот же результат.
Какое getGiftотношение изменение имеет к вашему вопросу, и что вы подразумеваете под «тот же результат»? Тот же результат, что и что?

Ответы (1)

.call()делает вид, что выполняет транзакцию, и выдает вам результат, но не передает никаких изменений обратно в блокчейн.

Вы можете найти более подробную информацию в документации Truffle , но в основном там будет сказано, что

Когда вы выполняете функцию контракта через вызов, вы немедленно получите возвращаемое значение.

Выполнение getGiftпосле offerGift.call(...)не будет работать, потому что idCounterне было обновлено.

Вы должны contract.offerGift('coffee', fiveDollars, giftReceiverAddress, {from: giftGiverAddress});, и вы получите объект tx. Затем вы должны проверить, было ли оно добыто, а затем получить журнал и из события журнала получить идентификатор подарка, который вы ожидали. Вы не получите возвращаемое значение.

Кажется, это больше кода, чем я надеялся написать для простого теста :(
Ну, зависит от того, что вы хотите протестировать. В этом случае, если бы я был вами, я бы просто сделал idCounter общедоступным (или создал функцию просмотра , чтобы получить его значение), а затем проверил его значение и сравнил с тем, что вы ожидаете. Что-то вроде этого:contract.idCounter({from: giftGiverAddress})