Gibt es eine Möglichkeit, Transaktionen zu indizieren, damit Filterload-Befehle beantwortet werden können, ohne alle Transaktionen in einem Block zu durchlaufen?

Einige SPV-Clients verwenden den filterloadBefehl, um nur Transaktionen mit Adressen in ihrer Brieftasche zu erhalten. Dazu benötigt der Remote-Knoten lineare Zeit (in Bezug auf die Anzahl der Transaktionen im Block), was suboptimal erscheint.

Könnten wir Transaktionen irgendwie indizieren, damit wir diese Abfragen schneller als mit linearer Komplexität beantworten können? Es scheint möglich, aber ich bin mir nicht sicher, wie ich vorgehen soll, insbesondere in Gegenwart von nTweak.

Antworten (1)

Es gibt eine bekannte, aber ziemlich undokumentierte Methode zur drastischen Verbesserung der SPV-Filterung, die dieses Problem vollständig beseitigt, aber auf Kosten einer Hard Fork-Änderung zu Bitcoin geht.

Herkömmliches BIP37-SPV

Für BIP37 setzt ein Client Bloom-Filter auf seine Peers und lädt nacheinander Transaktionen und Blöcke herunter, wobei er sich darauf verlässt, dass der Remote-Peer alle Daten für diesen Peer durchsucht und beschnittene Blöcke erzeugt, die seinem Filter entsprechen.

Dies ist aus mehreren Gründen unerwünscht:

  • In Bitcoin BIP37 Bloom gefilterte SPV-Kunden haben absolut keine Privatsphäre , selbst wenn unangemessen hohe False-Positive-Raten verwendet werden.

  • Knoten im Netzwerk müssen eine extrem große Datenmenge verarbeiten, um die Ergebnisse für nur einen einzelnen Peer zurückzugeben, und die Arbeit für jeden einzelnen Peer wiederholen, der beim Empfang eines neuen Blocks verbunden ist.

  • BIP37 SPV-Kunden können durch Unterlassung belogen werden.

  • Peers, die eine alte Brieftasche laden oder eine erneut nach Transaktionen durchsuchen, die sie möglicherweise verpasst haben, müssen alle gefilterten Blöcke vollständig herunterladen, wiederum auf Kosten anderer Netzwerk-Peers.

Bloom-Filter-Verpflichtungen

  • Vor dem Mining würde ein Bloom-Filter deterministisch aus allen Elementen des Pubkey-Hash (Adresse) und des Pay-to-Script-Hash (P2SH) im Kandidatenblock konstruiert.

  • Der Hash dieses Bloom-Filters müsste in der Nähe des oberen Rands des Merkle-Baums der Blockvorlagen platziert werden, und der Inhalt davon würde nicht anderweitig in irgendeiner Form in den Block geschrieben werden.

  • Bei der Validierung des Blocks würde dieser Bloom-Filter deterministisch rekonstruiert und verifiziert, um mit dem Hash im Merkle-Baum übereinzustimmen. Wenn der Hash des Filters nicht übereinstimmt, ist der Block ungültig.

  • Vollständig validierende Knoten können den festgeschriebenen Bloom-Filter auf der Festplatte zwischenspeichern oder ihn jederzeit aus den Blockdaten auf der Festplatte nach Bedarf neu erstellen (ein Zeit-/Speicher-Kompromiss).

Der neue Prozess für SPV-Kunden:

  • Laden Sie Block-Header, den vollständig festgeschriebenen Bloom-Filter für jeden Block in der Kette und den kurzen Merkle-Pfad zum Verpflichtungs-Hash des Bloom-Filters herunter. Überprüfen Sie, ob der Header gültig ist, überprüfen Sie den Merkle-Pfad zum Hash, überprüfen Sie, ob der Bloom-Filter mit dem Hash übereinstimmt.

  • Vergleichen Sie den Bloom-Filter lokal auf potenzielle Übereinstimmungen mit den Wallet-Daten des Benutzers (Adressen, P2SH-Skripte). Der Peer kann selbstständig entscheiden, welche Blöcke für ihn interessant sind und welche nicht, ohne die Inhalte tatsächlich herunterladen zu müssen. Ähnlich wie beim normalen Betrieb von Bloom-Filtern in BIP37 können falsch positive Ergebnisse auftreten, jedoch niemals falsch negative.

  • Wenn ein Block gefunden wird, der interessant sein könnte, können sie den gesamten Block herunterladen und verarbeiten, um die gewünschten Transaktionen zu finden.

Dies löst eine Reihe von Problemen mit dem traditionellen Ansatz:

  • Zufällige Remote-Peers erhalten keine Kopien des Bloom-Filters des Benutzers mehr. Sie können diese Informationen möglicherweise aus den Blöcken extrapolieren, die der Client herunterlädt, aber der Client kann viele Versuche unternehmen, dies zu verschleiern, indem er einzelne Blöcke aus verschiedenen Quellen herunterlädt, den Verkehr bekannter uninteressanter Blöcke verdeckt oder sogar einen Nicht-Bitcoin-Netzwerkspeicher verwendet wissen, an welchen Blöcken sie am wahrscheinlichsten interessiert sind.

  • Remote-Peers können nicht mehr durch Unterlassung an einen SPV-Client lügen. Wenn sie den im Block festgeschriebenen Bloom-Filter ändern, stimmt er nicht mehr mit dem Hash im Block überein, und der SPV-Client weiß, dass er getäuscht wurde.

  • SPV-Clients können schnelle Rescans durchführen, ohne dass neue Daten heruntergeladen werden müssen. Indem die Bloom-Filter nach der Überprüfung beibehalten werden, können sie so viele erneute Scans durchführen, ohne mit dem Netzwerk kommunizieren zu müssen. Für volle Storage Nodes bedeutet dies deutlich schnellere Rescans, ohne dass ganze Blöcke geladen werden müssen.

  • Knoten im Netzwerk haben keine Last mehr, die SPV-Clients bedient, außer dem Bereitstellen zusätzlicher Daten, wenn sie angefordert werden. Es ist ihre Wahl, die Filter beim Verifizieren von Blöcken zwischenzuspeichern (dies ist mit fast geringen Kosten verbunden, da sie den Filter sowieso immer erstellen müssten). Dies skaliert deutlich besser als BIP37, da die Daten für alle Peers gleich bleiben und nicht einzeln berechnet werden müssen.

Es ist unklar, ob dies jemals genug Anklang finden würde, um in einem Hard Fork implementiert zu werden, oder wie die optimale Falsch-Positiv-Rate für den festgeschriebenen Bloom-Filter wäre (dies ist eine Entscheidung, die sorgfältig getroffen werden muss, sie kann nur einmal getroffen werden). Es gibt einen unangenehmen Kompromiss zwischen der Größe des Filters und seiner Falsch-Positiv-Rate: Zu grob bedeutet, dass Peers viel zu viele Falsch-Positiv-Blöcke herunterladen, zu fein bedeutet, dass die Filter absolut gigantisch und für jeden unpraktisch sind, um sie auf einen SPV-Client herunterzuladen.

Es ist nicht offensichtlich, wo sich dieser Sweet Spot befindet oder ob er überhaupt existiert.