NEU: Helius übernimmt Light Protocol
So gehst du mit Blockhash-Fehlern auf Solana um
Blog/Entwicklung

So gehst du mit Blockhash-Fehlern auf Solana um

Developer Experience EngineerOwen Venter auf XOwen Venter auf LinkedIn
7 Min. Lesezeit

Was ist ein Blockhash?

Um zu verstehen, was ein Blockhash ist, musst du zunächst Slots und Blöcke verstehen.

  • Ein Slot ist ein Zeitraum, in dem ein Validator einen Block erzeugen kann 
  • Ein Block ist eine Sammlung von Transaktionen und Metadaten, die ein Validator verarbeitet. Die Metadaten jedes Blocks verknüpfen ihn mit dem vorherigen Block. So entsteht eine Kette.

Slots dauern zwischen 400 und 600 ms. In jedem Slot kann ein Validator einen neuen Block vorschlagen. Wird kein Block erstellt, erhöht sich der Slot und ein anderer Validator versucht, einen neuen Block zu erstellen. Daher ist nicht jedem Slot ein Block zugeordnet. Jeder Block ist jedoch dem Slot zugeordnet, in dem er vorgeschlagen wurde.

Was ist also ein Blockhash? Ein Blockhash ist ein eindeutiger Hashwert aller Ledger-Einträge der Blockchain, die während eines Slots erstellt wurden. Er wird aus der ID des letzten Eintrags im Block berechnet. Jeder erzeugte Block führt zu einem eindeutigen Blockhash. Diese Blockhashes dienen als Zeitstempel.

Welche Commitment-Stufen gibt es bei Solana?

Ein weiteres wichtiges Konzept sind Commitment-Stufen. Sie messen die Bestätigung eines bestimmten Blocks durch das Netzwerk. Es gibt drei Optionen: processed, confirmed und finalized.

Wenn ein Validator einen Block an die Chain übermittelt, befindet er sich im Status processed. Sobald die erforderliche Anzahl an Validatoren (66 % der Validatoren) dafür gestimmt hat, den Block aufzunehmen, wird er der Chain hinzugefügt und die Commitment-Stufe wechselt zu confirmed. Sobald 31 weitere Blöcke auf diesem Block aufgebaut wurden, wechselt die Commitment-Stufe zu finalized.

Warum treten Blockhash-Fehler auf?

Alle Transaktionen enthalten einen aktuellen Blockhash, der als Zeitstempel dient. Eine Transaktion läuft ab, sobald ihr Blockhash nicht mehr als aktuell genug gilt. Validatoren, die Transaktionen verarbeiten, prüfen die „BlockhashQueue“ – eine Liste der letzten 300 Blockhashes. So stellen sie fest, ob der Blockhash der Transaktion aktuell genug ist. Befindet er sich nicht in der Liste, wird die Transaktion abgelehnt. Da Slots normalerweise zwischen 400 und 600 ms dauern, bleibt ein Blockhash 60 bis 90 Sekunden gültig.

Blockhash nicht gefunden (Transaktionssimulation fehlgeschlagen: Blockhash nicht gefunden)

„Blockhash nicht gefunden“-Fehler treten auf, wenn der Blockhash einer Transaktion bei ihrer Verarbeitung durch einen Validator als ungültig gilt. Das kann daran liegen, dass er zu alt oder in einigen Fällen zu neu ist. 

Dieser Fehler tritt meist auf, wenn der Blockhash einer Transaktion nicht in der Warteschlange der letzten 300 Blockhashes enthalten ist, mit denen der Validator ihn vergleicht. Dies führt zum Fehler Blockhash nicht gefunden. Transaktionen können ablaufen, wenn sie nicht innerhalb des erforderlichen Zeitraums erstellt und verarbeitet werden. Das kann passieren, wenn ein Benutzer lange braucht, um eine Transaktion zu signieren. Es kann auch vorkommen, dass eine gültige Transaktion übermittelt, aber nicht in den aktuellen Block aufgenommen wird. Wenn sie später aufgenommen werden könnte, ist der Blockhash der Transaktion bereits zu alt.

Wenn die Transaktion effektiv abgelaufen ist, treten häufig Fehler des Typs „Blockhöhe überschritten“ auf (TransactionExpiredBlock heightExceededError). Um diesen Fehler besser zu verstehen, musst du wissen, was die Blockhöhe bedeutet. Die Blockhöhe bezeichnet die Anzahl der Blöcke unterhalb des aktuellen Blocks. Ist der aktuelle Block Block 1000, beträgt die Blockhöhe 1000. Beim Erstellen einer Transaktion wird die maximale Blockhöhe festgelegt, bis zu der sie gültig ist. Wird bei der Verarbeitung festgestellt, dass die aktuelle Blockhöhe über der maximalen gültigen Blockhöhe der Transaktion liegt, wird der Fehler ausgelöst.

