Das Aufrufen der Smart Contract-Funktion gibt ein tx-Objekt anstelle des erwarteten Rückgabewerts im Truffle-Test zurück

Ich habe angefangen, einen Smart Contract für eine Geschenkliste zu schreiben.

Wenn ich Tests mit dem Truffle Framework schreibe, erhalte ich unerwartete Rückgabewerte.

Wenn Sie beispielsweise die Funktion offerGift innerhalb des Tests aufrufen, wird anstelle der ID ein tx-Objekt zurückgegeben.

Wenn ich offerGift.call(...) verwende, gibt es die ID zurück, aber wenn ich getGift aufrufe, kann das Geschenk nicht gefunden werden, und ich erhalte die Fehlermeldung

Fehler: Zurückgegebener Fehler: VM-Ausnahme während der Verarbeitung der Transaktion: Geschenk nicht gefunden zurücksetzen

Ich habe die Antworten in Returns TX Object ausprobiert, die stattdessen im Truffle-Test resultieren, aber sie haben bei mir nicht funktioniert.

Verwenden von
Truffle v5.0.18 (Kern: 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

Was mache ich falsch?

Der Vertragscode

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

Der Trüffeltest

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

  });
});
Eine nicht konstante (entweder pureoder view) Funktion gibt den Hash der Transaktion zurück, wenn sie von der Off-Chain ausgeführt wird (dh von einem externen Konto). Eine solche Funktion sollte nur dann etwas zurückgeben, wenn sie von der On-Chain ausgeführt werden soll (dh durch diesen Vertrag oder durch einen anderen Vertrag). Wenn sie von außerhalb der Kette aufgerufen werden, geben sie immer den Hash der Transaktion zurück (selbst wenn sie nicht deklariert sind, etwas zurückzugeben). Wenn Sie also nicht beabsichtigen, es von der On-Chain aufzurufen, hat es keinen Sinn, dass diese Funktion etwas zurückgibt.
@goodvibration Das Entfernen der Ansicht von getGift führt zu demselben Ergebnis.
Was getGifthat das Ändern mit Ihrer Frage zu tun, und was meinen Sie mit "gleichem Ergebnis"? Gleiches Ergebnis wie was?

Antworten (1)

.call()gibt vor, die Transaktion durchzuführen, und gibt Ihnen das Ergebnis, schreibt aber keine Änderungen an die Blockchain zurück.

Weitere Details finden Sie in Truffle docs , aber im Grunde wird das gesagt

Wenn Sie eine Vertragsfunktion über einen Aufruf ausführen, erhalten Sie sofort den Rückgabewert

Das Ausführen getGiftdanach offerGift.call(...)funktioniert nicht, da idCounteres nicht aktualisiert wurde.

Sie müssen contract.offerGift('coffee', fiveDollars, giftReceiverAddress, {from: giftGiverAddress});und Sie erhalten das tx-Objekt. Dann müssen Sie überprüfen, ob es abgebaut wurde, und dann das Protokoll und aus dem Protokollereignis die Geschenk-ID abrufen, die Sie erwartet haben. Sie erhalten den Rückgabewert nicht.

Das scheint mehr Code zu sein, als ich gehofft hatte, für einen einfachen Test zu schreiben :(
Nun, kommt darauf an, was Sie testen möchten. In diesem Fall würde ich an Ihrer Stelle einfach idCounter öffentlich machen (oder eine Ansichtsfunktion erstellen, um seinen Wert abzurufen) und dann seinen Wert überprüfen und mit dem vergleichen, was Sie erwarten. Etwas wie das:contract.idCounter({from: giftGiverAddress})