Состояние контракта не изменится во время тестов Truffle

Я пытаюсь проверить свои контракты, используя пакет Truffle вместе с Ganache.

До сих пор я тестировал контрактные функции, которые ограничены viewтолько. Теперь, когда я пытаюсь внести изменения в состояние контракта, я обнаруживаю, что состояние на самом деле не изменяется между вызовами функций.

Рассмотрим следующий простой контракт:

pragma solidity ^0.4.24;

import "../OrderBook.sol";

contract IdManager {
    uint256 newId;

    function addId() public returns (uint256) {
        newId++;
        return newId;
    }
}

Все, что я хочу сделать, это увеличить newIdи вернуть его новое значение.

Код, который я написал, чтобы проверить это:

const { getWeb3, getContractInstance, parseSignature } = require("./test_helper");
const web3 = getWeb3();
const getInstance = getContractInstance(web3);

contract('IdManager', (accounts) => {
    let IdManager = getInstance('IdManager');

    it('test addId()', async () => {
        console.log(await IdManager.methods.addId().call());
        console.log(await IdManager.methods.addId().call());
        console.log(await IdManager.methods.addId().call());
    });
});

Вызов getInstance()использует Web3 v1.0, основанный на этом руководстве .

С приведенным выше тестом я ожидаю, что результат будет следующим:

1
2
3

Но на самом деле я получаю:

1
1
1

Кто-нибудь сталкивался с этой проблемой раньше?


Редактировать0:

console.log(await IdManager.methods.newId().call()); должно было быть console.log(await IdManager.methods.addId().call());newId()теперь addId().


Редактировать1:

Следуя совету goodvibration, я изменил пример контракта следующим образом:

contract IdManager {
    uint256 public newId;

    function addId() public {
        newId++;
    }

    function getId() public view returns (uint256) {
        return newId;
    }
}

Код теста был изменен на следующее:

it('test addId()', async () => {
    await IdManager.methods.addId().call();
    console.log(await IdManager.methods.getId().call());

    await IdManager.methods.addId().call();
    console.log(await IdManager.methods.getId().call());

    await IdManager.methods.addId().call();
    console.log(await IdManager.methods.getId().call());
});

К сожалению, мой вывод по-прежнему показывает, что состояние не сохраняется:

0
0
0
Вы addIdникуда не звоните в своем тесте!!!!!
Я обновил свой вопрос, newId()должен был быть addId(). Извинения.
Что такое OrderBook??? Возможно, это старый контракт, с которым вы пытались провести этот тест?
Извини, у меня не очень хороший день. Я беру не тот набор тестов! Я снова обновил свой вопрос.

Ответы (3)

Простое решение этой проблемы было прямо у меня под носом. Очевидно, мне просто нужно было прочитать предоставленную мне документацию.

методы.myMethod.call

Вызов Note не может изменить состояние смарт-контракта .

методы.myMethod.send

Обратите внимание, что это может изменить состояние смарт-контракта .

Итак, переделка последнего пассажа тестового кода в моем вопросе выглядит следующим образом:

it('test addId()', async () => {
    await IdManager.methods.addId().send({from: accounts[0]});
    console.log(await IdManager.methods.getId().call());

    await IdManager.methods.addId().send({from: accounts[0]});
    console.log(await IdManager.methods.getId().call());

    await IdManager.methods.addId().send({from: accounts[0]});
    console.log(await IdManager.methods.getId().call());
});

Что приводит к моему желаемому результату:

1
2
3

Функция addId— непостоянная функция (т. е. не объявленная как pureили view).

Таким образом, его возвращаемое значение может использоваться только в цепочке, то есть другими функциями (в том же контракте или в других контрактах), которые его вызывают.

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

Если вам нужно фактическое возвращаемое значение, вам нужно указать emitего в файле event, который позже вы сможете извлечь из квитанции.

Например:

event Event(uint256 val);
function addId() public returns (uint256) {
    newId++;
    emit Event(newId);
    return newId;
}

В качестве альтернативы, поскольку в вашем конкретном случае вы возвращаете значение глобальной переменной (состояния), вы можете объявить ее public, а затем просто прочитать ее из контракта, используя ее (неявную) функцию получения:

console.log(await IdManager.methods.newId().call());
Я должен был помнить, что выполнение таких функций возвращает только квитанцию ​​​​Tx, когда я использовал только Web3и remix! Но я изменил свой тестовый код, чтобы получить член Idчерез отдельный вызов функции. Я все еще не вижу изменения состояния между вызовами.

По состоянию на декабрь 2021 года Truffle изменил способ оформления контракта. Этот вопрос чрезвычайно важен для такого невнимательного человека, как я, поэтому вот пример теста для контракта от Edit1.

const idmanager= artifacts.require("IdManager"); 

contract('IdManager', async accounts => {

    it('test addId()', async () => {
        const instance = idmanager.deployed(); 

        await instance.addId({from: account[0]}); 
        const actual = await instance.getId.call({from: account[0]});

        assert.equal(actual, 1); 
    });
});