Prueba de trufa, los registros no incluyen un evento emitido

Estoy llamando a una función de contrato que emite un evento en una transacción. Esta transacción debe incluir el evento y normalmente es visible a través de:

const receipt = await contractInstance.someFunction()
let logs = receipt.logs

Esto normalmente contiene una lista de los nombres de eventos emitidos en la transacción. Sin embargo, en mi llamada, la salida de las pruebas:

[]
    1) Test someFunction()

    Events emitted during test:
    ---------------------------

    Stored()

    ---------------------------

  1 failing

  1) Contract: Test.js
       Test someFunction():
     AssertionError: Stored event not emitted: expected false to be truthy
      at Context.it (test/test.js:145:12)
      at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:188:7)

con bloque de prueba que falla:

const receipt = await instance.someFunction();
let event = validationReceipt.logs.some(l => { return l.event == "Stored" });
console.log(validationReceipt.logs);
assert.ok(event, "Stored event not emitted");

La primera línea realiza la llamada de función que emite el evento Stored. La segunda línea recupera la instancia por nombre de evento de los registros. La tercera línea simplemente registra los eventos contenidos. La cuarta línea afirma que el evento existe en los registros.

Como se muestra en el resultado de la prueba, los registros estaban vacíos [], pero se emitió el evento.

¿Por qué se muestra que el evento se emitió pero tampoco está presente en los registros de la transacción que lo emitió?

Respuestas (2)

Resulta que los registros de recepción de transacciones solo incluyen eventos emitidos en el contexto de la función de contrato directo que se llama. Si la función llamada realiza otra llamada a un contrato externo separado que emite un evento, estos no se incluirán incluso si se emiten.

Para hacer uso de los eventos emitidos de otros contratos:

const sha3 = require('js-sha3').keccak_256
...

const tx = await instance.someFunction(();
let event = tx.receipt.logs.some(l => { return l.topics[0] == '0x' + sha3("Stored()") });
assert.ok(event, "Stored event not emitted");

donde someFunctiones una función que llama a una función de otro contrato diferente a instance.

Esto toma los registros del objeto de recibo. Los registros deben contener temas, el primero de los cuales es una firma de evento con hash. Por lo tanto, podemos usar lo que esperamos que sea nuestra firma de evento, codificarla y probar su existencia en los registros. Esto funciona porque todos los eventos se incluyen en los registros de recepción, pero no se devuelven en los registros de transacciones proporcionados por truffle/ganache.

Esta publicación ayudó.

En versiones posteriores de Truffle (he probado con v5.1.0), los mismos registros y temas se encuentran en una propiedad de recibo de transacción diferente rawLogs:

const tx = await instance.someFunction(();
let event = tx.receipt.rawLogs.some(l => { return l.topics[0] == '0x' + sha3("Stored()") });
assert.ok(event, "Stored event not emitted");
Gran respuesta. Solo para que conste, no tiene que instalar js-sha3, en su lugar puede usar web3.utils.keccak256.
Actualización : parece que este código ya no funciona con la trufa ^5.0.30. No hay temas.
@PaulRazvanBerg El objeto ha cambiado ligeramente, pero aún son accesibles (¡afortunadamente!). He actualizado la respuesta para dar cuenta de esto.

Puede usar web3 y llamar al método Contract con la instancia de truffle abi y la dirección del contrato. Luego usa los métodos de eventos. No es necesario declarar web3 ya que truffle lo proporcionará.

const receipt = await contractInstance.someFunction()

const contract = new web3.eth.Contract(contractInstance.abi, contractInstance.address)

//Now get evens depending on what you need
contract.getPastEvents("allEvents", {fromBlock: 0, toBlock: "latest"})
.then(console.log)  

Siga la documentación de web3.js para obtener más métodos de eventos