Bellatrix-Upgrade: wie geth einen Sync-Fehler produzierte (+Fix)
Das Bellatrix-Upgrade läutete den Merge ein. Davor sorgte aber ein Bug in geth für Probleme, die sich nur mit einem neuen Sync beheben ließen.
Das Bellatrix-Upgrade läutet den Merge ein
Etwas mehr als eine Woche noch, dann ist es tatsächlich so weit: der lang erwartete Merge des Ethereum-Netzwerks und damit der endgültige Umstieg auf Proof of Stake soll über die Bühne gehen. Die Vorbereitungen darauf laufen seit Jahren. Der finale Vorbereitungsschritt für den Merge war das sogenannte Bellatrix-Upgrade, das pünktlich am 6. September 2022 um 13:34 Uhr mit Epoch 144896 als Fork eingespielt wurde. Damit startet eine sogenannte Difficulty Bomb. Abhängig von der Mining-Hashrate im verbliebenen Proof of Work-Netzwerk steigt die Difficulty nun inkrementell an, bis schließlich eine Difficulty von 58.750.000.000.000.000.000.000 erreicht wird. Dieser Wert wird auch Terminal Total Difficulty (TTD) genannt und löst das Paris-Upgrade auf dem Execution-Layer aus. Damit ist Mining dann Geschichte – und zwar zwischen dem 10. und 20. September, abhängig von der verbliebenen Hashrate im Netzwerk. Aktuellen Berechnungen zufolge wäre es derzeit zwischen dem 14. und 15. September soweit.
Ein integraler Bestandteil des Merges ist der Software-Stack auf den Validator Nodes. Alle großen Anbieter haben bereits Updates rausgebracht, um ihre Software „Merge-Ready“ zu machen. Aktuell sind allerdings erst 74,5% der im Netzwerk aktiven Nodes auf dem aktuellen Stand und damit bereit für den Merge. Die immer wieder propagierte Devise lautete daher „updatet eure Clients!“ – und das am besten noch vor dem Bellatrix-Upgrade.
Wenn geth einfach nicht mehr synchronisiert
Entsprechend bereitete auch ich meinen Staker auf den Merge vor und updatete brav die von mir eingesetzten Clients Lighthouse und geth samt eth-docker-Unterbau. Am Abend des 5. Septembers, gut 13 Stunden vor dem Bellatrix-Upgrade, lag ich bereits im Bett, als mich plötzlich leichte Panik überkam. Habe ich auch alles richtig gemacht? Ist wirklich die richtige geth-Version installiert? Hintergrund dazu: kurz zuvor gab es einen geth-Hotfix, da die Version 1.10.22 einen kritischen Bug enthielt. Das Zeitfenster, in dem 1.10.22 ausgerollt wurde, war zwar kurz, aber dennoch bestand diese Möglichkeit. Also stand ich wieder auf und verband mich mit meinem Staker. Der erste Blick in die Logs war beruhigend und seltsam zugleich: ich hatte erst nach dem Hotfix direkt auf geth 1.10.23 geupdatet, entsprechend sollte es keine Fehler geben. Dennoch warf die geth-Konsole im Sekundenbruchteil-Takt Fehler aus:
execution_1 | ERROR[09-05|23:36:28.559] Request tracker exceeded allowance pending=100,000 peer=1e0450adf74cdbe04fb8ada9c831b0dbd6477eae7cbaa31a3bf7db316c3c9bfc protocol=eth version=67 code=3
execution_1 | WARN [09-05|23:36:28.559] Synchronisation failed, retrying err="shutting down"
Dazu konnte sich geth mit keinem einzigen anderen Peer mehr verbinden. Was mir ebenfalls auffiel: die CPU-Auslastung meines Intel Core i5-11400 war seit gut einer Stunde bei bis zu 75%, während normalerweise gut 7% Last anlagen. Als erste Maßnahme startete ich den kompletten Stack in eth-docker neu. Parallel stellte ich den Fehler auf den ethstaker-Discord-Server. Ich konnte doch nicht der einzige mit diesem Problem sein. Schnell meldete sich auch ein anderer Staker mit exakt dem gleichen Fehler.
Nur ein Re-Sync konnte das Problem lösen
Wider Erwarten brachte der Neustart des Stacks nichts. Wie sehr geth hing machte mir erstmals das Stoppen des Services bewusst – dieser Schritt alleine dauerte über drei Minuten. Nach dem Neustart kam dann ein anderes Fehlerbild zum Vorschein. Scheinbar lagen irgendwo in meiner Datenbank fehlerhafte Daten. Der lokal gespeicherte Merkle-Tree passte nicht mit dem anderer Peers zusammen. geth lehnte so laufend die Verbindung mit anderen Peers ab und konnte sich so nicht mehr synchronisieren. Auch Lighthouse merkte in Warnungen bereits an, dass das gesamte Node nicht mehr „Merge Ready“ sei, da der Execution Client nicht gesynct ist. So blieben eigentlich nur zwei Möglichkeiten, um das Problem wieder zu lösen: entweder geth bzw. einen anderen Execution Client komplett neu installieren, oder die Datenbank löschen und neu synchronisieren. Da ein voller Sync gut 600 Gigabyte an Daten sind, war ich mir nicht mehr sicher, ob ein kompletter Re-Sync von 2:32 Uhr an bis zum Bellatrix Upgrade gut 11 Stunden später wohl klappen würde.
Zu diesem Zeitpunkt beschlich mich dann auch das Gefühl, dass dieser Fehler doch mit der fehlerhaften geth 1.10.22-Version zu tun haben könnte. Auf der Github-Release-Seite war nämlich ebenfalls die Rede davon, dass eventuell ein Zurücksetzen der Datenbank und ein kompletter Re-Sync die Lösung sein könnten.
Der Fix: so löscht man die geth-Datenbank
Grundsätzlich sieht geth das Löschen der Datenbank als eigene Funktion vor. Wer geth also einfach separat auf einem Staker installiert hat, kann in der geth-Konsole den Befehl geth removedb
verwenden und wird durch eine kleine Anleitung geführt. Hier lässt sich auch auswählen, ob die Ancient-Blöcke behalten werden sollen. Das geth-Team empfiehlt dies in ihrer Anleitung, damit der Re-Sync nicht so lange dauert. Anschließend kann man geth neu starten, woraufhin der Re-Sync samt ungefährer Zeitangabe startet.
eth-docker ist eigen…
Da ich allerdings eth-docker verwende, konnte ich nicht ohne weiteres auf die geth-Konsole zugreifen. Um zwei Uhr früh war auch der sonst recht belebte ethstaker-Discord ziemlich ruhig, weshalb mir niemand sagen konnte, wie ich vielleicht doch auf die geth-Konsole komme. Glücklicherweise lässt sich die Datenbank aber auch manuell löschen. Bei gestopptem Dienst muss dafür lediglich der ordner chaindata
gelöscht werden. Dazu muss man in das Docker-Volume, auf dem die Daten pro Docker-Container gespeichert sind. Wie das Volume heißt, lässt sich mit dem Befehl docker volume ls
herausfinden:
Die Docker-Volumes liegen unter folgendem Pfad – und dort findet sich auch der Ordner chaindata:
/var/lib/docker/volumes/eth-docker_geth-eth1-data/_data/geth
Bereits zum Anschauen des Ordners braucht man allerdings Root-Rechte, welche man durch sudo su
erhält. Diesen Ordner kann man nun entweder vollständig löschen, was einen kompletten Re-Sync bewirken würde. Alle Blockchain-Daten waren bei mir gesammelt aber schon 649 Gigabyte groß. Im Ordner chaindata
befindet sich neben zig Dateien aber auch der Ordner ancient
. Dieser war bereits stolze 361 Gigabyte groß und konnte so eine klare Ersparnis bei den Daten bewirken. Da ich mit der Linux-Shell nicht sehr geübt bin, bedurfte es einiger umständlicher Commands, um alle Inhalte abseits des Ordners zu löschen. Der simple Befehl rm chaindata/*
funktionierte nämlich nicht – der erstellte Befehl wäre durch die vielen einzelnen Dateien viel zu lang. Da ich den Ordner ancient
auf keinen Fall verlieren wollte, verschob ich ihn kurzerhand mit folgendem Befehl aus chaindata
in das Verzeichnis darüber:
mv /var/lib/docker/volumes/eth-docker_geth-eth1-data/_data/geth/chaindata/ancient /var/lib/docker/volumes/eth-docker_geth-eth1-data/_data/geth
Mit dem Befehl
find . -type f -delete
konnte ich schließlich alle verbliebenen Dateien im Verzeichnis chaindata
löschen. Anschließend verschob ich das Verzeichnis ancient
mit dem gleichen, passend abgeänderten Befehl wieder in chaindata
:
mv /var/lib/docker/volumes/eth-docker_geth-eth1-data/_data/geth/ancient /var/lib/docker/volumes/eth-docker_geth-eth1-data/_data/geth/chaindata
Die Datenbank ist damit weg. Beim Neustart von geth begann der Sync-Prozess also wieder von vorne. geth initialisierte dabei aber zuerst die Block-Daten in ancient
, was mir gut 360 Gigabyte an Daten sparte, die nicht neu synchronisiert werden mussten.
Alles paletti vor dem Bellatrix-Upgrade
Um gut 3:00 Uhr begann der Sync also von vorne. Ob sich 300 Gigabyte Daten wohl in 10 Stunden über das Peer to Peer-Netzwerk ausgehen? Tatsächlich klappte der Re-Sync von geth noch vor dem geplanten Bellatrix-Upgrade um 13:34 Uhr. Bereits um ca. 11 Uhr war geth wieder voll funktionsfähig. Einen Block musste das währenddessen laufende Validator Node zum Glück nicht produzieren, weshalb die Attestation wie gewohnt weiterlief. Dennoch war es ein gutes Gefühl, als wieder beide Programme reibungslos ihren Dienst verrichteten und dem Bellatrix-Upgrade nichts mehr im Wege stand.
Pünktlich war es dann auch soweit: um 13:34 Uhr kam der neue Fork, den Lighthouse auch direkt einspielte. Sowohl geth als Execution Client als auch Lighthouse als Consensus Client liefen reibungslos weiter, als wäre nichts gewesen. Danach entspannten sich meine Nerven nun vollends – die nächtliche Fehlersuche hat sich ausgezahlt. Tatsächlich wäre auch ein nicht gesyncter Execution Client kein großes Problem gewesen – solange die Software-Version stimmt, lässt sich auch das Bellatrix-Upgrade im Nachhinein synchronisieren.
Fazit: warum Client Diversity so wichtig ist
Am meisten verwunderte mich während des ganzen Vorgangs, dass ich und ein weiterer ethstaker-User quasi die einzigen waren, die dieses Problem hatten. Im Laufe des Vormittags kamen noch einige hinzu, die das gleiche Problem hatten. Waren wir paar also ein Ausnahmefall und hatten einfach Pech? Fakt ist, dass ein solcher plötzlich auftretender Bug in geth den ganzen Merge gefährden hätte können. geth ist der mit Abstand am weitesten verbreitete Exeuction Client. Über 80% aller Nodes verwenden geth. Viele nicht synchronisierte Execution Clients hätten den ganzen Consensus Layer schlagartig in den Non-Finality-Status zwingen können. Die Lösung hierfür lautet Client Diversity. Je gleichmäßiger die einzelnen Nodes auf unterschiedliche Software verteilt sind, umso unwahrscheinlicher ist, dass ein Bug gleich den gesamten Consensus Layer lahmlegt oder einen Inactivity Leak auslöst.
Auch deshalb überlege ich, auf einen anderen Execution Client wie Besu oder Nethermind umzusteigen. Client Diversity ist nicht optional, sondern wichtig – jede:r sollte seinen Beitrag dazu leisten.