Doppelte Ereignisse, die in einem Web3-Listener ausgelöst werden

Ich experimentiere damit, Ethereum in eine React-Webanwendung einzubinden, wobei ich dieses nette Tutorial-Repo als Grundlage verwende (danke an uzyn): https://github.com/uzyn/ethereum-webpack-example-dapp

Ich verbinde mich erfolgreich mit der lokalen TestRPC 3.0.3-Instanz, habe einen Solidity 0.4.8 „MyToken“-Vertrag bereitgestellt und schürfe erfolgreich eine Vertragsfunktion namens „Transfer“. Ich weiß aus den aktualisierten Kontoständen, dass die Überweisung nur einmal ausgeführt wird, aber ich erhalte zwei Instanzen des Ereignisses „Überweisung“ in meiner Browserkonsole. Wenn ich die Zeile herausnehme, die das Ereignis ausgibt, bekomme ich nichts in der Konsole.

Könnte jemand vorschlagen, warum das so ist? Vielen Dank!

Ich rufe diese Vertragsfunktion auf, die ein Ereignis ausgibt:

/* Send coins */
function transfer(address _to, uint256 _value) {

    if (balanceOf[msg.sender] < _value) throw;           // Check if the sender has enough
    if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows
    balanceOf[msg.sender] -= _value;                     // Subtract from the sender
    balanceOf[_to] += _value;                            // Add the same to the recipient

    Transfer(msg.sender, _to, _value);                   // Notify anyone listening that this transfer took place
}

Mit diesem Codeblock:

  MyTokenContract.transfer.sendTransaction(
    web3.eth.accounts[1],
    100,
    (error, result) => {
      if (error) {
        console.log(`Error occurred: ${error}`);
        return;
      }

      const accountOneBalance = MyTokenContract.balanceOf(web3.eth.accounts[0]);
      const accountTwoBalance = MyTokenContract.balanceOf(web3.eth.accounts[1]);

      console.log(`accountOneBalance: ${accountOneBalance}`);
      console.log(`accountTwoBalance: ${accountTwoBalance}`);
    }
  );

Und ich habe diesen Web3-Code, der auf Vertragsereignisse wartet:

MyTokenContract.allEvents((error, event) => {
if (error) {
  console.log(`Event error: ${error}`);
  return;
}

const eventName = event.event;
const accountFrom = event.args.from;
const accountTo = event.args.to;
const amount = event.args.value;
console.log(`Event '${eventName}' from account ${accountFrom} to ${accountTo} of ${amount}`);

});

Wenn es ausgeführt wird, erhalte ich zwei Ereignisse, die in meiner Chrome-Konsole protokolliert werden:

accountOneBalance: 249900
accountTwoBalance: 100
Event 'Transfer' from account 0xdd0efd8df206cb598bda146ae567f5d398436226 to 0x7497ac386ae2e1eb58210d08e6c401b56417e04d of 100

Event 'Transfer' from account 0xdd0efd8df206cb598bda146ae567f5d398436226 to 0x7497ac386ae2e1eb58210d08e6c401b56417e04d of 100
Wenn Sie die Zeile verdoppeln, in transferder das Ereignis erstellt wird (wodurch zwei Ereignisse erstellt werden), wie viele Ereignisse werden jetzt protokolliert? Drei? Vier? Ich habe eine Vermutung, dass dies Ihnen beim Debuggen helfen könnte.
Danke für den Vorschlag, ist eine gute Idee. Ich hoffe immer noch, dass es kein dummer Logikfehler ist :) Wenn ich also ein zusätzliches Ereignis hinzufüge und die protokollierten Werte "1" bzw. "2" mache, gibt es 1,2,1,2 aus. Vielleicht hat es etwas damit zu tun, wie React eine Seite lädt. Ich werde weiter nachforschen, wenn ich Zeit habe, und ein Update posten, es sei denn, es gibt einen anderen Vorschlag. Vielen Dank!
muss ein Web3-Fehler sein, haben Sie jemals einen Weg gefunden, dies zu umgehen?

Antworten (6)

Ich hatte das gleiche Problem und die obige Lösung funktionierte nicht, falls der Testrpc ausgeführt wird und bereits einige Ereignisse ausgelöst hat und beim Starten des Web3-Codes die Uhr das zuletzt ausgelöste Ereignis zurückgibt. Was das Problem gelöst und nur neue Ereignisse erhalten hat, ist:

