Könnte event watch() von der letzten Blocknummer (Tail) zum Head wechseln?

Im Allgemeinen gehe ich davon aus, dass Ereignisse von einer kleineren zu einer größeren Blocknummer durchlaufen.

Beispiel:

contractDeployedBlockNumber = 10000
fromBlock: contractDeployedBlockNumber, toBlock: 'latest'

[F] Könnte event watch()von 'latest'Blocknummer bis zur nullten Blocknummer (oder kleineren Blocknummer) traversieren? Dies ist im Grunde eine umgekehrte Traverse-Operation, um das neueste eventEreignis zuerst abzufangen und zu unterbrechen. Dies hilft, das neueste ausgegebene Ereignis so schnell wie möglich abzurufen.


Die Smart Contract-Funktion speichert die Informationen eines registrierten Benutzers und aktualisiert sie mithilfe der registerUser()Funktion.

contract Example {
   mapping(address => uint) userLatestEmittedBlocNum;
   function registerUser(string memory userEmail,
                         string memory name,
                         string memory githubUserName) public
       returns (bool success)
   {
       userLatestEmittedBlocNum[msg.sender] = block.number;
       emit LogUser(msg.sender, userEmail, name, githubUserName);
       return true;
   }

   function getUserLatestEmittedBlocNum(address userAddress) public view
    returns(uint)
  {
      if (userLatestEmittedBlocNum[userAddress] != 0)
          return (userLatestEmittedBlocNum[userAddress]);
   }
   event LogUser(address userAddress, string userEmail, string name, string githubUserName);
 }

Ich kann die Blocknummer speichern, unter der die Informationen des Benutzers aktualisiert userLatestEmittedBlocNum[msg.sender]werden, und das ausgegebene Protokoll direkt von dieser Blocknummer abrufen, aber dies kostet zusätzlichen Speicher und Gasverbrauch.

blockReadFrom = Example.functions. getUserLatestEmittedBlocNum(userAddress).call()
my_filter = Example.eventFilter('LogUser',{'fromBlock':int(blockReadFrom),'toBlock':int(blockReadFrom) + 1})

Als Ergebnis müssen wir das neueste Ereignis für jeden Benutzer abrufen, um die aktuellen Informationen zu erhalten.

Es kann ineffizient sein, von der kleineren Blocknummer zur letzten Blocknummer zu iterieren (die auch die vorherigen aktualisierten Ereignisse erhält), und der Spannenbereich kann sehr groß sein. Wenn wir stattdessen in der Lage wären, von der letzten Blocknummer bis zur kleinen Blocknummer zu scannen und die Iteration zu unterbrechen, wenn wir das Ereignis abfangen, könnte es schneller sein, das zuletzt ausgegebene Protokoll zu finden.

Bei einem Smart Contract werden einige Informationen protokolliert und im Laufe der Zeit aktualisiert, daher latestist das Ereignis gültig. Ich möchte also das neueste Ereignis auf meinem Smart Contract abrufen, ohne mit dem Scannen von der viel kleineren Blocknummer zu beginnen, was zeitaufwändig und ineffizient ist. Beginnen Sie also im Grunde mit der "neuesten" Blocknummer bis zum kleineren Block und unterbrechen Sie diese Iteration, wenn ich das Ereignis erwische. Andernfalls muss ich, egal was passiert, wenn ich mit einer kleineren Blocknummer beginne, bis zur neuesten Blocknummer iterieren.


Ziel :fromBlock: latest, toBlock: 0

blockNum = 0;
var contract = myContract.LogJob({}, { fromBlock: blockNum, toBlock: 'latest' });
var i = 0;
contract.watch(function (error, result) {
    console.log(i++ + ": " + JSON.stringify(result));
});
Sie würden wissen, wann Ihr Vertrag abgebaut wurde. Im Grunde müssen Sie latestalso von zu iterieren mindedBlockNumber. Ich hoffe, ich konnte dir eine Vorstellung geben. Bitte teilen Sie mir mit, wenn ich etwas falsch verstanden habe.
Aber ich kann nicht von der letzten zur kleineren Blocknummer iterieren, es gibt nichts zurück. fromBlock: latest, toBlock: 0@ Rajesh

Antworten (1)

Ich werde es versuchen, weil Prämien. :-)

Technisch gesehen nein, aber Sie könnten einen ähnlichen Effekt erzeugen.

Ich sage „nein“, weil die Blockchain ein wohlgeordneter Satz von Blöcken ist, die jeweils einen wohlgeordneten Satz von Transaktionen enthalten. Im weiteren Sinne ist die Blockchain ein wohlgeordneter Satz von Transaktionen, beginnend mit der ersten Transaktion in oder nach Block 0.

Hier ist der Knaller.

Es soll überprüft werden, da ein Block nach dem Genesis-Block ohne Bezugnahme auf den vorangehenden Block nicht unabhängig verifiziert werden kann. Mit anderen Worten, um zu wissen, dass Sie den authentischen 50. Block betrachten (durch Konsens), müssen Sie Kenntnis von Block 49 haben. Wenn Sie am Ende beginnen, wenden Sie im Allgemeinen entweder die Logik rekursiv bis zurück zu Block 0 an , oder vertrauen Sie auf etwas anderes als Ihre eigene unabhängige Einschätzung.

Außerdem können Sie nie wissen, dass Sie den neuesten Block haben. Das Beste, was Sie jemals wissen können, ist, dass Sie den neuesten Block haben, von dem Sie wissen (und wahrscheinlich ist ein noch neuerer auf dem Weg). Was, wäre das erste auf einer Liste von Ereignissen, beginnend mit dem neuesten zuerst? Es würde nicht sehr lange dauern.

