Tieferer Einblick in das L2-übergreifende Lesen für Wallets und andere Anwendungsfälle

Erweitert2/29/2024, 5:22:58 AM
In diesem Artikel geht Vitalik direkt auf einen spezifischen technischen Aspekt eines Teilproblems ein: wie man leichter von L2 nach L1, von L1 nach L2 oder von einem L2 zu einem anderen L2 lesen kann. Die Lösung dieses Problems ist entscheidend für das Erreichen einer Asset-/Schlüsseltrennungsarchitektur, aber es gibt auch wertvolle Anwendungsfälle in anderen Bereichen, insbesondere die Optimierung zuverlässiger L2-übergreifender Aufrufe, einschließlich Anwendungsfällen wie dem Verschieben von Assets zwischen L1 und L2.

Besonderer Dank geht an Yoav Weiss, Dan Finlay, Martin Koppelmann und die Teams von Arbitrum, Optimism, Polygon, Scroll und SoulWallet für das Feedback und die Bewertung.

In diesem Beitrag über die drei Übergänge habe ich einige Hauptgründe skizziert, warum es wertvoll ist, explizit über L1 + Cross-L2-Unterstützung, Wallet-Sicherheit und Datenschutz als notwendige Grundfunktionen des Ökosystem-Stacks nachzudenken, anstatt jedes dieser Dinge als Addons zu erstellen, die von einzelnen Wallets separat gestaltet werden können.

Dieser Beitrag konzentriert sich direkt auf die technischen Aspekte eines bestimmten Teilproblems: Wie kann man es einfacher machen, L1 von L2, L2 von L1 oder L2 von einem anderen L2 zu lesen? Die Lösung dieses Problems ist entscheidend für die Implementierung einer Asset-/Keystore-Trennungsarchitektur, hat aber auch wertvolle Anwendungsfälle in anderen Bereichen, insbesondere die Optimierung zuverlässiger L2-übergreifender Aufrufe, einschließlich Anwendungsfällen wie dem Verschieben von Assets zwischen L1 und L2.

Empfohlene Pre-Reads

Inhaltsverzeichnis

Was ist das Ziel?

Sobald L2s mehr zum Mainstream werden, werden die Benutzer über Assets in mehreren L2s und möglicherweise auch über L1 verfügen. Sobald Smart-Contract-Wallets (Multisig, Social Recovery oder andere) zum Mainstream werden, werden sich die Schlüssel, die für den Zugriff auf ein Konto benötigt werden, im Laufe der Zeit ändern, und alte Schlüssel müssten nicht mehr gültig sein. Sobald beides geschieht, muss ein Benutzer eine Möglichkeit haben, die Schlüssel zu ändern, die für den Zugriff auf viele Konten an vielen verschiedenen Orten berechtigt sind, ohne eine extrem hohe Anzahl von Transaktionen durchzuführen.

Insbesondere brauchen wir eine Möglichkeit, mit kontrafaktischen Adressen umzugehen: Adressen, die noch in keiner Weise on-chain "registriert" wurden, die aber dennoch Gelder empfangen und sicher aufbewahren müssen. Wir alle sind auf kontrafaktische Adressen angewiesen: Wenn Sie Ethereum zum ersten Mal verwenden, können Sie eine ETH-Adresse generieren, mit der jemand Sie bezahlen kann, ohne die Adresse auf der Chain zu "registrieren" (was die Zahlung von Txfees erfordern würde und somit bereits einige ETH halten würde).

Bei EOAs beginnen alle Adressen als kontrafaktische Adressen. Mit Smart-Contract-Wallets sind kontrafaktische Adressen immer noch möglich, vor allem dank CREATE2, die es Ihnen ermöglicht, eine ETH-Adresse zu haben, die nur von einem Smart Contract gefüllt werden kann, dessen Code mit einem bestimmten Hash übereinstimmt.

EIP-1014 (CREATE2) Adressberechnungsalgorithmus.

Smart-Contract-Wallets bringen jedoch eine neue Herausforderung mit sich: die Möglichkeit, Zugangsschlüssel zu ändern. Die Adresse, bei der es sich um einen Hash des Initcodes handelt, kann nur den anfänglichen Verifizierungsschlüssel des Wallets enthalten. Der aktuelle Verifizierungsschlüssel wird im Speicher der Wallet gespeichert, aber dieser Speicherdatensatz wird nicht auf magische Weise an andere L2s weitergegeben.

Wenn ein Benutzer viele Adressen auf vielen L2s hat, einschließlich Adressen, die (weil sie kontrafaktisch sind) der L2, auf der er sich befindet, nicht kennt, dann scheint es nur eine Möglichkeit zu geben, Benutzern das Ändern ihrer Schlüssel zu ermöglichen: Asset-/Keystore-Trennungsarchitektur. Jeder Benutzer hat (i) einen "Keystore-Vertrag" (auf L1 oder auf einem bestimmten L2), der den Verifizierungsschlüssel für alle Wallets zusammen mit den Regeln für die Änderung des Schlüssels speichert, und (ii) "Wallet-Verträge" auf L1 und vielen L2s, die Cross-Chain lesen, um den Verifizierungsschlüssel zu erhalten.

Es gibt zwei Möglichkeiten, dies zu implementieren:

  • Light-Version (nur zum Aktualisieren von Schlüsseln): Jede Wallet speichert den Verifizierungsschlüssel lokal und enthält eine Funktion, die aufgerufen werden kann, um einen Cross-Chain-Nachweis des aktuellen Zustands des Schlüsselspeichers zu überprüfen und den lokal gespeicherten Verifizierungsschlüssel entsprechend zu aktualisieren. Wenn ein Wallet zum ersten Mal auf einem bestimmten L2 verwendet wird, ist der Aufruf dieser Funktion zum Abrufen des aktuellen Verifizierungsschlüssels aus dem Keystore obligatorisch.
    • Vorteil: Verwendet Cross-Chain-Proofs sparsam, daher ist es in Ordnung, wenn Cross-Chain-Proofs teuer sind. Alle Gelder können nur mit den aktuellen Schlüsseln ausgegeben werden, so dass es immer noch sicher ist.
    • Nachteil: Um den Verifizierungsschlüssel zu ändern, müssen Sie sowohl im Keystore als auch in jeder bereits initialisierten Wallet (wenn auch nicht kontrafaktische) eine Änderung des On-Chain-Schlüssels vornehmen. Das könnte viel Gas kosten.
  • Heavy-Version (Prüfung für jeden TX): Für jede Transaktion ist ein Cross-Chain-Proof erforderlich, der den Schlüssel anzeigt, der sich derzeit im Keystore befindet.
    • Der Vorteil ist, dass die systemische Komplexität geringer ist und die Aktualisierung des Keystores kostengünstig ist.
    • Nachteil: teuer pro tx, erfordert also viel mehr Engineering, um Cross-Chain-Proofs akzeptabel billig zu machen. Auch nicht ohne weiteres kompatibel mit ERC-4337, das derzeit das vertragsübergreifende Lesen von veränderlichen Objekten während der Validierung nicht unterstützt.

Wie sieht ein Cross-Chain-Proof aus?

Um die volle Komplexität zu zeigen, untersuchen wir den schwierigsten Fall: Wenn sich der Keystore auf einem L2 und die Wallet auf einem anderen L2 befindet. Wenn sich entweder der Keystore oder die Wallet auf L1 befindet, wird nur die Hälfte dieses Designs benötigt.

Nehmen wir an, dass sich der Keystore auf Linea und die Wallet auf Kakarot befindet. Ein vollständiger Nachweis der Schlüssel zum Wallet besteht aus:

  • Ein Beweis für die aktuelle Linea-Zustandswurzel angesichts der aktuellen Ethereum-Zustandswurzel, die Kakarot kennt
  • Ein Beweis für die aktuellen Schlüssel im Keystore unter Angabe des aktuellen Linea-Zustandsstamms

Hier gibt es zwei primäre knifflige Implementierungsfragen:

  1. Welche Art von Beweisen verwenden wir? (Sind es Merkle-Beweise? etwas anderes?)
  2. Wie lernt die L2 überhaupt die aktuelle L1 (Ethereum)-Zustandswurzel (oder, wie wir sehen werden, möglicherweise den vollständigen L1-Zustand)? Und alternativ, wie lernt der L1 die L2-Zustandswurzel?
    • Wie lange sind in beiden Fällen die Verzögerungen zwischen etwas, das auf der einen Seite passiert, und dem, was auf der anderen Seite beweisbar ist?

Welche Arten von Nachweisschemata können wir verwenden?

Es gibt fünf Hauptoptionen:

  • Merkle-Proofs
  • Universell einsetzbare ZK-SNARKs
  • Spezielle Nachweise (z. mit KZG)
  • Verkle-Proofs, die sowohl in Bezug auf den Infrastruktur-Workload als auch auf die Kosten irgendwo zwischen KZG und ZK-SNARKs liegen.
  • Keine Beweise und verlassen Sie sich auf die direkte Zustandslesung

In Bezug auf den Infrastrukturaufwand und die Kosten für die Nutzer ordne ich sie grob wie folgt ein:

"Aggregation" bezieht sich auf die Idee, alle von Benutzern innerhalb jedes Blocks gelieferten Beweise zu einem großen Meta-Beweis zu aggregieren, der alle kombiniert. Dies ist für SNARKs und für KZG möglich, aber nicht für Merkle-Zweige (Sie können Merkle-Zweige ein wenig kombinieren, aber es spart Ihnen nur log(txs pro Block) / log (Gesamtzahl der Keystores), vielleicht 15-30% in der Praxis, also ist es die Kosten wahrscheinlich nicht wert).

Die Aggregation lohnt sich erst, wenn das Schema eine beträchtliche Anzahl von Benutzern hat, daher ist es realistischerweise in Ordnung, wenn eine Implementierung der Version 1 die Aggregation weglässt und für Version 2 implementiert.

Wie würden Merkle-Proofs funktionieren?

Das ist einfach: Folgen Sie direkt dem Diagramm im vorherigen Abschnitt . Genauer gesagt würde jeder "Beweis" (unter der Annahme des maximalen Schwierigkeitsfalls des Beweises eines L2 in ein anderes L2) enthalten:

  • Ein Merkle-Zweig, der die State-Root des Keystore-haltenden L2 beweist, wenn man die neueste State-Root von Ethereum angibt, die L2 kennt. Der Zustandsstamm des Keystore-Halters L2 wird in einem bekannten Speicherslot einer bekannten Adresse gespeichert (der Vertrag auf L1 stellt L2 dar), sodass der Pfad durch die Struktur hartcodiert werden kann.
  • Ein Merkle-Zweig, der die aktuellen Verifizierungsschlüssel unter Angabe des Zustandsstamms des Schlüsselspeichers L2 beweist. Auch hier wird der Verifizierungsschlüssel an einem bekannten Speicherplatz einer bekannten Adresse gespeichert, so dass der Pfad fest kodiert werden kann.