var latestBlock = web3.eth.blockNumber; //get the latest blocknumber
contractInstance.MyEvent({fromBlock: latestBlock}, (error, event) => { 
    if (error) {
     console.log(error); return; 
    } else {
        if(event.blockNumber != latestBlock) {   //accept only new events
        console.log(event);
        latestBlock = latestBlock + 1;   //update the latest blockNumber
        }
    }

Ich hoffe, das hilft!

das hat bei mir funktioniert

MyTokenContract.allEvents({fromBlock:'latest'}, (error, event) => { if (error) { console.log( Event error: ${error}); return; }

Obwohl in den Dokumenten steht, dass „neueste“ die Standardeinstellung ist, hat dies das Auslösen meiner doppelten Ereignisse behoben. Ich habe allEvents nicht verwendet. Ich habe nur ein Ereignis auf dem Vertrag beobachtet.

ich hoffe es hilft.

Ich hatte das noch im März 2019, ich habe es gelöst, indem ich ein Setin meinem Javascript erstellt und in meinem Rückruf blockNumbers hinzugefügt habe, um sicherzustellen, dass keine Duplikate zulässig sind.

var eventBlocks = new Set()

listenCallback = async (error, event, type) => {
  if (error) { console.log(error); }
  else {
    let blockNumber = event.blockNumber;
    if (eventBlocks.has(blockNumber)) return;
    eventBlocks.add(blockNumber);
    //do everything else you want to do
  }
}
Ich teste mit ropsten testnet, und die blockNumber ist bei 2 doppelten Ereignissen nicht gleich: 5777243und5777244

Ich habe genau das gemacht, was oben gemacht wurde. Ich habe mein ursprüngliches Ereignis so abgefangen:

  this.buyEvent = this.$store.state.web3contract.BuyTransaction({},{fromBlock: 0, toBlock: 'latest'});
          this.buyEvent.watch(function(err,res){
console.log(res);
console.log(err);
})

Um das doppelte Auslösen zu beheben, habe ich dieses zusätzliche Codestück eingefügt und es hat mein Problem gelöst.

  this.$store.state.web3contract.allEvents({fromBlock:'latest'}, function (error,event){
    if (error) {
      console.log(error)
    } else {
      console.log("All Events")
      console.log(event);
    }
  })

Es muss ein Fehler in web3 sein, oder ich weiß nicht, was es ist. Ich bin mir sicher, dass ich die Uhrenfunktion nicht zweimal registriere. Wäre toll, wenn jemand bestätigen könnte, ob dies ein Web3-Bug ist.

Ich habe endlich herausgefunden, dass Blockchain Bros

Ich habe einen Bot erstellt, um Käufe/Verkäufe auf Uniswap zu beobachten, und erhielt immer wieder doppelte Übertragungsereignisse für denselben Tx-Hash. Ich bin mir nicht sicher, ob es sich um eine Web3-Sache handelt oder um etwas mit meinem lokalen Eth-Knoten, aber es hat mich verrückt gemacht. Ich habe versucht, auf Blöcke zu beschränken (wie wenn der nächste Block gefunden wurde, ignorieren), aber ich würde mehrere Ereignisse mit demselben Hash im selben Block erhalten, also hat das nicht funktioniert.

Schließlich habe ich einen Weg gefunden, den letzten Tx-Hash mit dem aktuellen zu vergleichen, und wenn sie übereinstimmen, den Rest des Prozesses zu ignorieren; Wenn nicht, weiter mit der Verarbeitung der Transaktion:



    async function savetxhash(lasthash) {   //async function to save last tx
        return new Promise((resolve) => {

        resolve(lasthash)

       });
      }

      var lasthash = ""                     //declare empty at first

     //Here you will have your web3.eth.Transfer() or .allEvents() listener code
     //Then below that you will compare saved hash to new one

       console.log('This hash is '+event.transactionHash+'')
       console.log('Last hash was '+lasthash+'')
                      
       if (lasthash.toLowerCase() == event.transactionHash.toLowerCase()) {
           console.log('Found duplicate tx hash, skipping...')
           } else {
           console.log('No duplicate tx hash found, doing something important...')
           }
                      
       lasthash = await savetxhash(event.transactionHash)   //lastly call the function


Ich hatte hier das gleiche Problem mit web3 ^1.3.6.

Laut diesem Problem im web3.js-Repo scheint es ein Problem mit der Bibliothek selbst zu geben

Meine Lösung bestand darin, den Transaktions-Hash jedes Ereignisses zu speichern und diesen zu vergleichen, bevor eine Logik ausgeführt wurde.