Um etwas Ähnliches wie in Ihrem Anwendungsfall zu erreichen, scheint es zu implizieren, alle bekannten Ereignisse abzuhören und kontinuierlich neue "neueste" Blöcke am Anfang einer Liste einzufügen. Oder (wahrscheinlich effizienter) hängen Sie die neueste an das Ende Ihrer eigenen Liste an und lesen Sie sie dann bei Bedarf rückwärts zurück. Dies wäre wahrscheinlich in Bezug auf ein Offchain-Problem (UI, Cache, etwas anderes ...) - vielleicht "Point-in-Time"-Snapshots oder Live-Updates, wenn neue "neueste" Log-Einträge aufgedeckt werden.

Es ist vollkommen fair, Ihre eigenen Off-Chain-Datenquellen aus Leistungs- und anderen Gründen zu pflegen. Sie können immer noch die Vorteile der Blockchain nutzen, wenn Benutzer/Kunden die Fakten überprüfen können, wenn sie dies wünschen, indem sie die Fakten anhand ihrer eigenen Kopie der Kette bestätigen. Dies ist ungefähr das, was passiert, wenn Sie Online-Block-Explorer und andere Apps verwenden, die mehr Leistung benötigen, als ein typischer Knoten leisten könnte. Sie können so etwas sortieren, wie Sie möchten.

Ich hoffe es hilft.

AKTUALISIEREN

Es gibt ein Muster, um dies effizient zu tun, wenn Sie den Vertrag so gestalten, dass er dies unterstützt. Es verwendet sehr einfache Breadcrumbs:

pragma solidity 0.5.1;

contract ReverseOrderEvents {

    uint lastEventBlock;

    event LogEvent(address sender, uint previousEvent);

    function doSomething() public {
        emit LogEvent(msg.sender, lastEventBlock);
        lastEventBlock = block.number;
    }
}

Wenn Sie dann auf der Clientseite lastEvent != 0zu diesem Block springen und auf Ereignisse von Interesse "lauschen". Dieses Ereignis enthält einen Zeiger auf den Block, der das vorherige Ereignis enthält. Spülen und wiederholen. Wenn du triffst, 0gibt es keine vorherigen Ereignisse.

Die Technik ist einfach, und Sie können je nach Bedarf separate Zeiger für separate Protokolle, separate Benutzer usw. verwenden, damit Clients die wichtigsten aktuellen Informationen schnell finden können.

Auf diese Weise kann ein Client mit dem neuesten beginnen und so weit wie möglich zurückkriechen. Das Muster kann in zustandslosen Designs verwendet werden, in denen sich die Daten im Ereignisprotokoll befinden und möglicherweise nur der neueste Eintrag wichtig ist.

Nur für den Fall, dass es nicht klar ist, watch()geht nicht rückwärts. Um dies zu verwenden, würden Sie nur watch()einen Block (was schnell wäre), finden, was Sie brauchen, und dann watch()den nächsten einzelnen Block von Interesse, indem Sie den Hinweisen in umgekehrter Reihenfolge folgen, die Sie für sich selbst festgelegt haben.

TY. Ich verstehe Ihren Standpunkt, aber ich versuche nicht, Ereignisse zu beobachten. Es muss ein sehr einfacher Algorithmus sein. Ich möchte nur Ereignisse von der letzten Blocknummer auf die kleinere abrufen. Ich kann sie auf meinem lokalen Computer anmelden, aber ich möchte das nicht tun. Warum können wir sie nicht vom kleinsten zum kleineren bringen, da wir sie vom kleineren zum größeren bekommen können. Ich glaube immer noch, dass dies auf der Web3-Seite implementiert werden könnte, was tatsächlich eine nützliche Funktion ist. @Rob Hitchens
Ich glaube, ich habe erklärt, warum es nicht da ist. Wussten Sie, dass Sie die web3Bibliothek selbst erweitern können?
Könnten Sie mich bei der Erweiterung von anleiten web3, könnte ich die Codierung auf ihrem Github durchführen? Meine beste Lösung besteht darin, die bereitgestellten Funktionen blockNumber zu speichern und sie zu aktualisieren, wenn es ein Update gibt, das auf die genaue Blocknummer des aktualisierten Ereignisses verweist. @Rob Hitchens
@RobHitchens Ich denke, ein vollständig clientseitiges Modell würde funktionieren, da Sie die neueste bekannte Blocknummer auf dem Client abrufen und dann programmgesteuert mithilfe dieser Blocknummer die Existenz des Ereignisses überprüfen können, indem Sie getanstelle von watch, zum Abfragen verwenden, und wenn nicht, erhalten Reduzieren Sie die Blocknummer um eins und wiederholen Sie den Vorgang. Dies erhöht den Zeitaufwand, stellt jedoch sicher, dass dem Smart Contract nichts hinzugefügt werden muss. @alper Sie bräuchten entweder auf der Kundenseite Komplikationen oder einen absichtlich strukturierten Vertrag, um dies afaik zu erreichen
Ihre aktualisierte Antwort ist die Lösung, die ich zu meiner Frage erklärt habe ... uint lastEventBlockwird zusätzlichen Speicherplatz verursachen. Ich versuche, eine Lösung zu finden, bei der es keine zusätzliche Speichernutzung im Vertrag gibt. @RobHitchens