Leider sind Ethereum-Zustandsnachweise kompliziert, aber es gibt Bibliotheken, um sie zu verifizieren, und wenn Sie diese Bibliotheken verwenden, ist dieser Mechanismus nicht allzu kompliziert zu implementieren.

Das größere Problem sind die Kosten. Merkle-Beweise sind lang, und Patricia-Bäume sind leider ~3,9x länger als nötig (genau: ein idealer Merkle-Beweis für einen Baum, der N Objekte enthält, ist 32 log2(N)-Bytes lang, und da die Patricia-Bäume von Ethereum 16 Blätter pro Kind haben, sind die Beweise für diese Bäume 32 15 log16(N) ~= 125 log2(N) Bytes lang). In einem Staat mit etwa 250 Millionen (~2²⁸) Konten ergibt dies jeden Beweis 125 * 28 = 3500 Bytes oder etwa 56.000 Gas, zuzüglich zusätzlicher Kosten für die Dekodierung und Verifizierung von Hashes.

Zwei Proofs zusammen würden am Ende etwa 100.000 bis 150.000 Gas kosten (ohne Signaturprüfung, wenn diese pro Transaktion verwendet wird) - deutlich mehr als die derzeitige Basis von 21.000 Gas pro Transaktion. Die Diskrepanz wird jedoch noch größer, wenn der Beweis auf L2 verifiziert wird. Die Berechnung innerhalb eines L2 ist billig, da die Berechnung außerhalb der Kette und in einem Ökosystem mit viel weniger Knoten als L1 erfolgt. Die Daten hingegen müssen in L1 gebucht werden. Der Vergleich lautet also nicht 21000 Gas vs. 150.000 Gas; es sind 21.000 L2 Gas gegenüber 100.000 L1 Gas.

Wir können berechnen, was das bedeutet, indem wir uns Vergleiche zwischen den L1-Gaskosten und den L2-Gaskosten ansehen:

L1 ist derzeit etwa 15-25x teurer als L2 für einfache Sendungen und 20-50x teurer für Token-Swaps. Einfache Sendungen sind relativ datenintensiv, aber Swaps sind viel rechenintensiver. Daher sind Swaps ein besserer Maßstab für die Annäherung an die Kosten der L1-Berechnung im Vergleich zur L2-Berechnung. Wenn wir unter Berücksichtigung all dessen von einem 30-fachen Kostenverhältnis zwischen L1-Rechenkosten und L2-Rechenkosten ausgehen, scheint dies zu implizieren, dass das Platzieren eines Merkle-Proofs auf L2 das Äquivalent von vielleicht fünfzig regulären Transaktionen kostet.

Natürlich kann die Verwendung eines binären Merkle-Baums die Kosten um das ~4-fache senken, aber selbst dann werden die Kosten in den meisten Fällen zu hoch sein - und wenn wir bereit sind, das Opfer zu bringen, nicht mehr mit dem aktuellen hexaären Zustandsbaum von Ethereum kompatibel zu sein, können wir genauso gut nach noch besseren Optionen suchen.

Wie würden ZK-SNARK-Proofs funktionieren?

Konzeptionell ist die Verwendung von ZK-SNARKs auch einfach zu verstehen: Sie ersetzen einfach die Merkle-Beweise im obigen Diagramm durch einen ZK-SNARK, der beweist, dass diese Merkle-Beweise existieren. Ein ZK-SNARK kostet ~400.000 Gas an Rechenleistung und etwa 400 Bytes (zum Vergleich: 21.000 Gas und 100 Byte für eine einfache Transaktion, in Zukunft reduzierbar auf ~25 Bytes mit Komprimierung). Aus rechnerischer Sicht kostet ein ZK-SNARK heute also das 19-fache der Kosten einer Basistransaktion, und aus Datensicht kostet ein ZK-SNARK heute 4x so viel wie eine Basistransaktion und 16-mal so viel wie eine Basistransaktion in der Zukunft.

Diese Zahlen sind eine massive Verbesserung gegenüber Merkle-Proofs, aber sie sind immer noch ziemlich teuer. Es gibt zwei Möglichkeiten, dies zu verbessern: (i) spezielle KZG-Beweise oder (ii) Aggregation, ähnlich der ERC-4337-Aggregation , aber mit ausgefeilterer Mathematik. Wir können uns mit beidem befassen.

Wie würden spezielle KZG-Nachweise funktionieren?

Achtung, dieser Abschnitt ist viel mathematischer als andere Abschnitte. Das liegt daran, dass wir über Allzweckwerkzeuge hinausgehen und etwas Spezielles bauen, um billiger zu sein, also müssen wir viel mehr "unter die Haube" gehen. Wenn du keine tiefgründige Mathematik magst, springe direkt zum nächsten Abschnitt.

Zunächst eine Zusammenfassung der Funktionsweise der KZG-Verpflichtungen:

  • Wir können eine Reihe von Daten darstellen [D_1 ... D_n] mit einem KZG-Beweis eines aus den Daten abgeleiteten Polynoms: konkret das Polynom P wobei P(w) = D_1, P(w²) = D_2 ... P(wⁿ) = D_n. w ist hier eine "Wurzel der Einheit", ein Wert, bei dem wN = 1 für eine Auswertungsdomäne der Größe N ist (dies geschieht alles in einem endlichen Feld).
  • Um P zu "committieren", erzeugen wir einen elliptischen Kurvenpunkt com(P) = P₀ G + P₁ S₁ + ... + Pk * Sk. Hier:
    • G ist der Generatorpunkt der Kurve
    • Pi ist der i'te Koeffizient des Polynoms P
    • Si ist der i-te Punkt im vertrauenswürdigen Setup
  • Um P(z) = a zu beweisen, erstellen wir ein Quotientenpolynom Q = (P - a) / (X - z) und erstellen eine Verpflichtung com(Q) dazu. Es ist nur möglich, ein solches Polynom zu erzeugen, wenn P(z) tatsächlich gleich a ist.
  • Um einen Beweis zu verifizieren, überprüfen wir die Gleichung Q * (X - z) = P - a, indem wir eine elliptische Kurvenprüfung auf dem Beweis com(Q) und der Polynombindung com(P) durchführen: Wir überprüfen e(com(Q), com(X - z)) ?= e(com(P) - com(a), com(1))

