BLOG |
Anleitungen
Wiederherstellung von 100.000 Sats mithilfe von Seed- und Status-Backups.
Ein echter einseitiger Austritt aus dem Spark-Netzwerk: die Zahlen, die Misserfolge und die Lehren. Alles, was im Folgenden beschrieben wird, fand im Bitcoin-Mainnet statt und ist öffentlich in der Blockchain nachprüfbar.
Ich habe eine nicht-verwahrende Blink (unter Verwendung von Spark) im Bitcoin-Mainnet zwangsweise geschlossen. Alles, was für den Ausstieg erforderlich war, wurde aus dem Wallet-Seed abgeleitet: die Bereitstellung der Gebühren, die Signierung der Transaktion und der abschließende Abzug. Die einzige zusätzliche Komponente ist ein Wiederherstellungsbündel – ein Snapshot der Ausstiegsdaten der Wallet, der gespeichert wurde, als das Spark-Netzwerk noch erreichbar war. Mit diesem Bündel in der Hand erforderte der Ausstieg selbst keinerlei Zusammenarbeit von irgendjemandem.
Die realistischen Zahlen für eine Wallet mit 100.000 Sat:
„Ohne Freiheitsentzug“ bedeutet, dass man jederzeit gehen kann. Aber die Feuerleiter ist schmal. Hier ist die ganze Geschichte – mit Kosten, Misserfolgen und Lehren.
„Non-custodial“ ist ein Begriff, der sich leicht in Marketingtexte einbauen lässt. Wir wollten jedoch, dass man dies überprüfen kann und nicht einfach nur glauben muss. Also haben wir eine echte Blink genommen, so getan, als wäre das Spark-Netzwerk verschwunden, und jedes wiederherstellbare Satoshi mithilfe von nichts anderem als dem Seed, einem gespeicherten Wiederherstellungsbundle und Open-Source-Tools, die jeder ausführen kann, zurück auf die Bitcoin-Blockchain übertragen. Dieser Beitrag ist der Nachweis dafür.
Eine mobile Spark-Wallet mit 100.000 Sats, verteilt auf 22 „Leaves“.