Ein „Blockhash nicht gefunden“-Fehler kann auch auftreten, wenn der Blockhash einer Transaktion neuer ist als der Blockhash, mit dem ihr Ablauf geprüft wird. Das klingt zunächst verwirrend. Hier ist ein Beispiel: Du erstellst eine Transaktion, fügst den Blockhash eines bestimmten Blocks hinzu, etwa Block 1000, und sendest sie sofort an ein RPC. Das RPC ruft möglicherweise den Blockhash des vorherigen Blocks ab, in diesem Fall Block 999. Das kann passieren, weil das RPC eine höhere Commitment-Stufe verwendet oder weil der RPC-Node dem Netzwerk hinterherhinkt. Daher wird der Blockhash der Transaktion nicht gefunden. Diese ungewöhnliche Situation kann in zwei Szenarien auftreten:

1. Nicht übereinstimmende Commitment-Stufen

Beim Erstellen der Transaktion wird die Commitment-Stufe confirmed verwendet. Wenn das RPC ihre Gültigkeit berechnet, verwendet es standardmäßig jedoch finalized.

Dadurch kann der zur Prüfung verwendete Blockhash älter sein als der Blockhash der Transaktion, da finalized-Blöcke 31 Blöcke hinter dem neuesten Block liegen.

Wird die Commitment-Stufe processed verwendet, um den Blockhash einer Transaktion auf einem Minderheits-Fork abzurufen, der später verworfen wird, ist der Blockhash ungültig und wird bei der Verarbeitung nicht gefunden.

2. Nicht übereinstimmende RPCs

Wenn du zwei verschiedene RPCs verwendest, um den Blockhash abzurufen und die Transaktion zu senden, kann eine Verzögerung des sendenden RPC dazu führen, dass der zur Gültigkeitsprüfung verwendete Block älter ist als der Block, mit dem die Transaktion erstellt wurde.

So behebst du Blockhash-Fehler

Mit einigen Schritten kannst du die oben genannten Situationen lösen.

1. Stelle sicher, dass du eine Transaktion mit einem nicht zu alten Blockhash übermittelst:

Verwende beim Abrufen des Blockhashes für eine Transaktion die Commitment-Stufe confirmed. So wird im Vergleich zur Commitment-Stufe finalized ein neuerer Blockhash verwendet.

Für einen etwas aktuelleren Blockhash kannst du auch die Commitment-Stufe processed verwenden. Allerdings werden etwa 5 % der verarbeiteten Blöcke nicht vom Cluster finalisiert. Der Blockhash der Transaktion würde dann zu einem verworfenen Fork gehören und wäre nicht mehr gültig.

2. Stelle sicher, dass der Blockhash einer Transaktion nicht neuer ist als der Blockhash, mit dem ihre Gültigkeit geprüft wird:

Setze preflightCommitment immer auf dieselbe Commitment-Stufe, mit der du den Blockhash der Transaktion abgerufen hast – auch wenn du skipPreflight verwendest. So verhinderst du, dass der Blockhash der Transaktion neuer ist als der Blockhash, mit dem ihre Gültigkeit geprüft wird.

Um beim Senden von Transaktionen mit verzögerten RPC-Nodes umzugehen, solltest du die Transaktionen wiederholt an das RPC senden. Das kannst du in einem festen Intervall tun. Hinkt ein RPC hinterher, holt es schließlich auf und erkennt, dass die Transaktion abgelaufen ist.

Wenn du die Anfrage simulateTransaction verwendest, solltest du den Parameter replaceRecentBlockhash setzen. Dieses Flag weist das RPC an, den Blockhash der simulierten Transaktion durch einen Blockhash zu ersetzen, der für die Simulation immer gültig ist.

3. Wiederhole die Transaktion, solange der Blockhash gültig ist:

Wenn du eine Transaktion erstellst und den neuesten Blockhash abrufst, solltest du lastValidBlockHeight für diesen Blockhash notieren. Anschließend kannst du die Transaktion mit diesem Blockhash wiederholen, bis die aktuelle Blockhöhe die gültige Blockhöhe der Transaktion überschreitet. Mit dem RPC-Aufruf getBlockHeight kannst du fortlaufend prüfen, ob die Transaktion noch gültig ist. Sobald die aktuelle Blockhöhe über der Höhe lastValidBlock der Transaktion liegt, solltest du einen neuen Blockhash abrufen und verwenden.

Ich hoffe, dieser Blogbeitrag hilft dir, Blockhash-Fehler besser zu verstehen und ihre Häufigkeit zu reduzieren. Wenn du weitere Fragen hast, tritt unserer Discord-Community bei oder sende uns eine Direktnachricht auf X.

Weitere Ressourcen:

‍

Helius abonnieren

Bleib bei der Solana-Entwicklung auf dem Laufenden und erhalte Updates, wenn wir neue Beiträge veröffentlichen

Vergrößertes Bild