Einige wichtige Eigenschaften, die es zu verstehen gilt, sind:

  • Ein Beweis ist nur der com(Q)-Wert, der 48 Byte groß ist
  • com(P₁) + com(P₂) = com(P₁ + P₂)
  • Das bedeutet auch, dass Sie einen Wert in einen bestehenden Sekundärvertrag "bearbeiten" können. Angenommen, wir wissen, dass D_i derzeit a ist, wollen wir es auf b setzen, und die bestehende Verpflichtung für D ist com(P). Ein Bekenntnis zu "P, aber mit P(wⁱ) = b, und keine anderen Auswertungen geändert", dann setzen wir com(new_P) = com(P) + (b-a) * com(Li), wobei Li ein "Lagrange-Polynom" ist, das an wⁱ gleich 1 und an anderen wj-Punkten 0 ist.
  • Um diese Aktualisierungen effizient durchführen zu können, können alle N-Verpflichtungen für Lagrange-Polynome (com(Li)) von jedem Client vorberechnet und gespeichert werden. Innerhalb eines On-Chain-Vertrags kann es zu viel sein, alle N Verpflichtungen zu speichern, so dass Sie stattdessen eine KZG-Verpflichtung für den Satz von com(L_i)- (oder hash(com(L_i)) Werten eingehen könnten, so dass jeder, der den Baum on-chain aktualisieren muss, einfach dem entsprechenden com(L_i) einen Beweis für seine Richtigkeit liefern kann.

Daher haben wir eine Struktur, in der wir einfach am Ende einer ständig wachsenden Liste Werte hinzufügen können, wenn auch mit einer bestimmten Größenbeschränkung (realistisch gesehen könnten Hunderte von Millionen lebensfähig sein). Wir verwenden dies dann als unsere Datenstruktur, um (i) eine Zusage für die Liste der Schlüssel auf jeder L2, die auf dieser L2 gespeichert und auf L1 gespiegelt wird, und (ii) eine Verpflichtung für die Liste der L2-Schlüsselzusagen zu verwalten, die auf der Ethereum-L1 gespeichert und auf jede L2 gespiegelt werden.

Die Verpflichtungen auf dem neuesten Stand zu halten, könnte entweder Teil der Kernlogik von L2 werden, oder sie könnte ohne Änderungen des L2-Kernprotokolls durch Ein- und Auszahlungsbrücken implementiert werden.

Ein vollständiger Nachweis würde daher Folgendes erfordern:

  • Die neueste com(Schlüsselliste) auf dem Keystore-Holding L2 (48 Bytes)
  • KZG-Beweis dafür, dass com(key list) ein Wert innerhalb von com(mirror_list ist, die Verpflichtung zur Liste aller Schlüssellisten-Comitments (48 Bytes)
  • KZG-Nachweis Ihres Schlüssels in com(Schlüsselliste) (48 Bytes, plus 4 Byte für den Index)

Es ist tatsächlich möglich, die beiden KZG-Beweise zu einem zusammenzuführen, so dass wir eine Gesamtgröße von nur 100 Bytes erhalten.

Beachten Sie eine Feinheit: Da es sich bei der Schlüsselliste um eine Liste und nicht um eine Schlüssel-Wert-Zuordnung wie beim Status handelt, muss die Schlüsselliste Positionen sequenziell zuweisen. Der Schlüsselverpflichtungsvertrag würde eine eigene interne Registrierung enthalten, die jeden Schlüsselspeicher einer ID zuordnet, und für jeden Schlüssel würde er hash (Schlüssel, Adresse des Schlüsselspeichers) anstelle des Schlüssels speichern, um anderen L2s eindeutig mitzuteilen, um welchen Schlüsselspeicher ein bestimmter Eintrag spricht.

Der Vorteil dieser Technik ist, dass sie auf L2 sehr gut funktioniert. Die Daten sind 100 Byte groß, ~4x kürzer als ein ZK-SNARK und waaaay kürzer als ein Merkle-Proof. Die Rechenkosten belaufen sich größtenteils auf eine Pairing-Prüfung der Größe 2 oder etwa 119.000 Gas. Auf L1 sind die Daten weniger wichtig als die Berechnung, und so ist KZG leider etwas teurer als Merkle-Beweise.

Wie würden Verkle-Bäume funktionieren?

Bei Verkle-Bäumen geht es im Wesentlichen darum, KZG-Verpflichtungen (oder IPA-Verpflichtungen, die effizienter sein und einfachere Kryptografie verwenden können) übereinander zu stapeln: Um 2⁴⁸-Werte zu speichern, können Sie eine KZG-Verpflichtung zu einer Liste von 2²⁴-Werten eingehen, von denen jeder selbst eine KZG-Verpflichtung zu 2²⁴-Werten ist. Verkle-Bäume werden <a href="https://notes.ethereum.org/@vbuterin/verkle_tree_eip">stark für den Ethereum-Zustandsbaum in Betracht gezogen, da Verkle-Bäume verwendet werden können, um Schlüssel-Wert-Karten und nicht nur Listen zu speichern (im Grunde können Sie einen Baum der Größe 2²⁵⁶ erstellen, ihn aber leer beginnen und nur bestimmte Teile des Baums ausfüllen, wenn Sie sie tatsächlich füllen müssen).

Wie ein Verkle-Baum aussieht. In der Praxis können Sie jedem Knoten eine Breite von 256 == 2⁸ für IPA-basierte Bäume oder 2²⁴ für KZG-basierte Bäume zuweisen.

Die Nachweise in Verkle-Bäumen sind etwas länger als in KZG; Sie können einige hundert Byte lang sein. Sie sind auch schwer zu überprüfen, vor allem, wenn Sie versuchen, viele Beweise zu einem zu aggregieren.

Realistisch betrachtet sollten Verkle-Bäume als wie Merkle-Bäume betrachtet werden, aber ohne SNARKing praktikabler (wegen der geringeren Datenkosten) und billiger mit SNARKing (wegen der niedrigeren Beweiskosten).

Der größte Vorteil von Verkle-Bäumen ist die Möglichkeit, Datenstrukturen zu harmonisieren: Verkle-Proofs können direkt über dem L1- oder L2-Zustand verwendet werden, ohne Überlagerungsstrukturen und mit genau demselben Mechanismus für L1 und L2. Sobald Quantencomputer ein Problem darstellen oder der Nachweis erbracht ist, dass Merkle-Zweige effizient genug sind, könnten Verkle-Bäume an Ort und Stelle durch einen binären Hash-Baum mit einer geeigneten SNARK-freundlichen Hash-Funktion ersetzt werden.

Aggregation

Wenn N Benutzer N Transaktionen (oder realistischer, N ERC-4337 UserOperations) durchführen, die N Cross-Chain-Behauptungen beweisen müssen, können wir eine Menge Gas sparen, indem wir diese Beweise aggregieren: Der Builder, der diese Transaktionen zu einem Block oder Bündel kombinieren würde, der in einen Block geht, kann einen einzigen Beweis erstellen, der alle diese Behauptungen gleichzeitig beweist.

Dies könnte bedeuten:

In allen drei Fällen würden die Proofs jeweils nur ein paar hunderttausend Gas kosten. Der Ersteller müsste eine davon auf jeder L2 für die Benutzer in dieser L2 erstellen. Damit dies nützlich ist, muss das Schema als Ganzes so weit genutzt werden, dass es sehr oft mindestens ein paar Transaktionen innerhalb desselben Blocks auf mehreren großen L2s gibt.

Wenn ZK-SNARKs verwendet werden, sind die Hauptgrenzkosten einfach die "Geschäftslogik" der Nummernweitergabe zwischen den Verträgen, also vielleicht ein paar tausend L2-Gas pro Benutzer. Wenn KZG-Multi-Proofs verwendet werden, müsste der Prüfer 48 Gas für jeden Keystore-haltenden L2 hinzufügen, der innerhalb dieses Blocks verwendet wird, so dass die Grenzkosten des Schemas pro Benutzer weitere ~800 L1-Gas pro L2 (nicht pro Benutzer) hinzufügen würden. Diese Kosten sind jedoch viel niedriger als die Kosten für die Nicht-Aggregation, die unweigerlich über 10.000 L1-Gas und Hunderttausende von L2-Gas pro Benutzer mit sich bringen. Für Verkle-Bäume können Sie entweder direkt Verkle-Multi-Proofs verwenden, indem Sie etwa 100-200 Bytes pro Benutzer hinzufügen, oder Sie können einen ZK-SNARK aus einem Verkle-Multi-Proof erstellen, der ähnliche Kosten wie ZK-SNARKs von Merkle-Zweigen hat, aber deutlich billiger zu beweisen ist.

Aus Sicht der Implementierung ist es wahrscheinlich am besten, wenn Bundler Cross-Chain-Proofs über den ERC-4337-Kontoabstraktionsstandard aggregieren. ERC-4337 verfügt bereits über einen Mechanismus, mit dem Entwickler Teile von UserOperations auf benutzerdefinierte Weise aggregieren können. Es gibt sogar eine <a href="https://hackmd.io/@voltrevo/BJ0QBy3zi">Implementierung für die BLS-Signaturaggregation, die die Gaskosten auf L2 um das 1,5- bis 3-fache senken könnte, je nachdem, welche anderen Formen der Kompression enthalten sind.

Diagramm aus einem <a href="https://hackmd.io/@voltrevo/BJ0QBy3zi">BLS-Wallet-Implementierungsbeitrag, der den Workflow von BLS-aggregierten Signaturen in einer früheren Version von ERC-4337 zeigt. Der Workflow zum Aggregieren von Cross-Chain-Proofs wird wahrscheinlich sehr ähnlich aussehen.

Direktes Auslesen des Zustands

Eine letzte Möglichkeit, die nur für L2 verwendet werden kann, die L1 liest (und nicht L1, die L2 liest), besteht darin, L2s so zu modifizieren, dass sie statische Aufrufe von Kontrakten auf L1 direkt ausführen können.

Dies kann mit einem Opcode oder einem Vorkompilat erfolgen, das Anrufe in L1 ermöglicht, wobei Sie die Zieladresse, Gas und Anrufdaten angeben, und es gibt die Ausgabe zurück, obwohl diese Aufrufe statische Aufrufe sind, können sie keinen L1-Zustand ändern. L2s müssen L1 bereits kennen, um Einlagen zu verarbeiten, also gibt es nichts Grundsätzliches, was die Implementierung einer solchen Sache verhindert; Es handelt sich hauptsächlich um eine technische Herausforderung bei der Implementierung (siehe: diese Ausschreibung von Optimism zur Unterstützung statischer Aufrufe in L1).

Beachten Sie, dass, wenn sich der Keystore auf L1 befindet und L2s die statische Anruffunktion von L1 integrieren, überhaupt keine Nachweise erforderlich sind! Wenn L2s jedoch keine statischen L1-Aufrufe integrieren oder wenn sich der Keystore auf L2 befindet (was möglicherweise irgendwann der Fall sein muss, wenn L1 für Benutzer zu teuer wird, um es auch nur ein bisschen zu verwenden), dann sind Nachweise erforderlich.

Wie lernt L2 die aktuelle Ethereum-Zustandswurzel?

Alle oben genannten Schemata erfordern, dass L2 entweder auf den aktuellen L1-Statusstamm oder auf den gesamten aktuellen L1-Status zugreift. Glücklicherweise verfügen alle L2s bereits über einige Funktionen, um auf den aktuellen L1-Status zuzugreifen. Dies liegt daran, dass sie eine solche Funktionalität benötigen, um Nachrichten zu verarbeiten, die von L1 bis L2 eingehen, insbesondere Einzahlungen.

Und tatsächlich, wenn ein L2 eine Einzahlungsfunktion hat, dann können Sie dieses L2 unverändert verwenden, um L1-Zustandswurzeln in einen Vertrag auf L2 zu verschieben: Lassen Sie einfach einen Vertrag auf L1 den BLOCKHASH-Opcode aufrufen und übergeben Sie ihn als Einzahlungsnachricht an L2. Der vollständige Blockheader kann auf der L2-Seite empfangen und sein Zustandsstamm extrahiert werden. Es wäre jedoch viel besser, wenn jede L2 eine explizite Möglichkeit hätte, entweder direkt auf den vollständigen aktuellen L1-Status oder auf die aktuellen L1-Statusstämme zuzugreifen.

Die größte Herausforderung bei der Optimierung der Art und Weise, wie L2s aktuelle L1-Zustandswurzeln empfangen, besteht darin, gleichzeitig Sicherheit und niedrige Latenz zu erreichen:

  • Wenn L2s die Funktionalität des "direkten Lesens von L1" auf eine faule Art und Weise implementieren und nur die endgültigen L1-Zustandswurzeln lesen, dann beträgt die Verzögerung normalerweise 15 Minuten, aber im Extremfall von Inaktivitätslecks (die Sie tolerieren müssen) kann die Verzögerung mehrere Wochen betragen.
  • L2s kann durchaus so konzipiert werden, dass es viel neuere L1-Zustandswurzeln liest, aber da L1 rückgängig gemacht werden kann (selbst bei Finalität eines einzelnen Slots können Reverts während Inaktivitätslecks auftreten), müsste L2 auch in der Lage sein, zurückzukehren. Das ist aus Sicht des Software-Engineerings eine technische Herausforderung, aber zumindest Optimism verfügt bereits über diese Fähigkeit.
  • Wenn Sie die Deposit-Bridge verwenden, um L1-State-Wurzeln in L2 zu bringen, dann kann die einfache wirtschaftliche Rentabilität eine lange Zeit zwischen den Deposit-Aktualisierungen erfordern: Wenn die vollen Kosten einer Einlage 100.000 Gas betragen und wir davon ausgehen, dass ETH bei 1800 USD liegt und die Gebühren bei 200 Gwei liegen und L1-Wurzeln einmal pro Tag in L2 eingebracht werden, Das wären Kosten von 36 US-Dollar pro L2 pro Tag oder 13148 US-Dollar pro L2 pro Jahr für die Wartung des Systems. Mit einer Verzögerung von einer Stunde steigt das auf 315.569 US-Dollar pro L2 und Jahr. Im besten Fall deckt ein ständiges Rinnsal ungeduldiger, wohlhabender Nutzer die Update-Gebühren und hält das System für alle anderen auf dem neuesten Stand. Im schlimmsten Fall müsste irgendein altruistischer Akteur selbst dafür bezahlen.
  • "Orakel" (zumindest die Art von Technologie, die einige DeFi-Leute "Orakel" nennen) sind hier keine akzeptable Lösung: Die Verwaltung von Wallet-Schlüsseln ist eine sehr sicherheitskritische Low-Level-Funktionalität und sollte daher höchstens von ein paar Teilen einer sehr einfachen, kryptographisch vertrauenswürdigen Low-Level-Infrastruktur abhängen.

Zusätzlich in die entgegengesetzte Richtung (L1s, die L2 liest):

  • Bei optimistischen Rollups dauert es aufgrund der Verzögerung mit der Betrugssicherheit eine Woche, bis die State Roots L1 erreichen. Bei ZK-Rollups dauert es aufgrund einer Kombination aus Testzeiten und wirtschaftlichen Grenzen vorerst einige Stunden, obwohl zukünftige Technologien dies reduzieren werden.
  • Vorbestätigungen (von Sequenzern, Attestern usw.) sind keine akzeptable Lösung für L1-Lesung von L2. Die Wallet-Verwaltung ist eine sehr sicherheitskritische Low-Level-Funktionalität, und daher muss das Sicherheitsniveau der L2->-L1-Kommunikation absolut sein: Es sollte nicht einmal möglich sein, eine falsche L1-State-Root zu pushen, indem man das L2-Validator-Set übernimmt. Die einzigen State-Roots, denen L1 vertrauen sollte, sind State-Roots, die vom State-Root-Holding-Vertrag der L2 auf L1 als endgültig akzeptiert wurden.

Einige dieser Geschwindigkeiten für vertrauenswürdige Cross-Chain-Operationen sind für viele DeFi-Anwendungsfälle inakzeptabel langsam. In diesen Fällen benötigen Sie schnellere Bridges mit unvollkommeneren Sicherheitsmodellen. Für den Anwendungsfall der Aktualisierung von Wallet-Schlüsseln sind längere Verzögerungen jedoch akzeptabler: Sie verzögern Transaktionen nicht um Stunden, sondern um Schlüsseländerungen. Sie müssen nur die alten Schlüssel länger aufbewahren. Wenn Sie Schlüssel ändern, weil Schlüssel gestohlen wurden, haben Sie eine erhebliche Anfälligkeit, die jedoch gemildert werden kann, z. durch Wallets mit einer Freeze-Funktion.

Letztendlich besteht die beste Lösung zur Minimierung der Latenz darin, dass L2s das direkte Lesen von L1-Zustandswurzeln auf optimale Weise implementiert, wobei jeder L2-Block (oder das Zustandsstammberechnungsprotokoll) einen Zeiger auf den letzten L1-Block enthält, sodass L2 ebenfalls zurückkehren kann, wenn L1 zurückgesetzt wird. Keystore-Verträge sollten entweder im Mainnet oder auf L2-Verträgen platziert werden, die ZK-Rollups sind und sich daher schnell an L1 binden können.

Blöcke der L2-Kette können nicht nur von vorherigen L2-Blöcken, sondern auch von einem L1-Block abhängig sein. Wenn L1 über einen solchen Link hinaus zurückkehrt, wird auch L2 zurückgesetzt. Es ist erwähnenswert, dass dies auch die Art und Weise ist, wie eine frühere Version von Sharding (vor Dank) funktionieren sollte. Code finden Sie hier .

Wie viel Verbindung zu Ethereum benötigt eine andere Chain, um Wallets zu halten, deren Keystores auf Ethereum oder einem L2 basieren?

Überraschenderweise nicht so sehr. Es muss eigentlich nicht einmal ein Rollup sein: Wenn es sich um ein L3 oder ein Validium handelt, dann ist es in Ordnung, Wallets dort zu halten, solange Sie Keystores entweder auf L1 oder auf einem ZK-Rollup halten. Was Sie brauchen, ist, dass die Chain direkten Zugang zu den Wurzeln des Ethereum-Staates hat und ein technisches und soziales Engagement, um bereit zu sein, sich neu zu organisieren, wenn Ethereum neu organisiert wird, und eine Hard Fork, wenn Ethereum hart abgespalten wird.

Ein interessantes Forschungsproblem besteht darin, herauszufinden, inwieweit es möglich ist, dass eine Kette diese Form der Verbindung mit mehreren anderen Ketten (z. Ethereum und Zcash). Es ist möglich, es naiv zu machen: Ihre Chain könnte sich darauf einigen, sich neu zu organisieren, wenn Ethereum oder Zcash reorganisiert werden (und eine Hard Fork, wenn Ethereum oder Zcash eine Hard Fork hat), aber dann haben Ihre Node-Betreiber und Ihre Community im Allgemeinen doppelt so viele technische und politische Abhängigkeiten. Daher könnte eine solche Technik verwendet werden, um eine Verbindung zu einigen anderen Ketten herzustellen, jedoch zu steigenden Kosten. Schemes, die auf ZK-Bridges basieren, haben attraktive technische Eigenschaften, aber sie haben die entscheidende Schwäche, dass sie nicht robust gegenüber 51%-Angriffen oder Hard Forks sind. Vielleicht gibt es cleverere Lösungen.

Wahrung der Privatsphäre

Im Idealfall wollen wir auch die Privatsphäre wahren. Wenn Sie viele Wallets haben, die vom selben Keystore verwaltet werden, möchten wir sicherstellen:

  • Es ist nicht öffentlich bekannt, dass diese Wallets alle miteinander verbunden sind.
  • Die Hüter der sozialen Wiederherstellung erfahren nicht, was die Adressen sind, die sie bewachen.

Dies führt zu einigen Problemen:

  • Wir können Merkle-Proofs nicht direkt verwenden, da sie die Privatsphäre nicht wahren.
  • Wenn wir KZG oder SNARKs verwenden, muss der Beweis eine verblindete Version des Verifizierungsschlüssels enthalten, ohne den Speicherort des Verifizierungsschlüssels preiszugeben.
  • Wenn wir Aggregation verwenden, sollte der Aggregator den Speicherort nicht im Klartext lernen. Vielmehr sollte der Aggregator verblindete Beweise erhalten und eine Möglichkeit haben, diese zu aggregieren.
  • Wir können die "Light-Version" (verwenden Sie Cross-Chain-Proofs nur zum Aktualisieren von Schlüsseln) nicht verwenden, da dies zu einem Datenschutzleck führt: Wenn viele Wallets aufgrund eines Aktualisierungsvorgangs gleichzeitig aktualisiert werden, verliert das Timing die Information, dass diese Wallets wahrscheinlich miteinander verbunden sind. Wir müssen also die "schwere Version" (Cross-Chain-Proofs für jede Transaktion) verwenden.

Mit SNARKs sind die Lösungen konzeptionell einfach: Beweise verbergen standardmäßig Informationen, und der Aggregator muss ein rekursives SNARK erzeugen, um die SNARKs zu beweisen.

Die größte Herausforderung dieses Ansatzes besteht heute darin, dass der Aggregator für die Aggregation ein rekursives SNARK erstellen muss, was derzeit recht langsam ist.

Mit KZG können wir <a href="https://notes.ethereum.org/@vbuterin/non_index_revealing_proof">this verwenden. Arbeit an nicht-index-offenbaren KZG-Beweisen (siehe auch: eine formalisiertere Version dieser Arbeit im Caulk-Papier ) als Ausgangspunkt. Die Aggregation von verblindeten Beweisen ist jedoch ein offenes Problem, das mehr Aufmerksamkeit erfordert.

Das direkte Lesen von L1 aus L2 bewahrt leider nicht die Privatsphäre, obwohl die Implementierung der Funktion zum direkten Lesen immer noch sehr nützlich ist, sowohl um die Latenz zu minimieren als auch wegen ihrer Nützlichkeit für andere Anwendungen.

Zusammenfassung

  • Um Cross-Chain-Social-Recovery-Wallets zu haben, ist der realistischste Workflow eine Wallet, die einen Keystore an einem Ort und Wallets an vielen Standorten unterhält, wobei die Wallet den Keystore liest, entweder (i) um ihre lokale Ansicht des Verifizierungsschlüssels zu aktualisieren, oder (ii) während des Prozesses der Verifizierung jeder Transaktion.
  • Ein wichtiger Bestandteil, um dies zu ermöglichen, sind Cross-Chain-Proofs. Wir müssen diese Beweise stark optimieren. Entweder ZK-SNARKs, die auf Verkle-Proofs warten, oder eine maßgeschneiderte KZG-Lösung scheinen die besten Optionen zu sein.
  • Längerfristig werden Aggregationsprotokolle, bei denen Bundler aggregierte Proofs generieren, um ein Bündel aller von Benutzern übermittelten UserOperations zu erstellen, erforderlich sein, um die Kosten zu minimieren. Dies sollte wahrscheinlich in das ERC-4337-Ökosystem integriert werden, obwohl wahrscheinlich Änderungen an ERC-4337 erforderlich sein werden.
  • L2s sollte optimiert werden, um die Latenz beim Lesen des L1-Zustands (oder zumindest des Zustandsstamms) aus dem L2 zu minimieren. L2s direkt das Lesen des L1-Zustands ist ideal und kann Beweisplatz sparen.
  • Wallets können nicht nur auf L2s sein; Sie können Wallets auch auf Systemen mit geringerer Verbindung zu Ethereum platzieren (L3s oder sogar separate Chains, die sich nur darauf einigen, Ethereum-State-Roots und Reorg oder Hard Fork einzubeziehen, wenn Ethereum reorganisiert oder hardforks wird).
  • Keystores sollten sich jedoch entweder auf L1 oder auf dem hochsicheren ZK-Rollup L2 befinden. Auf L1 zu sein, spart viel Komplexität, obwohl selbst das auf lange Sicht zu teuer sein kann, daher die Notwendigkeit von Keystores auf L2.
  • Die Wahrung der Privatsphäre erfordert zusätzliche Arbeit und erschwert einige Optionen. Allerdings sollten wir uns wahrscheinlich sowieso auf Lösungen zubewegen, die die Privatsphäre schützen, und zumindest sicherstellen, dass alles, was wir vorschlagen, mit dem Schutz der Privatsphäre kompatibel ist.

Verzichtserklärung:

  1. Dieser Artikel ist ein Nachdruck von [vitalik], Alle Urheberrechte liegen beim ursprünglichen Autor [Vitalik Buterin]. Wenn es Einwände gegen diesen Nachdruck gibt, wenden Sie sich bitte an das Gate Learn-Team , das sich umgehend darum kümmern wird.
  2. Haftungsausschluss: Die in diesem Artikel geäußerten Ansichten und Meinungen sind ausschließlich die des Autors und stellen keine Anlageberatung dar.
  3. Übersetzungen des Artikels in andere Sprachen werden vom Gate Learn-Team durchgeführt. Sofern nicht anders angegeben, ist das Kopieren, Verbreiten oder Plagiieren der übersetzten Artikel verboten.

Tieferer Einblick in das L2-übergreifende Lesen für Wallets und andere Anwendungsfälle

Erweitert2/29/2024, 5:22:58 AM
In diesem Artikel geht Vitalik direkt auf einen spezifischen technischen Aspekt eines Teilproblems ein: wie man leichter von L2 nach L1, von L1 nach L2 oder von einem L2 zu einem anderen L2 lesen kann. Die Lösung dieses Problems ist entscheidend für das Erreichen einer Asset-/Schlüsseltrennungsarchitektur, aber es gibt auch wertvolle Anwendungsfälle in anderen Bereichen, insbesondere die Optimierung zuverlässiger L2-übergreifender Aufrufe, einschließlich Anwendungsfällen wie dem Verschieben von Assets zwischen L1 und L2.

Besonderer Dank geht an Yoav Weiss, Dan Finlay, Martin Koppelmann und die Teams von Arbitrum, Optimism, Polygon, Scroll und SoulWallet für das Feedback und die Bewertung.

In diesem Beitrag über die drei Übergänge habe ich einige Hauptgründe skizziert, warum es wertvoll ist, explizit über L1 + Cross-L2-Unterstützung, Wallet-Sicherheit und Datenschutz als notwendige Grundfunktionen des Ökosystem-Stacks nachzudenken, anstatt jedes dieser Dinge als Addons zu erstellen, die von einzelnen Wallets separat gestaltet werden können.

Dieser Beitrag konzentriert sich direkt auf die technischen Aspekte eines bestimmten Teilproblems: Wie kann man es einfacher machen, L1 von L2, L2 von L1 oder L2 von einem anderen L2 zu lesen? Die Lösung dieses Problems ist entscheidend für die Implementierung einer Asset-/Keystore-Trennungsarchitektur, hat aber auch wertvolle Anwendungsfälle in anderen Bereichen, insbesondere die Optimierung zuverlässiger L2-übergreifender Aufrufe, einschließlich Anwendungsfällen wie dem Verschieben von Assets zwischen L1 und L2.

Empfohlene Pre-Reads

Inhaltsverzeichnis

Was ist das Ziel?

Sobald L2s mehr zum Mainstream werden, werden die Benutzer über Assets in mehreren L2s und möglicherweise auch über L1 verfügen. Sobald Smart-Contract-Wallets (Multisig, Social Recovery oder andere) zum Mainstream werden, werden sich die Schlüssel, die für den Zugriff auf ein Konto benötigt werden, im Laufe der Zeit ändern, und alte Schlüssel müssten nicht mehr gültig sein. Sobald beides geschieht, muss ein Benutzer eine Möglichkeit haben, die Schlüssel zu ändern, die für den Zugriff auf viele Konten an vielen verschiedenen Orten berechtigt sind, ohne eine extrem hohe Anzahl von Transaktionen durchzuführen.

Insbesondere brauchen wir eine Möglichkeit, mit kontrafaktischen Adressen umzugehen: Adressen, die noch in keiner Weise on-chain "registriert" wurden, die aber dennoch Gelder empfangen und sicher aufbewahren müssen. Wir alle sind auf kontrafaktische Adressen angewiesen: Wenn Sie Ethereum zum ersten Mal verwenden, können Sie eine ETH-Adresse generieren, mit der jemand Sie bezahlen kann, ohne die Adresse auf der Chain zu "registrieren" (was die Zahlung von Txfees erfordern würde und somit bereits einige ETH halten würde).

Bei EOAs beginnen alle Adressen als kontrafaktische Adressen. Mit Smart-Contract-Wallets sind kontrafaktische Adressen immer noch möglich, vor allem dank CREATE2, die es Ihnen ermöglicht, eine ETH-Adresse zu haben, die nur von einem Smart Contract gefüllt werden kann, dessen Code mit einem bestimmten Hash übereinstimmt.

EIP-1014 (CREATE2) Adressberechnungsalgorithmus.

Smart-Contract-Wallets bringen jedoch eine neue Herausforderung mit sich: die Möglichkeit, Zugangsschlüssel zu ändern. Die Adresse, bei der es sich um einen Hash des Initcodes handelt, kann nur den anfänglichen Verifizierungsschlüssel des Wallets enthalten. Der aktuelle Verifizierungsschlüssel wird im Speicher der Wallet gespeichert, aber dieser Speicherdatensatz wird nicht auf magische Weise an andere L2s weitergegeben.

Wenn ein Benutzer viele Adressen auf vielen L2s hat, einschließlich Adressen, die (weil sie kontrafaktisch sind) der L2, auf der er sich befindet, nicht kennt, dann scheint es nur eine Möglichkeit zu geben, Benutzern das Ändern ihrer Schlüssel zu ermöglichen: Asset-/Keystore-Trennungsarchitektur. Jeder Benutzer hat (i) einen "Keystore-Vertrag" (auf L1 oder auf einem bestimmten L2), der den Verifizierungsschlüssel für alle Wallets zusammen mit den Regeln für die Änderung des Schlüssels speichert, und (ii) "Wallet-Verträge" auf L1 und vielen L2s, die Cross-Chain lesen, um den Verifizierungsschlüssel zu erhalten.

Es gibt zwei Möglichkeiten, dies zu implementieren:

  • Light-Version (nur zum Aktualisieren von Schlüsseln): Jede Wallet speichert den Verifizierungsschlüssel lokal und enthält eine Funktion, die aufgerufen werden kann, um einen Cross-Chain-Nachweis des aktuellen Zustands des Schlüsselspeichers zu überprüfen und den lokal gespeicherten Verifizierungsschlüssel entsprechend zu aktualisieren. Wenn ein Wallet zum ersten Mal auf einem bestimmten L2 verwendet wird, ist der Aufruf dieser Funktion zum Abrufen des aktuellen Verifizierungsschlüssels aus dem Keystore obligatorisch.
    • Vorteil: Verwendet Cross-Chain-Proofs sparsam, daher ist es in Ordnung, wenn Cross-Chain-Proofs teuer sind. Alle Gelder können nur mit den aktuellen Schlüsseln ausgegeben werden, so dass es immer noch sicher ist.
    • Nachteil: Um den Verifizierungsschlüssel zu ändern, müssen Sie sowohl im Keystore als auch in jeder bereits initialisierten Wallet (wenn auch nicht kontrafaktische) eine Änderung des On-Chain-Schlüssels vornehmen. Das könnte viel Gas kosten.
  • Heavy-Version (Prüfung für jeden TX): Für jede Transaktion ist ein Cross-Chain-Proof erforderlich, der den Schlüssel anzeigt, der sich derzeit im Keystore befindet.
    • Der Vorteil ist, dass die systemische Komplexität geringer ist und die Aktualisierung des Keystores kostengünstig ist.
    • Nachteil: teuer pro tx, erfordert also viel mehr Engineering, um Cross-Chain-Proofs akzeptabel billig zu machen. Auch nicht ohne weiteres kompatibel mit ERC-4337, das derzeit das vertragsübergreifende Lesen von veränderlichen Objekten während der Validierung nicht unterstützt.

Wie sieht ein Cross-Chain-Proof aus?

Um die volle Komplexität zu zeigen, untersuchen wir den schwierigsten Fall: Wenn sich der Keystore auf einem L2 und die Wallet auf einem anderen L2 befindet. Wenn sich entweder der Keystore oder die Wallet auf L1 befindet, wird nur die Hälfte dieses Designs benötigt.

Nehmen wir an, dass sich der Keystore auf Linea und die Wallet auf Kakarot befindet. Ein vollständiger Nachweis der Schlüssel zum Wallet besteht aus:

  • Ein Beweis für die aktuelle Linea-Zustandswurzel angesichts der aktuellen Ethereum-Zustandswurzel, die Kakarot kennt
  • Ein Beweis für die aktuellen Schlüssel im Keystore unter Angabe des aktuellen Linea-Zustandsstamms

Hier gibt es zwei primäre knifflige Implementierungsfragen:

  1. Welche Art von Beweisen verwenden wir? (Sind es Merkle-Beweise? etwas anderes?)
  2. Wie lernt die L2 überhaupt die aktuelle L1 (Ethereum)-Zustandswurzel (oder, wie wir sehen werden, möglicherweise den vollständigen L1-Zustand)? Und alternativ, wie lernt der L1 die L2-Zustandswurzel?
    • Wie lange sind in beiden Fällen die Verzögerungen zwischen etwas, das auf der einen Seite passiert, und dem, was auf der anderen Seite beweisbar ist?

Welche Arten von Nachweisschemata können wir verwenden?

Es gibt fünf Hauptoptionen:

  • Merkle-Proofs
  • Universell einsetzbare ZK-SNARKs
  • Spezielle Nachweise (z. mit KZG)
  • Verkle-Proofs, die sowohl in Bezug auf den Infrastruktur-Workload als auch auf die Kosten irgendwo zwischen KZG und ZK-SNARKs liegen.
  • Keine Beweise und verlassen Sie sich auf die direkte Zustandslesung

In Bezug auf den Infrastrukturaufwand und die Kosten für die Nutzer ordne ich sie grob wie folgt ein:

"Aggregation" bezieht sich auf die Idee, alle von Benutzern innerhalb jedes Blocks gelieferten Beweise zu einem großen Meta-Beweis zu aggregieren, der alle kombiniert. Dies ist für SNARKs und für KZG möglich, aber nicht für Merkle-Zweige (Sie können Merkle-Zweige ein wenig kombinieren, aber es spart Ihnen nur log(txs pro Block) / log (Gesamtzahl der Keystores), vielleicht 15-30% in der Praxis, also ist es die Kosten wahrscheinlich nicht wert).

Die Aggregation lohnt sich erst, wenn das Schema eine beträchtliche Anzahl von Benutzern hat, daher ist es realistischerweise in Ordnung, wenn eine Implementierung der Version 1 die Aggregation weglässt und für Version 2 implementiert.

Wie würden Merkle-Proofs funktionieren?

Das ist einfach: Folgen Sie direkt dem Diagramm im vorherigen Abschnitt . Genauer gesagt würde jeder "Beweis" (unter der Annahme des maximalen Schwierigkeitsfalls des Beweises eines L2 in ein anderes L2) enthalten:

  • Ein Merkle-Zweig, der die State-Root des Keystore-haltenden L2 beweist, wenn man die neueste State-Root von Ethereum angibt, die L2 kennt. Der Zustandsstamm des Keystore-Halters L2 wird in einem bekannten Speicherslot einer bekannten Adresse gespeichert (der Vertrag auf L1 stellt L2 dar), sodass der Pfad durch die Struktur hartcodiert werden kann.
  • Ein Merkle-Zweig, der die aktuellen Verifizierungsschlüssel unter Angabe des Zustandsstamms des Schlüsselspeichers L2 beweist. Auch hier wird der Verifizierungsschlüssel an einem bekannten Speicherplatz einer bekannten Adresse gespeichert, so dass der Pfad fest kodiert werden kann.

Leider sind Ethereum-Zustandsnachweise kompliziert, aber es gibt Bibliotheken, um sie zu verifizieren, und wenn Sie diese Bibliotheken verwenden, ist dieser Mechanismus nicht allzu kompliziert zu implementieren.

Das größere Problem sind die Kosten. Merkle-Beweise sind lang, und Patricia-Bäume sind leider ~3,9x länger als nötig (genau: ein idealer Merkle-Beweis für einen Baum, der N Objekte enthält, ist 32 log2(N)-Bytes lang, und da die Patricia-Bäume von Ethereum 16 Blätter pro Kind haben, sind die Beweise für diese Bäume 32 15 log16(N) ~= 125 log2(N) Bytes lang). In einem Staat mit etwa 250 Millionen (~2²⁸) Konten ergibt dies jeden Beweis 125 * 28 = 3500 Bytes oder etwa 56.000 Gas, zuzüglich zusätzlicher Kosten für die Dekodierung und Verifizierung von Hashes.

Zwei Proofs zusammen würden am Ende etwa 100.000 bis 150.000 Gas kosten (ohne Signaturprüfung, wenn diese pro Transaktion verwendet wird) - deutlich mehr als die derzeitige Basis von 21.000 Gas pro Transaktion. Die Diskrepanz wird jedoch noch größer, wenn der Beweis auf L2 verifiziert wird. Die Berechnung innerhalb eines L2 ist billig, da die Berechnung außerhalb der Kette und in einem Ökosystem mit viel weniger Knoten als L1 erfolgt. Die Daten hingegen müssen in L1 gebucht werden. Der Vergleich lautet also nicht 21000 Gas vs. 150.000 Gas; es sind 21.000 L2 Gas gegenüber 100.000 L1 Gas.

Wir können berechnen, was das bedeutet, indem wir uns Vergleiche zwischen den L1-Gaskosten und den L2-Gaskosten ansehen:

L1 ist derzeit etwa 15-25x teurer als L2 für einfache Sendungen und 20-50x teurer für Token-Swaps. Einfache Sendungen sind relativ datenintensiv, aber Swaps sind viel rechenintensiver. Daher sind Swaps ein besserer Maßstab für die Annäherung an die Kosten der L1-Berechnung im Vergleich zur L2-Berechnung. Wenn wir unter Berücksichtigung all dessen von einem 30-fachen Kostenverhältnis zwischen L1-Rechenkosten und L2-Rechenkosten ausgehen, scheint dies zu implizieren, dass das Platzieren eines Merkle-Proofs auf L2 das Äquivalent von vielleicht fünfzig regulären Transaktionen kostet.

Natürlich kann die Verwendung eines binären Merkle-Baums die Kosten um das ~4-fache senken, aber selbst dann werden die Kosten in den meisten Fällen zu hoch sein - und wenn wir bereit sind, das Opfer zu bringen, nicht mehr mit dem aktuellen hexaären Zustandsbaum von Ethereum kompatibel zu sein, können wir genauso gut nach noch besseren Optionen suchen.

Wie würden ZK-SNARK-Proofs funktionieren?

Konzeptionell ist die Verwendung von ZK-SNARKs auch einfach zu verstehen: Sie ersetzen einfach die Merkle-Beweise im obigen Diagramm durch einen ZK-SNARK, der beweist, dass diese Merkle-Beweise existieren. Ein ZK-SNARK kostet ~400.000 Gas an Rechenleistung und etwa 400 Bytes (zum Vergleich: 21.000 Gas und 100 Byte für eine einfache Transaktion, in Zukunft reduzierbar auf ~25 Bytes mit Komprimierung). Aus rechnerischer Sicht kostet ein ZK-SNARK heute also das 19-fache der Kosten einer Basistransaktion, und aus Datensicht kostet ein ZK-SNARK heute 4x so viel wie eine Basistransaktion und 16-mal so viel wie eine Basistransaktion in der Zukunft.

Diese Zahlen sind eine massive Verbesserung gegenüber Merkle-Proofs, aber sie sind immer noch ziemlich teuer. Es gibt zwei Möglichkeiten, dies zu verbessern: (i) spezielle KZG-Beweise oder (ii) Aggregation, ähnlich der ERC-4337-Aggregation , aber mit ausgefeilterer Mathematik. Wir können uns mit beidem befassen.

Wie würden spezielle KZG-Nachweise funktionieren?

Achtung, dieser Abschnitt ist viel mathematischer als andere Abschnitte. Das liegt daran, dass wir über Allzweckwerkzeuge hinausgehen und etwas Spezielles bauen, um billiger zu sein, also müssen wir viel mehr "unter die Haube" gehen. Wenn du keine tiefgründige Mathematik magst, springe direkt zum nächsten Abschnitt.

Zunächst eine Zusammenfassung der Funktionsweise der KZG-Verpflichtungen:

  • Wir können eine Reihe von Daten darstellen [D_1 ... D_n] mit einem KZG-Beweis eines aus den Daten abgeleiteten Polynoms: konkret das Polynom P wobei P(w) = D_1, P(w²) = D_2 ... P(wⁿ) = D_n. w ist hier eine "Wurzel der Einheit", ein Wert, bei dem wN = 1 für eine Auswertungsdomäne der Größe N ist (dies geschieht alles in einem endlichen Feld).
  • Um P zu "committieren", erzeugen wir einen elliptischen Kurvenpunkt com(P) = P₀ G + P₁ S₁ + ... + Pk * Sk. Hier:
    • G ist der Generatorpunkt der Kurve
    • Pi ist der i'te Koeffizient des Polynoms P
    • Si ist der i-te Punkt im vertrauenswürdigen Setup
  • Um P(z) = a zu beweisen, erstellen wir ein Quotientenpolynom Q = (P - a) / (X - z) und erstellen eine Verpflichtung com(Q) dazu. Es ist nur möglich, ein solches Polynom zu erzeugen, wenn P(z) tatsächlich gleich a ist.
  • Um einen Beweis zu verifizieren, überprüfen wir die Gleichung Q * (X - z) = P - a, indem wir eine elliptische Kurvenprüfung auf dem Beweis com(Q) und der Polynombindung com(P) durchführen: Wir überprüfen e(com(Q), com(X - z)) ?= e(com(P) - com(a), com(1))

Einige wichtige Eigenschaften, die es zu verstehen gilt, sind:

  • Ein Beweis ist nur der com(Q)-Wert, der 48 Byte groß ist
  • com(P₁) + com(P₂) = com(P₁ + P₂)
  • Das bedeutet auch, dass Sie einen Wert in einen bestehenden Sekundärvertrag "bearbeiten" können. Angenommen, wir wissen, dass D_i derzeit a ist, wollen wir es auf b setzen, und die bestehende Verpflichtung für D ist com(P). Ein Bekenntnis zu "P, aber mit P(wⁱ) = b, und keine anderen Auswertungen geändert", dann setzen wir com(new_P) = com(P) + (b-a) * com(Li), wobei Li ein "Lagrange-Polynom" ist, das an wⁱ gleich 1 und an anderen wj-Punkten 0 ist.
  • Um diese Aktualisierungen effizient durchführen zu können, können alle N-Verpflichtungen für Lagrange-Polynome (com(Li)) von jedem Client vorberechnet und gespeichert werden. Innerhalb eines On-Chain-Vertrags kann es zu viel sein, alle N Verpflichtungen zu speichern, so dass Sie stattdessen eine KZG-Verpflichtung für den Satz von com(L_i)- (oder hash(com(L_i)) Werten eingehen könnten, so dass jeder, der den Baum on-chain aktualisieren muss, einfach dem entsprechenden com(L_i) einen Beweis für seine Richtigkeit liefern kann.

Daher haben wir eine Struktur, in der wir einfach am Ende einer ständig wachsenden Liste Werte hinzufügen können, wenn auch mit einer bestimmten Größenbeschränkung (realistisch gesehen könnten Hunderte von Millionen lebensfähig sein). Wir verwenden dies dann als unsere Datenstruktur, um (i) eine Zusage für die Liste der Schlüssel auf jeder L2, die auf dieser L2 gespeichert und auf L1 gespiegelt wird, und (ii) eine Verpflichtung für die Liste der L2-Schlüsselzusagen zu verwalten, die auf der Ethereum-L1 gespeichert und auf jede L2 gespiegelt werden.

Die Verpflichtungen auf dem neuesten Stand zu halten, könnte entweder Teil der Kernlogik von L2 werden, oder sie könnte ohne Änderungen des L2-Kernprotokolls durch Ein- und Auszahlungsbrücken implementiert werden.

Ein vollständiger Nachweis würde daher Folgendes erfordern:

  • Die neueste com(Schlüsselliste) auf dem Keystore-Holding L2 (48 Bytes)
  • KZG-Beweis dafür, dass com(key list) ein Wert innerhalb von com(mirror_list ist, die Verpflichtung zur Liste aller Schlüssellisten-Comitments (48 Bytes)
  • KZG-Nachweis Ihres Schlüssels in com(Schlüsselliste) (48 Bytes, plus 4 Byte für den Index)

Es ist tatsächlich möglich, die beiden KZG-Beweise zu einem zusammenzuführen, so dass wir eine Gesamtgröße von nur 100 Bytes erhalten.

Beachten Sie eine Feinheit: Da es sich bei der Schlüsselliste um eine Liste und nicht um eine Schlüssel-Wert-Zuordnung wie beim Status handelt, muss die Schlüsselliste Positionen sequenziell zuweisen. Der Schlüsselverpflichtungsvertrag würde eine eigene interne Registrierung enthalten, die jeden Schlüsselspeicher einer ID zuordnet, und für jeden Schlüssel würde er hash (Schlüssel, Adresse des Schlüsselspeichers) anstelle des Schlüssels speichern, um anderen L2s eindeutig mitzuteilen, um welchen Schlüsselspeicher ein bestimmter Eintrag spricht.

Der Vorteil dieser Technik ist, dass sie auf L2 sehr gut funktioniert. Die Daten sind 100 Byte groß, ~4x kürzer als ein ZK-SNARK und waaaay kürzer als ein Merkle-Proof. Die Rechenkosten belaufen sich größtenteils auf eine Pairing-Prüfung der Größe 2 oder etwa 119.000 Gas. Auf L1 sind die Daten weniger wichtig als die Berechnung, und so ist KZG leider etwas teurer als Merkle-Beweise.

Wie würden Verkle-Bäume funktionieren?

Bei Verkle-Bäumen geht es im Wesentlichen darum, KZG-Verpflichtungen (oder IPA-Verpflichtungen, die effizienter sein und einfachere Kryptografie verwenden können) übereinander zu stapeln: Um 2⁴⁸-Werte zu speichern, können Sie eine KZG-Verpflichtung zu einer Liste von 2²⁴-Werten eingehen, von denen jeder selbst eine KZG-Verpflichtung zu 2²⁴-Werten ist. Verkle-Bäume werden <a href="https://notes.ethereum.org/@vbuterin/verkle_tree_eip">stark für den Ethereum-Zustandsbaum in Betracht gezogen, da Verkle-Bäume verwendet werden können, um Schlüssel-Wert-Karten und nicht nur Listen zu speichern (im Grunde können Sie einen Baum der Größe 2²⁵⁶ erstellen, ihn aber leer beginnen und nur bestimmte Teile des Baums ausfüllen, wenn Sie sie tatsächlich füllen müssen).

Wie ein Verkle-Baum aussieht. In der Praxis können Sie jedem Knoten eine Breite von 256 == 2⁸ für IPA-basierte Bäume oder 2²⁴ für KZG-basierte Bäume zuweisen.

Die Nachweise in Verkle-Bäumen sind etwas länger als in KZG; Sie können einige hundert Byte lang sein. Sie sind auch schwer zu überprüfen, vor allem, wenn Sie versuchen, viele Beweise zu einem zu aggregieren.

Realistisch betrachtet sollten Verkle-Bäume als wie Merkle-Bäume betrachtet werden, aber ohne SNARKing praktikabler (wegen der geringeren Datenkosten) und billiger mit SNARKing (wegen der niedrigeren Beweiskosten).

Der größte Vorteil von Verkle-Bäumen ist die Möglichkeit, Datenstrukturen zu harmonisieren: Verkle-Proofs können direkt über dem L1- oder L2-Zustand verwendet werden, ohne Überlagerungsstrukturen und mit genau demselben Mechanismus für L1 und L2. Sobald Quantencomputer ein Problem darstellen oder der Nachweis erbracht ist, dass Merkle-Zweige effizient genug sind, könnten Verkle-Bäume an Ort und Stelle durch einen binären Hash-Baum mit einer geeigneten SNARK-freundlichen Hash-Funktion ersetzt werden.

Aggregation

Wenn N Benutzer N Transaktionen (oder realistischer, N ERC-4337 UserOperations) durchführen, die N Cross-Chain-Behauptungen beweisen müssen, können wir eine Menge Gas sparen, indem wir diese Beweise aggregieren: Der Builder, der diese Transaktionen zu einem Block oder Bündel kombinieren würde, der in einen Block geht, kann einen einzigen Beweis erstellen, der alle diese Behauptungen gleichzeitig beweist.

Dies könnte bedeuten:

In allen drei Fällen würden die Proofs jeweils nur ein paar hunderttausend Gas kosten. Der Ersteller müsste eine davon auf jeder L2 für die Benutzer in dieser L2 erstellen. Damit dies nützlich ist, muss das Schema als Ganzes so weit genutzt werden, dass es sehr oft mindestens ein paar Transaktionen innerhalb desselben Blocks auf mehreren großen L2s gibt.

Wenn ZK-SNARKs verwendet werden, sind die Hauptgrenzkosten einfach die "Geschäftslogik" der Nummernweitergabe zwischen den Verträgen, also vielleicht ein paar tausend L2-Gas pro Benutzer. Wenn KZG-Multi-Proofs verwendet werden, müsste der Prüfer 48 Gas für jeden Keystore-haltenden L2 hinzufügen, der innerhalb dieses Blocks verwendet wird, so dass die Grenzkosten des Schemas pro Benutzer weitere ~800 L1-Gas pro L2 (nicht pro Benutzer) hinzufügen würden. Diese Kosten sind jedoch viel niedriger als die Kosten für die Nicht-Aggregation, die unweigerlich über 10.000 L1-Gas und Hunderttausende von L2-Gas pro Benutzer mit sich bringen. Für Verkle-Bäume können Sie entweder direkt Verkle-Multi-Proofs verwenden, indem Sie etwa 100-200 Bytes pro Benutzer hinzufügen, oder Sie können einen ZK-SNARK aus einem Verkle-Multi-Proof erstellen, der ähnliche Kosten wie ZK-SNARKs von Merkle-Zweigen hat, aber deutlich billiger zu beweisen ist.

Aus Sicht der Implementierung ist es wahrscheinlich am besten, wenn Bundler Cross-Chain-Proofs über den ERC-4337-Kontoabstraktionsstandard aggregieren. ERC-4337 verfügt bereits über einen Mechanismus, mit dem Entwickler Teile von UserOperations auf benutzerdefinierte Weise aggregieren können. Es gibt sogar eine <a href="https://hackmd.io/@voltrevo/BJ0QBy3zi">Implementierung für die BLS-Signaturaggregation, die die Gaskosten auf L2 um das 1,5- bis 3-fache senken könnte, je nachdem, welche anderen Formen der Kompression enthalten sind.

Diagramm aus einem <a href="https://hackmd.io/@voltrevo/BJ0QBy3zi">BLS-Wallet-Implementierungsbeitrag, der den Workflow von BLS-aggregierten Signaturen in einer früheren Version von ERC-4337 zeigt. Der Workflow zum Aggregieren von Cross-Chain-Proofs wird wahrscheinlich sehr ähnlich aussehen.

Direktes Auslesen des Zustands

Eine letzte Möglichkeit, die nur für L2 verwendet werden kann, die L1 liest (und nicht L1, die L2 liest), besteht darin, L2s so zu modifizieren, dass sie statische Aufrufe von Kontrakten auf L1 direkt ausführen können.

Dies kann mit einem Opcode oder einem Vorkompilat erfolgen, das Anrufe in L1 ermöglicht, wobei Sie die Zieladresse, Gas und Anrufdaten angeben, und es gibt die Ausgabe zurück, obwohl diese Aufrufe statische Aufrufe sind, können sie keinen L1-Zustand ändern. L2s müssen L1 bereits kennen, um Einlagen zu verarbeiten, also gibt es nichts Grundsätzliches, was die Implementierung einer solchen Sache verhindert; Es handelt sich hauptsächlich um eine technische Herausforderung bei der Implementierung (siehe: diese Ausschreibung von Optimism zur Unterstützung statischer Aufrufe in L1).

Beachten Sie, dass, wenn sich der Keystore auf L1 befindet und L2s die statische Anruffunktion von L1 integrieren, überhaupt keine Nachweise erforderlich sind! Wenn L2s jedoch keine statischen L1-Aufrufe integrieren oder wenn sich der Keystore auf L2 befindet (was möglicherweise irgendwann der Fall sein muss, wenn L1 für Benutzer zu teuer wird, um es auch nur ein bisschen zu verwenden), dann sind Nachweise erforderlich.

Wie lernt L2 die aktuelle Ethereum-Zustandswurzel?

Alle oben genannten Schemata erfordern, dass L2 entweder auf den aktuellen L1-Statusstamm oder auf den gesamten aktuellen L1-Status zugreift. Glücklicherweise verfügen alle L2s bereits über einige Funktionen, um auf den aktuellen L1-Status zuzugreifen. Dies liegt daran, dass sie eine solche Funktionalität benötigen, um Nachrichten zu verarbeiten, die von L1 bis L2 eingehen, insbesondere Einzahlungen.

Und tatsächlich, wenn ein L2 eine Einzahlungsfunktion hat, dann können Sie dieses L2 unverändert verwenden, um L1-Zustandswurzeln in einen Vertrag auf L2 zu verschieben: Lassen Sie einfach einen Vertrag auf L1 den BLOCKHASH-Opcode aufrufen und übergeben Sie ihn als Einzahlungsnachricht an L2. Der vollständige Blockheader kann auf der L2-Seite empfangen und sein Zustandsstamm extrahiert werden. Es wäre jedoch viel besser, wenn jede L2 eine explizite Möglichkeit hätte, entweder direkt auf den vollständigen aktuellen L1-Status oder auf die aktuellen L1-Statusstämme zuzugreifen.

Die größte Herausforderung bei der Optimierung der Art und Weise, wie L2s aktuelle L1-Zustandswurzeln empfangen, besteht darin, gleichzeitig Sicherheit und niedrige Latenz zu erreichen:

  • Wenn L2s die Funktionalität des "direkten Lesens von L1" auf eine faule Art und Weise implementieren und nur die endgültigen L1-Zustandswurzeln lesen, dann beträgt die Verzögerung normalerweise 15 Minuten, aber im Extremfall von Inaktivitätslecks (die Sie tolerieren müssen) kann die Verzögerung mehrere Wochen betragen.
  • L2s kann durchaus so konzipiert werden, dass es viel neuere L1-Zustandswurzeln liest, aber da L1 rückgängig gemacht werden kann (selbst bei Finalität eines einzelnen Slots können Reverts während Inaktivitätslecks auftreten), müsste L2 auch in der Lage sein, zurückzukehren. Das ist aus Sicht des Software-Engineerings eine technische Herausforderung, aber zumindest Optimism verfügt bereits über diese Fähigkeit.
  • Wenn Sie die Deposit-Bridge verwenden, um L1-State-Wurzeln in L2 zu bringen, dann kann die einfache wirtschaftliche Rentabilität eine lange Zeit zwischen den Deposit-Aktualisierungen erfordern: Wenn die vollen Kosten einer Einlage 100.000 Gas betragen und wir davon ausgehen, dass ETH bei 1800 USD liegt und die Gebühren bei 200 Gwei liegen und L1-Wurzeln einmal pro Tag in L2 eingebracht werden, Das wären Kosten von 36 US-Dollar pro L2 pro Tag oder 13148 US-Dollar pro L2 pro Jahr für die Wartung des Systems. Mit einer Verzögerung von einer Stunde steigt das auf 315.569 US-Dollar pro L2 und Jahr. Im besten Fall deckt ein ständiges Rinnsal ungeduldiger, wohlhabender Nutzer die Update-Gebühren und hält das System für alle anderen auf dem neuesten Stand. Im schlimmsten Fall müsste irgendein altruistischer Akteur selbst dafür bezahlen.
  • "Orakel" (zumindest die Art von Technologie, die einige DeFi-Leute "Orakel" nennen) sind hier keine akzeptable Lösung: Die Verwaltung von Wallet-Schlüsseln ist eine sehr sicherheitskritische Low-Level-Funktionalität und sollte daher höchstens von ein paar Teilen einer sehr einfachen, kryptographisch vertrauenswürdigen Low-Level-Infrastruktur abhängen.

Zusätzlich in die entgegengesetzte Richtung (L1s, die L2 liest):

  • Bei optimistischen Rollups dauert es aufgrund der Verzögerung mit der Betrugssicherheit eine Woche, bis die State Roots L1 erreichen. Bei ZK-Rollups dauert es aufgrund einer Kombination aus Testzeiten und wirtschaftlichen Grenzen vorerst einige Stunden, obwohl zukünftige Technologien dies reduzieren werden.
  • Vorbestätigungen (von Sequenzern, Attestern usw.) sind keine akzeptable Lösung für L1-Lesung von L2. Die Wallet-Verwaltung ist eine sehr sicherheitskritische Low-Level-Funktionalität, und daher muss das Sicherheitsniveau der L2->-L1-Kommunikation absolut sein: Es sollte nicht einmal möglich sein, eine falsche L1-State-Root zu pushen, indem man das L2-Validator-Set übernimmt. Die einzigen State-Roots, denen L1 vertrauen sollte, sind State-Roots, die vom State-Root-Holding-Vertrag der L2 auf L1 als endgültig akzeptiert wurden.

Einige dieser Geschwindigkeiten für vertrauenswürdige Cross-Chain-Operationen sind für viele DeFi-Anwendungsfälle inakzeptabel langsam. In diesen Fällen benötigen Sie schnellere Bridges mit unvollkommeneren Sicherheitsmodellen. Für den Anwendungsfall der Aktualisierung von Wallet-Schlüsseln sind längere Verzögerungen jedoch akzeptabler: Sie verzögern Transaktionen nicht um Stunden, sondern um Schlüsseländerungen. Sie müssen nur die alten Schlüssel länger aufbewahren. Wenn Sie Schlüssel ändern, weil Schlüssel gestohlen wurden, haben Sie eine erhebliche Anfälligkeit, die jedoch gemildert werden kann, z. durch Wallets mit einer Freeze-Funktion.

Letztendlich besteht die beste Lösung zur Minimierung der Latenz darin, dass L2s das direkte Lesen von L1-Zustandswurzeln auf optimale Weise implementiert, wobei jeder L2-Block (oder das Zustandsstammberechnungsprotokoll) einen Zeiger auf den letzten L1-Block enthält, sodass L2 ebenfalls zurückkehren kann, wenn L1 zurückgesetzt wird. Keystore-Verträge sollten entweder im Mainnet oder auf L2-Verträgen platziert werden, die ZK-Rollups sind und sich daher schnell an L1 binden können.

Blöcke der L2-Kette können nicht nur von vorherigen L2-Blöcken, sondern auch von einem L1-Block abhängig sein. Wenn L1 über einen solchen Link hinaus zurückkehrt, wird auch L2 zurückgesetzt. Es ist erwähnenswert, dass dies auch die Art und Weise ist, wie eine frühere Version von Sharding (vor Dank) funktionieren sollte. Code finden Sie hier .

Wie viel Verbindung zu Ethereum benötigt eine andere Chain, um Wallets zu halten, deren Keystores auf Ethereum oder einem L2 basieren?

Überraschenderweise nicht so sehr. Es muss eigentlich nicht einmal ein Rollup sein: Wenn es sich um ein L3 oder ein Validium handelt, dann ist es in Ordnung, Wallets dort zu halten, solange Sie Keystores entweder auf L1 oder auf einem ZK-Rollup halten. Was Sie brauchen, ist, dass die Chain direkten Zugang zu den Wurzeln des Ethereum-Staates hat und ein technisches und soziales Engagement, um bereit zu sein, sich neu zu organisieren, wenn Ethereum neu organisiert wird, und eine Hard Fork, wenn Ethereum hart abgespalten wird.

Ein interessantes Forschungsproblem besteht darin, herauszufinden, inwieweit es möglich ist, dass eine Kette diese Form der Verbindung mit mehreren anderen Ketten (z. Ethereum und Zcash). Es ist möglich, es naiv zu machen: Ihre Chain könnte sich darauf einigen, sich neu zu organisieren, wenn Ethereum oder Zcash reorganisiert werden (und eine Hard Fork, wenn Ethereum oder Zcash eine Hard Fork hat), aber dann haben Ihre Node-Betreiber und Ihre Community im Allgemeinen doppelt so viele technische und politische Abhängigkeiten. Daher könnte eine solche Technik verwendet werden, um eine Verbindung zu einigen anderen Ketten herzustellen, jedoch zu steigenden Kosten. Schemes, die auf ZK-Bridges basieren, haben attraktive technische Eigenschaften, aber sie haben die entscheidende Schwäche, dass sie nicht robust gegenüber 51%-Angriffen oder Hard Forks sind. Vielleicht gibt es cleverere Lösungen.

Wahrung der Privatsphäre

Im Idealfall wollen wir auch die Privatsphäre wahren. Wenn Sie viele Wallets haben, die vom selben Keystore verwaltet werden, möchten wir sicherstellen:

  • Es ist nicht öffentlich bekannt, dass diese Wallets alle miteinander verbunden sind.
  • Die Hüter der sozialen Wiederherstellung erfahren nicht, was die Adressen sind, die sie bewachen.

Dies führt zu einigen Problemen:

  • Wir können Merkle-Proofs nicht direkt verwenden, da sie die Privatsphäre nicht wahren.
  • Wenn wir KZG oder SNARKs verwenden, muss der Beweis eine verblindete Version des Verifizierungsschlüssels enthalten, ohne den Speicherort des Verifizierungsschlüssels preiszugeben.
  • Wenn wir Aggregation verwenden, sollte der Aggregator den Speicherort nicht im Klartext lernen. Vielmehr sollte der Aggregator verblindete Beweise erhalten und eine Möglichkeit haben, diese zu aggregieren.
  • Wir können die "Light-Version" (verwenden Sie Cross-Chain-Proofs nur zum Aktualisieren von Schlüsseln) nicht verwenden, da dies zu einem Datenschutzleck führt: Wenn viele Wallets aufgrund eines Aktualisierungsvorgangs gleichzeitig aktualisiert werden, verliert das Timing die Information, dass diese Wallets wahrscheinlich miteinander verbunden sind. Wir müssen also die "schwere Version" (Cross-Chain-Proofs für jede Transaktion) verwenden.

Mit SNARKs sind die Lösungen konzeptionell einfach: Beweise verbergen standardmäßig Informationen, und der Aggregator muss ein rekursives SNARK erzeugen, um die SNARKs zu beweisen.

Die größte Herausforderung dieses Ansatzes besteht heute darin, dass der Aggregator für die Aggregation ein rekursives SNARK erstellen muss, was derzeit recht langsam ist.

Mit KZG können wir <a href="https://notes.ethereum.org/@vbuterin/non_index_revealing_proof">this verwenden. Arbeit an nicht-index-offenbaren KZG-Beweisen (siehe auch: eine formalisiertere Version dieser Arbeit im Caulk-Papier ) als Ausgangspunkt. Die Aggregation von verblindeten Beweisen ist jedoch ein offenes Problem, das mehr Aufmerksamkeit erfordert.

Das direkte Lesen von L1 aus L2 bewahrt leider nicht die Privatsphäre, obwohl die Implementierung der Funktion zum direkten Lesen immer noch sehr nützlich ist, sowohl um die Latenz zu minimieren als auch wegen ihrer Nützlichkeit für andere Anwendungen.

Zusammenfassung

  • Um Cross-Chain-Social-Recovery-Wallets zu haben, ist der realistischste Workflow eine Wallet, die einen Keystore an einem Ort und Wallets an vielen Standorten unterhält, wobei die Wallet den Keystore liest, entweder (i) um ihre lokale Ansicht des Verifizierungsschlüssels zu aktualisieren, oder (ii) während des Prozesses der Verifizierung jeder Transaktion.
  • Ein wichtiger Bestandteil, um dies zu ermöglichen, sind Cross-Chain-Proofs. Wir müssen diese Beweise stark optimieren. Entweder ZK-SNARKs, die auf Verkle-Proofs warten, oder eine maßgeschneiderte KZG-Lösung scheinen die besten Optionen zu sein.
  • Längerfristig werden Aggregationsprotokolle, bei denen Bundler aggregierte Proofs generieren, um ein Bündel aller von Benutzern übermittelten UserOperations zu erstellen, erforderlich sein, um die Kosten zu minimieren. Dies sollte wahrscheinlich in das ERC-4337-Ökosystem integriert werden, obwohl wahrscheinlich Änderungen an ERC-4337 erforderlich sein werden.
  • L2s sollte optimiert werden, um die Latenz beim Lesen des L1-Zustands (oder zumindest des Zustandsstamms) aus dem L2 zu minimieren. L2s direkt das Lesen des L1-Zustands ist ideal und kann Beweisplatz sparen.
  • Wallets können nicht nur auf L2s sein; Sie können Wallets auch auf Systemen mit geringerer Verbindung zu Ethereum platzieren (L3s oder sogar separate Chains, die sich nur darauf einigen, Ethereum-State-Roots und Reorg oder Hard Fork einzubeziehen, wenn Ethereum reorganisiert oder hardforks wird).
  • Keystores sollten sich jedoch entweder auf L1 oder auf dem hochsicheren ZK-Rollup L2 befinden. Auf L1 zu sein, spart viel Komplexität, obwohl selbst das auf lange Sicht zu teuer sein kann, daher die Notwendigkeit von Keystores auf L2.
  • Die Wahrung der Privatsphäre erfordert zusätzliche Arbeit und erschwert einige Optionen. Allerdings sollten wir uns wahrscheinlich sowieso auf Lösungen zubewegen, die die Privatsphäre schützen, und zumindest sicherstellen, dass alles, was wir vorschlagen, mit dem Schutz der Privatsphäre kompatibel ist.

Verzichtserklärung:

  1. Dieser Artikel ist ein Nachdruck von [vitalik], Alle Urheberrechte liegen beim ursprünglichen Autor [Vitalik Buterin]. Wenn es Einwände gegen diesen Nachdruck gibt, wenden Sie sich bitte an das Gate Learn-Team , das sich umgehend darum kümmern wird.
  2. Haftungsausschluss: Die in diesem Artikel geäußerten Ansichten und Meinungen sind ausschließlich die des Autors und stellen keine Anlageberatung dar.
  3. Übersetzungen des Artikels in andere Sprachen werden vom Gate Learn-Team durchgeführt. Sofern nicht anders angegeben, ist das Kopieren, Verbreiten oder Plagiieren der übersetzten Artikel verboten.
Jetzt anfangen
Registrieren Sie sich und erhalten Sie einen
100
-Euro-Gutschein!