Activación de eventos antes de que se establezcan realmente los datos

Digamos que este es mi contrato inteligente:

  event NewUser(
    address userAddress,
    uint amount
  );
  function addUser() public payable{
    require(msg.value <= maxValue && msg.value > 0);
    require(allowedValues[msg.value]);
    require(accountAmount() < 5);

    if (users[msg.sender] > 0) {
        userPullout(); //Remove senders data
    }

    userAddresses.push(msg.sender);
    partAmounts.push(msg.value);// This value doesn't get pushed before the event is finished
    users[msg.sender] = msg.value;

    emit NewUser(msg.sender, msg.value);//This is called to soon
}

Este es mi archivo nodeJS:

app.contract.events.NewUser({}, function(error, event){})
.on('data', function(event){
  io.emit('new user', event.returnValues);
}).on('change', function(event){
  io.emit('new user', event.returnValues);
})
.on('error', console.error);

Si registro la partAmountmatriz en web3 con una .callfunción, los valores antiguos antes del evento todavía se devuelven. Esto me dice que el evento se dispara demasiado pronto.

¿Hay alguna forma de llamar a un evento después de configurar los datos?

EDITAR: un poco más de código.

const socket = openSocket('http://localhost:3000'); // subscribed to the socket server firing the events from node back-end
socket.on('new user', (event) => {
  console.log(event) // returns for example 7 which is CORRECT
  this.props.contract.methods.getCertainArray().call(this.props.contractObject, (err, res) => {
    console.log(res); // old data from before the event so if the previous array was [0, 6 , 6], this would still be returned NOTICE: no 7 in the array yet.
  });
})

NOTA: si pongo un tiempo de espera establecido alrededor de la función de llamada como esta:

setTimeout(() => {
    this.props.contract.methods.getCertainArray().call(this.props.contractObject, (err, res) => {
      console.log(res); // old data from before the event so if the previous array was [0, 6 , 6], this would still be returned NOTICE: no 7 in the array yet.
    });
}, 5000);

Devuelve la matriz correcta, pero no es la forma en que quiero que se ejecute el script.

Respuestas (3)

El problema es que no está esperando a que se extraiga la transacción antes .callde verificar el resultado.

Va:

  1. Firma y envía una transacción. Obtenga un recibo de la transacción.
  2. La transacción se extrae y el contrato ejecuta las instrucciones, en orden.
  3. El bloque llega con la transacción confirmada.
  4. Ahora puedes usar calluna función para ver el efecto.

O bien, esté atento a un evento, como aparece en su ejemplo JS. Los eventos no llegan hasta que la transacción se incluye en un bloque.

Espero eso ayude.

Mira, ese es el comportamiento esperado, ¿tal vez tenga algo que ver con el hecho de que estoy usando trufa y ganache? ¿Que debido a esto el evento se dispara porque no está en una cadena de bloques real?
Sí, se espera, pero no, los eventos no se activan antes de la minería. Es muy improbable cualquier otra explicación. Lo estás haciendo callantes de que se extraiga la transacción. La primera devolución de llamada proporciona un hash de transacción. Eso no es una confirmación de "minado". Es solo un acuse de recibo de la solicitud. Es común confundir eso con la confirmación de minería. Echa un vistazo aquí: gist.github.com/xavierlepretre/88682e871f4ad07be4534ae560692ee6
Ok, todavía no he logrado solucionar el problema, así que tratemos de explicar un poco más ... Los datos que surgen del evento son CORRECTOS, el problema es que la función de llamada (que se activa por el evento) después de eso aún recupera los datos ANTIGUOS. Subiré un poco más de código.
Entiendes la mecánica esperada y entiendo tu frustración. No creo que la trufa sea el culpable probable, pero es posible que hayas descubierto algo sobre el ganache que informa el evento antes de que haya digerido completamente el estado, o tal vez incluso una advertencia relacionada con el paso de matrices. Esa es una característica relativamente nueva y, por lo general, no es una buena idea dada la redundancia. Si lo piensa, cuando a los clientes se les informa acerca de las filas paso a paso, no hay motivo para pedir la matriz completa de un solo trago. No explica por qué parece fallar, pero podría explicar por qué existe el problema.
Tal vez alguien pueda intervenir con alguna idea para confirmar que tiene la garantía de obtener la matriz dinámica más reciente de inmediato, con ganache. Consideraría configurar un nodo privado con geth solo para ver si el comportamiento es más como el esperado. En caso de desacuerdo, geth gana.
Puede que tengas razón, de todos modos encontré una solución. Mira mi respuesta.

Como señaló Rob, lo más probable es que no esté esperando a que la transacción se extraiga por completo antes de extraer datos. No estoy seguro acerca de web3js, pero Golang brinda la capacidad de leer datos de estado pendientes antes de que se extraiga la transacción. Personalmente, prefiero golang para escribir código backend que interactúe con contratos inteligentes, y solo usaría web3 si fuera necesario (es decir, código frontend)

Sin embargo, tenga cuidado, recomendaría no leer los datos de estado pendientes, ya que eso puede cambiar dependiendo de las transacciones que se inserten en el mempool.

Se recomienda encarecidamente esperar a que se extraiga una transacción antes de procesar cualquier dato, y personalmente recomendaría golang sobre web3 para interactuar con contratos inteligentes, y solo usaría web3 si necesitara escribir código de interfaz.

Tengo una función que se llama cada vez que se envía una transacción en particular a la cadena de bloques, y automáticamente terminará de procesarse y saldrá después de recibir el evento.

https://github.com/RTradeLtd/Temporal/blob/2dd19bd950e2864e2cbad904c3b7c94958499048/servidor/pagos.go#L55

Ahora que estoy conectado a la red de prueba de Ropsten, funciona como se esperaba (si el servidor WebSocket está activo).

No sé exactamente cuál es el problema, pero sí sé que el problema radica en Ganache, que activó los eventos antes de que el siguiente bloque terminara de extraerse y todas las variables se actualizaran.

Solución: Trabaje desde su propio servidor Geth local o cargue su contrato en una de las redes de prueba.

Hola @jasper, parece que resolviste tu problema. Sería ideal que lo puedan elaborar de manera detallada, para que la comunidad se vea beneficiada. Si alguna de las otras respuestas lo ayudó, sería mejor que pueda aceptarlo y editarlo si siguió algún paso adicional.
Hola Achala tienes razón!
Genial, sería bueno tener una respuesta aceptada, incluso tu propia respuesta :).
La marcaré como la respuesta correcta cuando pueda en 23 horas :)
Genial :)