EinkurzerÜberblick für Leser, die Spark noch nicht kennen: Die Guthaben einer Spark-Wallet befinden sich in einem gemeinsamen On-Chain-Baum, der von einer Gruppe von Betreibern verwaltet wird, und jedes Blatt dieses Baums ist ein eigenständiger Teil des Guthabens der Wallet mit einem eigenen, vorab signierten Pfad zurück zu Bitcoin. Ein einseitiger Ausstieg bedeutet, diesen Pfad – die Ausstiegskette des Blatts aus On-Chain-Transaktionen, die Ebene für Ebene entlang des Baums bestätigt wird – zu übertragen, um das Blatt ohne die Mitwirkung der Betreiber auf Bitcoin zu zwingen.
Eine mobile Spark-Wallet mit 100.000 Sats, verteilt auf 22 Blätter. Spark-Wallets sammeln Blätter durch normale Nutzung an (Zahlungen teilen und teilen den Baum erneut auf), und jedes Blatt verfügt über eine eigene Ausstiegskette: die On-Chain-Transaktionen, die Ebene für Ebene bestätigt werden müssen, um das Blatt ohne Mitwirkung der Betreiber auf Bitcoin zu zwingen. Für diese Wallet bedeutete das 253 Transaktionspakete über die 22 Ketten hinweg. Für 100.000 Sats.
Eine Wiederherstellung allein anhand des Seeds ist nicht möglich, sobald die Spark-Operatoren offline sind: Aktuelle Leaf-Transaktionen lassen sich nicht allein anhand des Seeds ermitteln. Für den Ausstieg ist ein Wiederherstellungsbundle erforderlich – ein JSON-Snapshot der Leaf-Transaktionen der Wallet und ihrer Vorgängotransaktionen –, der aktualisiert werden muss, solange die Operatoren noch online sind:
make refresh-recovery-bundle SEED_FILE=../.spark-seed.txt BUNDLE=../recovery-bundle.json
Erste Lektion aus der Praxis: Unser erstes Bundle war unbemerkt unvollständig. Die Massen von Betreibern query_nodes(include_parents=true) Die API lässt den Stammknoten bei älteren Mainnet-Bäumen weg, sodass jede der 22 Exit-Chains oben eine Lücke aufwies und die Erstellung des Offline-Pakets mit folgendem Fehler fehlschlug: Die Exit-Kette ist unvollständig. Das erneute Abrufen fehlender Vorfahren anhand der Knoten-ID (wodurch das Überspringen der Wurzel umgangen wird) hat das Problem behoben – der Exporter führt dies nun automatisch durch und weigert sich, ein Bundle mit offenen Ketten zu schreiben.
Überprüfen Sie die Vorläuferketten Ihres Bundles, bevor Sie sie benötigen; ein unvollständiges Bundle, das erst während eines Ausfalls entdeckt wird, lässt sich nicht mehr wiederherstellen.
Ausgangstransaktionen werden gebührenfrei vorab signiert und die Gebühren werden über kurzlebige CPFP-Anker bezahlt; daher benötigt der Ausgang ein unabhängiges L1-Bitcoin-UTXO, um Gebührenerhöhungen zu finanzieren. Das Tool leitet eine spezielle Finanzierungsadresse aus dem Wallet-Seed selbst ab (Pfad m/8797556'/<account>/0: Nur der Zweck-Index ist gehärtet, der Konto- und der Adress-Index hingegen nicht; daher kann eine „Watch-Only“-Wallet die Einzahlungsadresse aus einem XPUB ableiten und überwachen, ohne dass ein privater Schlüssel erforderlich ist):
make cpfp-address SEED_FILE=../.spark-seed.txt BUNDLE=../recovery-bundle.json FEE_RATE=1
Bei 1 sat/vB waren dafür 78.573 Sats erforderlich, um alle 22 Zweige zu verlassen. Fast 79 % des Wallet-Guthabens gingen als Gebühren drauf. Wir haben den Betrag 3ab20a4c…7262 eingezahlt, bevor wir die Berechnung pro Zweig durchgeführt haben. Mehr dazu weiter unten.
Beim ersten Versuch wurden alle 253 Pakete nacheinander über den POST-Endpunkt /txs/package von Esplora gepackt, signiert und übermittelt. Das erste Paket wurde bestätigt (Eltern-ID 16895bc8…9619, CPFP-Kind-ID 384cdc6d…3b37). Die übrigen 252 wurden abgelehnt:
"error": "TRUC-Verstoß, Transaktion 16895bc8… würde das Limit für die Anzahl der Nachkommen überschreiten"
"error": "bad-txns-inputs-missingorspent"
Spark-Exit-Transaktionen sind vom Typ v3, auch TRUC (Topologically Restricted Until Confirmation, BIP 431) genannt. Die Mempool-Richtlinie begrenzt einen v3-Cluster auf einen unbestätigten übergeordneten Block plus einen untergeordneten Block. Dadurch lassen sich die vorab signierten, gebührenfreien Exit-Transaktionen sicher durch Gebührenerhöhungen in den Mempool bringen, und es bedeutet auch, dass jede Ebene einer Exit-Kette bestätigt werden muss, bevor die nächste Ebene in den Mempool gelangen kann. Eine Kette mit 15 Paketen benötigt mindestens 15 Blöcke, unabhängig davon, wie sie eingereicht wird. Jedes Tool, das Pakete direkt nacheinander sendet, lässt alles nach dem ersten Paket pro Kette zurückbleiben.
Bevor wir die Schleife automatisiert haben, haben wir jedes Blatt bewertet: die CPFP-Gebühren für die jeweilige Kette zuzüglich des abschließenden Sweeps von ca. 111 vB, gemessen am Wert des Blattes. Das Ergebnis für diese echte Wallet bei 1 sat/vB:
Vier Blätter (32.768 + 32.768 + 16.384 + 8.192 Sats) machten 90 % des Guthabens aus. Die übrigen 18 – Restbeträge aus routinemäßigen Wallet-Aktivitäten, von denen einige nur 1 Sat betrugen – hätten jeweils 2.100–4.600 Sats gekostet, um sie abzuheben: Die Abhebung aller Beträge hätte ~77,5k Sats an Gebühren gekostet, um 100k zurückzugewinnen. Das Tool berechnet dies nun pro Blatt und überspringt unwirtschaftliche Blätter standardmäßig. (INCLUDE_UNECONOMICAL=1 hebt dies auf; die wirtschaftliche Berechnung wurde anhand genau dieses Bündels regressionsgetestet und an den Regtest angepasst).
Verfolgung jedes einzelnen Sats der 100.000-Sat-Wallet über den wirtschaftlichen Ausstieg bei 1 Sat/vB. Dabei sind zwei Geldbeträge im Spiel: das Wallet-Guthaben selbst und die 9.388 Sats an Gebühren, die den wirtschaftlichen Ausstieg finanzieren und tatsächlich von der Finanzierungsadresse verbraucht wurden.
Die 100.000 Sats in der Wallet:
Spark-Exit- und Rückerstattungstransaktionen werden vorab ohne Gebühr signiert (die Gebühren richten sich nach den CPFP-Ankern), sodass jede Rückerstattungsausgabe den vollen Leaf-Wert enthält; der einzige Abzug vom Wallet-Guthaben selbst ist die abschließende Sweep-Gebühr.
Die 9.388 Sats aus der Gebührenfinanzierung wurden entnommen aus:
Fazit: 89.668 von 100.000 Sats (~90 %) erreichen das Ziel. Die Gesamtkosten für den Ausstieg betragen ~18.700 Sats – 9.888 gehen als „Dust“ verloren, 8.388 entfallen auf CPFP-Gebühren, 444 auf Sweep-Gebühren – zuzüglich der On-Chain-Gebühr für die Transaktion, mit der die CPFP-Adresse ursprünglich aufgefüllt wurde. Bei höheren Gebührensätzen skalieren alle Werte nach oben, und mehr „Leaves“ fallen unter die wirtschaftliche Schwelle; bei 10 sat/vB würde diese Wallet zwei weitere „Leaves“ aufgeben und für die restlichen das Zehnfache an Gebühren zahlen.
Der überarbeitete Ablauf besteht aus einem einzigen Befehl:
make recover SEED_FILE=../.spark-seed.txt BUNDLE=../recovery-bundle.json NETWORK=mainnet FEE_RATE=1
In jeder Runde werden Pakete anhand des aktuellen Kettenzustands neu erstellt, der CPFP-Bump mit dem Seed signiert, ein Paket pro Leaf-Chain übermittelt, auf die Bestätigung gewartet und der Vorgang wiederholt. Bereits bestätigte Transaktionen werden bei der Neuerstellung übersprungen, sodass die Schleife zustandslos ist: Ratenbeschränkungen, Abstürze und Neustarts haben keine Auswirkungen – nach einem Neustart wird der Vorgang einfach fortgesetzt. Bei Esplora-Störungen wird mit exponentiellem Backoff ein erneuter Versuch unternommen, anstatt eine stundenlange Wartezeit abzubrechen.
Zwei strukturelle Details sind von Bedeutung:
Wir haben diese Wiederherstellung sequenziell durchgeführt (Standardeinstellung). Bei FAN_OUT=1 hätte die Schleife zunächst eine zusätzliche Transaktion mit vier Ausgängen gesendet – die 9.388 Sats der Mittel würden auf je ein UTXO pro wirtschaftlichem Blatt aufgeteilt, wobei jedes UTXO so bemessen wäre, dass es die verbleibenden CPFP-Gebühren dieses Blattes sowie einen Puffer von 1.000 Sats abdeckt, wobei der letzte Ausgang den Rest aufnimmt. Eine P2WPKH-Transaktion mit 1 Input und 4 Outputs beträgt ~203 vB, also ~203 Sats bei 1 Sat/vB.
Von da an verlaufen vier Ketten parallel – eine pro Blatt. Jede Blattkette bildet einen eigenen TRUC-Cluster, sodass alle vier Pakete einer Runde unabhängig voneinander sind und im selben Block bestätigt werden können. Jedes der vier Blätter dieser Wallet wies vor der Rückerstattung eine Kette mit etwa sechs Paketen auf:
Etwa eine 3,5-fache Steigerung der Realisierungszeit für ~203 Sats, und nach Ablauf der Rückerstattungsfrist wiederholt sich das gleiche Muster: Die vier Rückerstattungspakete werden in einem Block mit UTXOs pro Blatt gesendet, anstatt in vier aufeinanderfolgenden Blöcken. Der Gewinn skaliert mit der Blattanzahl (Summe der Kettentiefen im Vergleich zur tiefsten einzelnen Kette), sodass eine Wallet mit Dutzenden wirtschaftlicher Blätter immer auf mehrere Blöcke verteilt werden sollte; bei einer Handvoll Blättern ist die sequenzielle Vorgehensweise einfacher und war hier schnell genug.
Nachdem die Schleife beendet ist, wartet die Rückerstattung für jedes „economical leaf“ ab, bis die CSV-Sperrfrist abgelaufen ist. Eine erneute Ausführung derselben wiederherstellen Nach Ablauf der Frist werden die Rückerstattungen bekannt gegeben; sobald diese bestätigt sind, einen Durchlauf durchführen erstellt und signiert Taproot-Key-Path-Ausgaben mit einem Eingang von den Rückerstattungs-Outputs an beliebige Zieladressen und sendet diese als gewöhnliche Transaktionen. Zum Zeitpunkt der Erstellung dieses Artikels erfolgen die vier wirtschaftlichen Ausgänge dieser Wallet über ihre jeweiligen Blockchains und warten auf die Fälligkeit der Rückerstattung.
Da lohnt es sich, genau zu sein, denn hier eilen die Marketingfloskeln den Fakten meist voraus:
Nicht vertrauenslos, und wir behaupten auch nicht, dass es das ist. Auf einer Skala betrachtet: schwächer als ein Lightning , der von Natur aus seinen eigenen Kanalstatus verwaltet, aber deutlich sicherer als ein Verwahrer, der sowohl Ihre Schlüssel als auch Ihre Daten verwahrt und dessen Zurückhaltung bis zum Einfrieren der Auszahlungen wie ein normaler Service erscheint.
TRUC-Verstoß und fehlende Eingaben wie normale Sequenzierungssignale und behandeln Sie eine Paketcharge niemals nach dem Prinzip „Fire-and-Forget“.All das wurde bisher manuell mit Open-Source-Tools durchgeführt. Das ist zwar der richtige Ort, um dies unter Beweis zu stellen, aber nicht der, an dem sich die meisten Nutzer aufhalten. Unser Ziel ist es, einen Ausstiegspfad zu schaffen, auf den sich ein Nutzer niemals vorbereiten muss.
Konkret bedeutet dies: Die Blink aktualisiert das Wiederherstellungs-Bundle nach jeder Zustandsänderung – also nach jeder Transaktion – automatisch und speichert es dauerhaft im lokalen Gerätespeicher sowie, sofern der Nutzer dies konfiguriert hat, verschlüsselt in seinem eigenen Cloud-Speicher. Das Bundle beinhaltet keine Ausgabebefugnis; es handelt sich um Ausstiegsdaten, nicht um Schlüssel, sodass die automatische Sicherung das Ausstiegsfenster erweitert, ohne die Angriffsfläche zu vergrößern. Der Seed bleibt das einzige Geheimnis, das es zu schützen gilt – genau wie heute.
Der springende Punkt ist, dass „man jederzeit aussteigen kann“ keine Vorbereitungen erfordern sollte. Unabhängig davon, wie die letzte Transaktion aussah, sind die Daten, die erforderlich sind, um diese Gelder zurück auf Bitcoin zu übertragen, bereits gespeichert. Sollte Spark nicht erreichbar sein, wird der Ausstieg über die Blink oder über das Open-Source-Tool anhand desselben Bundles durchgeführt – es entsteht kein hektisches Hin und Her, um den Status von Betreibern abzurufen, die möglicherweise bereits nicht mehr erreichbar sind.
Damit wird die Lücke geschlossen, die diese Fallstudie aufgezeigt hat: Die Tools können zwar beendet werden, jedoch nur im Vergleich zu einem vollständigen, aktuellen Bundle. Die Automatisierung der Aktualisierung, sodass diese stets auf dem neuesten Stand ist und stets gesichert wird, verwandelt eine Notausstiegsmöglichkeit, die man erst aufbauen muss, in eine, die einfach schon da ist.
Allehier verwendeten Tools sind Open Source, und die technische Fallstudie mit allen Befehlen und Transaktions-IDs befindet sich direkt neben dem Code:
Probier es doch mal mit dem Bundle deiner eigenen Wallet aus, bevor du es brauchst. Darum geht es ja.

Empfangen und senden Sie jetzt Bitcoin