Ereignisauslösung, bevor Daten tatsächlich gesetzt werden

Nehmen wir an, dies ist mein Smart Contract:

  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
}

Dies ist meine nodeJS-Datei:

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

Wenn ich das partAmountArray in web3 mit einer .callFunktion logge, werden immer noch die alten Werte vor dem Ereignis zurückgegeben. Dies sagt mir, dass das Ereignis zu früh ausgelöst wird.

Gibt es trotzdem ein Ereignis aufzurufen, nachdem die Daten gesetzt sind?

EDIT: etwas mehr Code.

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

HINWEIS: Wenn ich ein Timeout um die Anruffunktion wie folgt setze:

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

Es gibt das richtige Array zurück, aber es ist nicht die Art und Weise, wie das Skript ausgeführt werden soll.

Antworten (3)

Das Problem ist, dass Sie nicht darauf warten, dass die Transaktion abgebaut wird, bevor Sie .callnach einem Ergebnis suchen.

Es geht:

  1. Unterzeichnen und senden Sie eine Transaktion. Holen Sie sich einen Transaktionsbeleg.
  2. Die Transaktion wird abgebaut und der Vertrag führt die Anweisungen der Reihe nach aus.
  3. Block kommt mit der bestätigten Transaktion an.
  4. Jetzt können Sie calleine Funktion verwenden, um den Effekt zu sehen.

Oder achten Sie auf ein Ereignis, wie es Ihr Beispiel-JS zu tun scheint. Ereignisse kommen erst an, wenn die Transaktion in einem Block enthalten ist.

Ich hoffe es hilft.

Sehen Sie, das ist das erwartete Verhalten, vielleicht hat es etwas damit zu tun, dass ich Trüffel und Ganache verwende? Dass das Ereignis deswegen gefeuert wird, weil es nicht auf einer echten Blockchain ist?
Ja, es wird erwartet, aber nein, Ereignisse werden vor dem Mining nicht ausgelöst. Eine andere Erklärung ist sehr unwahrscheinlich. Sie tun das, callbevor die Transaktion abgebaut wird. Der erste Rückruf gibt einen Transaktions-Hash zurück. Das ist keine Bestätigung von "abgebaut". Es ist nur eine Bestätigung der Anfrage. Es ist üblich, dies mit einer Mining-Bestätigung zu verwechseln. Schau mal hier: gist.github.com/xavierlepretre/88682e871f4ad07be4534ae560692ee6
Ok, ich habe es immer noch nicht geschafft, das Problem zu beheben, also lass mich versuchen, etwas mehr zu erklären. Die Daten, die aus dem Ereignis kommen, sind RICHTIG, das Problem ist, dass die Anruffunktion (die durch das Ereignis ausgelöst wird) danach ruft immer noch die ALTEN Daten ab. Ich werde etwas mehr Code hochladen
Sie verstehen die erwartete Mechanik und ich verstehe Ihre Frustration. Ich glaube nicht, dass Trüffel der wahrscheinliche Schuldige ist, aber Sie haben vielleicht etwas über Ganache entdeckt, das das Ereignis meldet, bevor es den Zustand vollständig verdaut hat, oder vielleicht sogar eine Einschränkung im Zusammenhang mit dem Herumreichen von Arrays. Das ist eine relativ neue Funktion und angesichts der Redundanz normalerweise keine gute Idee. Wenn Sie darüber nachdenken, wenn Kunden Schritt für Schritt über die Zeilen informiert werden, gibt es keinen Grund, nach dem gesamten Array auf einen Schlag zu fragen. Es erklärt nicht, warum es anscheinend fehlschlägt, aber es könnte erklären, warum das Problem besteht.
Vielleicht kann sich jemand mit etwas Einsicht melden, um zu bestätigen, dass Sie garantiert sofort das neueste dynamische Array mit Ganache erhalten. Ich würde erwägen, einen privaten Knoten mit Geth einzurichten, nur um zu sehen, ob das Verhalten eher wie erwartet ist. Bei Meinungsverschiedenheiten gewinnt Geth.
Du könntest Recht haben, trotzdem habe ich eine Lösung gefunden. Siehe meine Antwort.

Wie Rob betonte, warten Sie höchstwahrscheinlich nicht, bis die Transaktion vollständig abgebaut ist, bevor Sie Daten abrufen. Ich bin mir bei web3js nicht sicher, aber Golang bietet die Möglichkeit, ausstehende Zustandsdaten zu lesen, bevor die Transaktion abgebaut wird. Ich persönlich bevorzuge viel Golang zum Schreiben von Backend-Code, der mit intelligenten Verträgen interagiert, und würde nur bei Bedarf web3 verwenden (dh Frontend-Code).

Vorsicht, ich würde jedoch davon abraten, ausstehende Zustandsdaten zu lesen, da sich dies ändern kann, je nachdem, welche Transaktionen in den Mempool eingefügt werden.

Es wird dringend empfohlen, auf das Mining einer Transaktion zu warten, bevor Daten verarbeitet werden, und ich persönlich würde Golang über Web3 für die Interaktion mit Smart Contracts empfehlen und Web3 nur verwenden, wenn ich Frontend-Code schreiben müsste.

Ich habe eine Funktion, die immer dann aufgerufen wird, wenn eine bestimmte Transaktion an die Blockchain gesendet wird, und die Verarbeitung automatisch beendet und nach Erhalt des Ereignisses beendet wird.

https://github.com/RTradeLtd/Temporal/blob/2dd19bd950e2864e2cbad904c3b7c94958499048/server/payments.go#L55

Jetzt, wo ich mit dem Ropsten-Testnet verbunden bin, funktioniert es wie erwartet (wenn der WebSocket-Server aktiv ist).

Ich weiß nicht genau, was das Problem ist, aber ich weiß, dass das Problem in Ganache liegt, das die Ereignisse ausgelöst hat, bevor der nächste Block tatsächlich fertig war und alle Variablen aktualisiert wurden.

Lösung: Arbeiten Sie entweder von Ihrem eigenen lokalen Geth-Server aus oder laden Sie Ihren Vertrag in eines der Testnetze hoch.

Hi @jasper, es sieht so aus, als hättest du dein Problem gelöst. Es wäre ideal, wenn Sie es detailliert ausarbeiten könnten, damit die Gemeinschaft davon profitiert. Wenn Ihnen eine der anderen Antworten geholfen hat, ist es besser, wenn Sie sie akzeptieren und bearbeiten, wenn Sie einen zusätzlichen Schritt befolgt haben.
Hallo Achala, du hast Recht!
Großartig, es wäre schön, eine akzeptierte Antwort zu haben, sogar Ihre eigene Antwort :).
Ich werde es als die richtige Antwort markieren, wenn ich in 23 Stunden dazu in der Lage bin :)
Das ist großartig :)