El estado del contrato no cambiará durante las pruebas de Truffle

Estoy tratando de probar mis contratos usando la suite Truffle, junto con Ganache.

Hasta ahora, he estado probando funciones de contrato que están restringidas a viewsolo. Ahora, cuando intento hacer cambios en el estado del contrato, descubro que el estado en realidad no se cambia entre llamadas a funciones.

Considere el siguiente contrato simple:

pragma solidity ^0.4.24;

import "../OrderBook.sol";

contract IdManager {
    uint256 newId;

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

Todo lo que deseo hacer es incrementar newIdy devolver su nuevo valor.

El código que he escrito para probar esto es:

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

La getInstance()llamada está utilizando Web3 v1.0, según este tutorial .

Con la prueba anterior, esperaría que el resultado fuera:

1
2
3

Pero, en realidad obtengo:

1
1
1

¿Alguien se ha encontrado con este problema antes?


Editar0:

console.log(await IdManager.methods.newId().call()); debería haber sido console.log(await IdManager.methods.addId().call());newId()es ahora addId().


Edit1:

Siguiendo el consejo de goodvibration, he modificado el contrato de ejemplo para que sea el siguiente:

contract IdManager {
    uint256 public newId;

    function addId() public {
        newId++;
    }

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

El código de prueba ha sido modificado a lo siguiente:

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

Desafortunadamente, mi salida aún muestra que el estado no se conserva:

0
0
0
¡No estás llamando addIda ninguna parte en tu prueba!!!!!
He actualizado mi pregunta, newId()debería haber sido addId(). Disculpas.
que es OrderBook??? ¿Es posible que ese sea el antiguo contrato con el que intentabas realizar esta prueba?
Lo siento, no estoy teniendo un muy buen día. ¡Estoy sacando del conjunto equivocado de pruebas allí! He actualizado mi pregunta de nuevo.

Respuestas (3)

Una solución simple a esto estaba justo debajo de mis narices. Obviamente, solo tenía que leer la documentación que me dieron.

métodos.myMethod.call

Tenga en cuenta que la llamada no puede alterar el estado del contrato inteligente .

métodos.myMethod.send

Tenga en cuenta que esto puede alterar el estado del contrato inteligente .

Entonces, la alteración del último paso del código de prueba en mi pregunta es la siguiente:

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

Lo que da como resultado mi resultado deseado:

1
2
3

Función addIdes una función no constante (es decir, no declarada como pureo view).

Como tal, su valor de retorno solo puede ser utilizado en la cadena, es decir, por otras funciones (en el mismo contrato o en otros contratos) que lo llamen.

Cuando llama a dicha función desde fuera de la cadena, se ejecuta una transacción en la cadena y lo que obtiene a cambio es un recibo de esa transacción.

Si desea obtener el valor de devolución real, debe incluirlo emiten un correo electrónico event, que luego podrá extraer del recibo.

Por ejemplo:

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

Alternativamente, dado que en su caso específico está devolviendo el valor de una variable global (de estado), puede declararla publicy luego simplemente leerla del contrato usando su función de obtención (implícita):

console.log(await IdManager.methods.newId().call());
¡Debería haber recordado que ejecutar tales funciones solo devuelve el recibo Tx, de cuando solo usaba Web3y remix! Pero modifiqué mi código de prueba para recuperar el miembro Ida través de una llamada de función separada. Todavía no veo un cambio de estado entre llamadas.

A partir de diciembre de 2021, Truffle cambió la forma en que se debe llamar el contrato. Esta pregunta es extremadamente importante para alguien tan distraído como yo, así que aquí hay una prueba de muestra para el contrato de 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); 
    });
});