Eine Hot-Wallet durch Primitive von Substrate erstellen
Substrate und das für die Laufzeitentwicklung konzipierte FRAME-System stellen ein leistungsfähiges Set an Tools für den Aufbau einer Blockchain-Infrastruktur durch primitive Funktionen zur Verfügung. Gemeinsam eingesetzt, schaffen sie neue Ansätze für bestehende Probleme. In diesem Artikel wird eine reale Anwendung beschrieben, bei der die Funktionen von Substrate zur Implementierung einer Hot-Wallet mit Mehrfachadressen verwendet werden.
Eine Hot-Wallet bedeutet in der Regel, dass die Ausgabeschlüssel auf einem Online-Gerät aufbewahrt werden, so dass Transaktionen bequem durchgeführt, aber typischerweise mit höherem Risiko übertragen werden können. In diesem Artikel werden einige der Kontoabstraktionen von Substrate untersucht - Konten mit Mehrfachsignaturen, Proxy-Konten und derivative Konten -, die es uns ermöglichen, eine Hot-Wallet zu konstruieren, die Millionen von Adressen absichern könnte.
Eine solche Wallet wäre nützlich, wenn Sie Token für mehrere Benutzerkonten halten müssen, aber jedem Kunden seine eigene Einzahlungsadresse geben wollen. Die triviale Lösung wäre, für jeden Kunden eine neue Depotadresse zu erzeugen, indem man ein neues Schlüsselpaar generiert. Aber die Handhabung all dieser Schlüssel erweist sich schnell als problematisch. Was ist, wenn Sie zehn- oder hunderttausende von Benutzern betreuen müssen? Mit den Kontoabstraktionen von Substrate können wir eine Lösung bereitstellen, die sowohl skalierbar als auch mehr Sicherheit bietet.
Ursprünge und Konto-IDs
Bevor wir mit dem Aufbau der Hot-Wallet beginnen, müssen wir die Grundlagen schaffen, auf denen sie basieren wird. Wenn ein Benutzer mit einer Blockchain interagiert, ruft er eine Funktion auf; die Menge dieser "versendbaren" Funktionen bildet die Schnittstelle der Blockchain.
Da versendbare Funktionen von der Außenwelt aufgerufen werden, ist das erste, was die Blockchain interessieren könnte, wer die Funktion tatsächlich aufgerufen hat. Zum einen muss eine Funktion prüfen, ob der Aufrufer die Berechtigung hat, diese Funktion auszuführen. Zweitens muss die Blockchain möglicherweise genau wissen, wer die Funktion aufgerufen hat, um einige Informationen über den Aufrufer zu aktualisieren. Handelt es sich bei dem Aufrufer um ein Konto, muss die Blockchain möglicherweise den Kontostand aktualisieren, z. B. um eine Transaktionsgebühr abzuziehen.
Sie fragen sich vielleicht: "Was meinen Sie, wenn der Aufrufer ein Konto ist?" Funktionen in Substrate kommen nicht von Konten an sich, sondern von Ursprüngen. Das Governance-System von Polkadot verfügt beispielsweise über eine Reihe spezieller Ursprünge, die über Privilegien wie die Zuweisung von Finanzmitteln oder die Aufhebung von sogenannten Slashes verfügen. Wenn Sie Ihre eigene Blockchain mit Substrate entwerfen, können Sie Ihre eigenen benutzerdefinierten Ursprünge erstellen. Für diesen Artikel sollten Sie jedoch bedenken, dass ein Konto lediglich eine Variante eines Ursprungs von Substrate ist. Man kann sich das so vorstellen, dass Substrate der versendbaren Funktion mitteilt: "Der Ursprung dieser Sendung ist ein Konto."
Nachdem wir nun den ersten Schritt der Abstraktion vollzogen haben, brauchen wir eine Möglichkeit, der Funktion mitzuteilen, auf welches Konto sich der Ursprung bezieht. Wenn Sie bereits eine Blockchain genutzt haben, sind Sie vermutlich damit vertraut, dass eine Konto-ID der öffentliche Schlüssel ist, der einem privaten Schlüssel entspricht. Keine Sorge, das funktioniert auch in Substrate. In diesem Sinne wird ein Konto durch den öffentlichen Schlüssel identifiziert und durch den entsprechenden privaten Schlüssel autorisiert.
Substrate unterstützt jedoch mehr Abstraktion. Eine Konto-ID kann eine beliebige 32-Byte-Zahl sein.[1] Sie könnte der öffentliche Schlüssel sein, der einem privaten Schlüssel entspricht, muss es aber nicht. Es braucht nur eine Methode zur Autorisierung. Das heißt, es muss eine eindeutige Möglichkeit geben, diese kontoidentifizierende Nummer zu generieren, damit Substrate den oben begonnenen Satz vervollständigen kann: "Der Ursprung dieser Sendung ist ein Konto, das durch diese Nummer identifiziert wird."[2]
Hash-Funktionen
Hash-Funktionen tauchen in der Blockchain immer wieder auf. Die Blöcke sind wortwörtlich über ihre Hashes miteinander verknüpft. Aber wir werden die Eigenschaften von Hash-Funktionen für zwei weitere Zwecke nutzen: die Erzeugung von Konto-IDs und die Identifizierung von Funktionsaufrufen.
Eine Hash-Funktion nimmt eine Eingabe beliebiger Größe an und bildet sie auf eine Ausgabe fester Größe ab, z. B. 32 Byte. Aber sie ordnet nicht einfach nur Daten auf eine beliebige Zahl von 32 Byte zu, sondern sie sollte eindeutige Daten deterministisch auf eine eindeutige Zahl abbilden. Zufälligerweise können 32 Byte eine astronomisch große Anzahl an Elementen erfassen[3].
Wir könnten zum Beispiel einige Informationen über eine Blockchain wie "polkadot-treasury" nehmen und diese mit Hilfe einer Hash-Funktion in eine Konto-ID (32 Byte) umwandeln. Oder wir nehmen die Informationen über eine Transaktion, z. B. "Überweise 10 Einheiten auf Konto 123...", und vertrauen darauf, dass der Hash ein eindeutiges Abbild dieser Informationen ist.
Multisig-Konten
Nachdem das geklärt ist, können wir mit dem ersten Teil unserer Hot-Wallet beginnen: einem Multisig-Konto. Multisig-Konten erscheinen vielleicht nicht als Teil einer Hot-Wallet, weil sie im Allgemeinen komplex erscheinen, aber dieses Konto dient als Sicherheitsgrundlage für den Rest der Komponenten, und die besagte Komplexität beeinträchtigt die alltägliche Nutzung nicht.
Einige Blockchains verwenden kryptografische Multisig-Mechanismen, bei dem mehrere Schlüsselbesitzer eine einzelne Transaktion außerhalb der Blockchain signieren, bevor sie die Transaktion auf der Blockchain einreichen. Das Multisig-System, das mit FRAME von Substrate geliefert wird, funktioniert auf eine andere Art und Weise: Es generiert eine Konto-ID auf der Grundlage der aus der Multisig bestehenden Einzelkonten und den erforderlichen Schwellenwert, der für den Versand von dem generierten Konto erforderlich ist. Substrate fügt all diesen Informationen ein spezielles Multisig-Präfix hinzu und verschlüsselt es, um eine einzige 32-Byte-Ausgabe zu erhalten, die als Multisig-Konto-ID verwendet wird. Beachten Sie, dass diese Konto-ID nicht mit einem privaten Schlüssel verknüpft ist.
Um eine Transaktion mit dieser neuen Konto-ID zu autorisieren, übermittelt jedes Mitglied der Multisig eine Transaktion auf der Blockchain mit dem Funktionsaufruf, den das Multisig-Konto ausführen soll. Es ist jedoch nicht effizient, wenn jeder den Funktionsaufruf übermittelt; er könnte sehr umfangreich sein und der Blockspeicher ist knapp (und daher teuer). Auch hier kommen Hash-Funktionen ins Spiel: Nur eines der einzelnen Konten muss den eigentlichen Funktionsaufruf übermitteln; die anderen übermitteln nur den Hash. Sie sagen: "Wir sind damit einverstanden, die Funktion mit diesem Hash vom Multisig-Konto aufzurufen", und brauchen die Funktion nicht erneut zu übermitteln.
Dieses Multisig-System allein ist für den Einsatz als Hot-Wallet zu umständlich, da es mehrere Schlüsselbesitzer benötigt, um Transaktionen zu übermitteln, damit es funktioniert. Es ist jedoch sehr sicher und dient als Basiskonto, das wir in eine Hot-Wallet umwandeln können, ohne seine Sicherheit zu beeinträchtigen.
Proxy-Konten
Proxy-Konten ermöglichen es der Multisig-Adresse, die Ausgabebefugnis an ein anderes Konto zu delegieren, das dann als Hot-Wallet dient, während die Multisig-Adresse weiterhin abgesichert bleibt. Wir werden einen Zeitverzögerungs-Proxy für die Verwaltung der Ausgaben und einen anderen (oder mehrere) Instant-Proxys zur Kontrolle der Sicherheit für dieses Multisig-Konto einrichten.
Ein Proxy-Konto gibt einem anderen Konto bestimmte Privilegien, um in seinem Namen Funktionsaufrufe zu tätigen. Diese Privilegien können spezifisch sein, z. B. "nur Transaktionen im Zusammenhang mit Staking", oder weit gefasst, z. B. "alle Transaktionen, bei denen kein Geld überwiesen wird", oder sogar umfassende Privilegien, z. B. "jede Transaktion".
Um eine Vollmacht einzurichten, ist lediglich eine Transaktion des Kontos, das die Vollmacht erhalten soll, erforderlich, in der angegeben wird, welches andere Konto die Vollmacht erhalten soll und welche Rechte es hat. Sobald die Proxy-Beziehung eingerichtet ist, kann das Proxy-Konto Transaktionen für das bevollmächtigte Konto durchführen, indem es der Blockchain im Wesentlichen mitteilt: "Ich bin ein Proxy für dieses Konto, ich habe diese Rechte, und ich möchte diesen Funktionsaufruf im Namen des bevollmächtigten Kontos versenden." Die Logik der Blockchain überprüft, ob der Bevollmächtigte über die nötigen Berechtigungen verfügt, und sendet die Funktion mit dem Ursprung des bevollmächtigten Kontos.
Durch das Hinzufügen einer Zeitverzögerung wird eine zusätzliche Sicherheitsebene geschaffen. Stellen Sie sich eine Zeitverzögerung von 600 Blöcken vor (eine Stunde im Polkadot-Ökosystem). Das Proxy-Konto würde immer noch eine Transaktion übermitteln, die besagt, dass es ein Proxy mit einigen Privilegien ist, aber es würde nur den Hash der Funktion bekannt geben, die es aufrufen möchte. Der Eigentümer des Proxy-Kontos kann den tatsächlichen Funktionsaufruf anfordern und überprüfen. Ist er damit nicht einverstanden, kann er den Funktionsaufruf ablehnen, indem er vor Ablauf der Zeitspanne eine weitere Transaktion übermittelt. Nach Ablauf der Verzögerungszeit kann der Bevollmächtigte den eigentlichen Funktionsaufruf, der der Ankündigung entspricht, übermitteln, und Substrate sendet ihn ab[4].
In unserem Anwendungsfall werden die Inhaber von Multisig-Schlüsseln eine Transaktion durchführen, um ein anderes Konto als Zeitverzögerungs-Proxy mit vollen Rechten, einschließlich Überweisungen, einzurichten. Dieses Proxy-Konto könnte sich auf einem Online-Server befinden, der eigenständig Transaktionen durchführt. Bei jeder Transaktion muss es zunächst den Hash bekannt geben und dann den eigentlichen Funktionsaufruf an einen anderen Kontoinhaber senden (der Einfachheit halber betrachten wir diesen anderen Kontoinhaber als Mitglied der Multisig), der überprüfen kann, ob der Funktionsaufruf nicht bösartig ist. Wenn dies der Fall ist, kann die Multisig rechtzeitig eine Transaktion durchführen, um den Aufruf abzulehnen, und aus Vorsicht entscheiden, dass das Proxy-Konto kompromittiert wurde, und es entfernen.
Dieses System funktioniert tatsächlich, aber wir können es noch bequemer machen. Bei der Verwendung eines einzigen Proxy-Kontos könnte eine lange Zeitverzögerung erforderlich sein, da es schwierig sein kann, genügend Inhaber von Multisig-Schlüsseln zu koordinieren, um eine Ablehnungstransaktion kurzfristig durchzuführen. Aber ein Konto kann mehrere Proxy-Konten mit unterschiedlichen Berechtigungen haben. Um dieses Problem zu lösen, setzen Sie jeden Multisig-Schlüsselinhaber als Proxy mit Nicht-Übertragungsrechten, insbesondere mit dem Recht, Ankündigungen vom Proxy mit Zeitverzögerung abzulehnen.
Lassen Sie uns diese Konfiguration zusammenfassen. Unser Kernstück bildet ein Multisig-Konto.. Dieses Konto verfügt nicht über einen privaten Schlüssel, aber es hat zwei Möglichkeiten, ihn zu kontrollieren: durch die Verwendung eines Proxy-Kontos mit Zeitverzögerungs oder durch die Zusammenführung einer ausreichenden Anzahl von Signatoren der Mitgliedskonten. Jedes Mitglied des Multisig-Kontos hat auch die Möglichkeit, Transaktionen des voll privilegierten Proxy-Kontos abzulehnen, kann aber keine Überweisungen vornehmen, solange sich nicht andere Mitglieder zur Durchführung einer Multisig-Transaktion bereit erklären.
Dabei handelt es sich um eine voll funktionsfähige Hot-Wallet, die den sogenannten Hot-Key (das voll privilegierte Proxy-Konto) ändern kann, ohne ihre Adresse (das Multisig-Konto) zu ändern, indem sie einfach den Proxy entfernt und einen neuen einrichtet. Unsere ursprüngliche Problemstellung erforderte jedoch eindeutige Einzahlungsadressen für mehrere zehntausend Benutzer, und bisher haben wir nur eine.
Derivative Konten
Bisher haben wir mehrere Möglichkeiten genutzt, um auf ein Multisig-Konto zuzugreifen; jetzt werden wir ein Konto nutzen, um auf viele zuzugreifen.
Jedes Konto hat in Substrate einen Baum von derivativen Konten, auf die es zugreifen kann. Um die Konto-IDs zu bestimmen, verwendet Substrate einen Hash-Algorithmus, was an dieser Stelle keine Überraschung sein sollte. Durch Hashing der Konto-ID des aufrufenden Kontos mit dem gewünschten Index und einem abgeleiteten Präfix erstellt Substrate eine neue Konto-ID. Ein Beispiel: Der Absender gibt einen Funktionsaufruf und einen Index an und sagt: "Ich möchte diese Funktion von meinem derivativen Konto mit diesem Index senden."
Sie sehen wahrscheinlich, worauf das hinausläuft. Der Besitzer der Wallet kann jedem seiner Benutzer einen Index zuweisen und die ID des Derivatkontos als Einzahlungsadresse für diesen Benutzer angeben. Um auf die Gelder zuzugreifen, würde die Proxy-Adresse eine Transaktion durchführen, um Gelder von der Derivat-Adresse des Multisig-Kontos zu überweisen.
Praktisch gesehen ist der Index auf 16 Bits bzw. 65.536 Derivatkonten begrenzt, aber auch eine Verschachtelung ist möglich. Das heißt, jedes Derivatkonto kann einen eigenen Satz von 65.536 Derivatkonten haben usw. Die zweite Ebene dieses Baums würde über vier Milliarden Konten umfassen.
Das vollständige Bild
Lassen Sie uns dies endlich umsetzen. Stellen Sie sich vor, der Nutzer mit Index 11 zahlt an Sie und Sie haben ein "Sparkonto", auf das Sie das Geld einzahlen möchten. Die vollständige Transaktion würde wie folgt aussehen: "Ich bin ein Bevollmächtigter für das Multisig-Konto und möchte Geld vom Derivatkonto des Multisig mit Index 11 auf das Sparkonto überweisen."
Unter der Annahme, dass für die zuständigen Verwaltungsstellen alles in Ordnung ist, würde die Zeitverzögerung ablaufen, und der Bevollmächtigte könnte die vollständige Transaktion übermitteln. Sollten die Mitglieder der Multisig jemals der Meinung sein, dass der Hot-Key geändert werden muss, können sie einfach einen neuen generieren und den alten als Stellvertreter entfernen, ohne dass die Multisig oder eine ihrer derivativen Adressen davon betroffen ist.
Die obige Abbildung zeigt ein Diagramm der von uns eingerichteten Wallet: Eine Multisig (MS) wird durch einen Satz von n Schlüsseln (mit k gekennzeichnet) gesteuert und setzt einen Proxy mit Zeitverzögerung (H) als Hot-Key. Von der Multisig können praktisch unbegrenzt viele Adressen abgeleitet werden (die Menge d).
Wir können diesen Arbeitsablauf sogar noch weiter optimieren. Substrate bietet auch eine Funktion zum Senden eines Stapels von Funktionsaufrufen. Wenn Benutzer regelmäßig Einzahlungen auf ihre Derivatkonten vornehmen und von diesen abheben, können Sie diese in einem einzigen Stapel von Überweisungen versenden.
Die sich auf der Blockchain befindende Kontoabstraktionen von Substrate bieten leistungsstarke Möglichkeiten zur Verwaltung von Konten. Durch die Verringerung der Anzahl der tatsächlich benötigten Schlüssel und den Zugriff auf Konten auf der Grundlage formaler Regeln anstelle von privaten Schlüsseln, können Sie hunderttausende Konten verwalten, ohne sich mit den Einschränkungen der Speicherung einer entsprechenden Anzahl von Signierschlüsseln auseinandersetzen zu müssen. Dieser Artikel konzentrierte sich nur auf ein Beispiel, und zwar den Aufbau einer Hot-Wallet, aber alle Abstraktionen sind isoliert und können in fortgeschrittenere Anwendungen eingebaut werden.
- Es müssen nicht unbedingt 32 Bytes sein. Sie können Ihre Runtime mit allem erstellen, wonach Ihnen der Sinn steht aber ich möchte nicht, dass dieser Artikel mehr als nötig in die Laufzeitentwicklung abschweift. ︎
- Eine kurze Unterbrechung zum Wort "einzigartig", das ich in einem strengeren Sinne als die durchschnittliche Wörterbuchdefinition meine. Eine Funktion ist nicht einzigartig, wenn es nur eine einzige Darstellung von ihr gibt, sondern wenn alle Darstellungen (oder Reihen von Darstellungen) nachweislich gleichwertig sind. Es könnte eine unendliche Anzahl von Methoden geben, um eine bestimmte Zahl (Konto) zu erzeugen, aber solange alle diese Methoden dasselbe Konto erzeugen, kann dieses Konto als einzigartig angesehen werden. Wenn man diesen Weg weiterverfolgt, kommt man zu der Art von Mathematik, die einen nachts wachhält. Wir werden jedoch Konto-IDs erzeugen und sie zwischen Funktionen weitergeben, und das Wichtigste dabei ist, dass egal, wie viele Funktionen wir aneinanderreihen, um eine Konto-ID zu erreichen, sie sich als dieselbe Konto-ID in ihrer Eigenschaft als Versandursprung verhält. ︎
- Falls es Sie interessiert: 32 Bytes können bis zu der Zahl 1,15x10^77 gespeichert werden. Die Entfernung zum Rand des beobachtbaren Universums beträgt 45,7 Milliarden Lichtjahre, was 4,32x10^23 Kilometern oder 4,32x10^29 Millimetern entspricht. Wenn wir das als eine flache Scheibe betrachten, hat sie eine Fläche von 5,87x10^59 Quadratmillimetern. Wir liegen immer noch um den Faktor 10^18 oder eine Milliarde zum Quadrat daneben. Die Wahrscheinlichkeit, dass zwei verschiedene Hash-Eingänge denselben Ausgang haben, ist also so, dass beide Elemente auf demselben Quadratmillimeter im beobachtbaren Universum landen, dann wird das Ganze in ein 1 Milliarde mal 1 Milliarde großes Raster zerlegt und beide landen wieder auf demselben Quadrat. Diese Quadrate sind 1 Pikometer breit. Zum Vergleich: Ein Heliumatom hat einen Durchmesser von 62 Pikometern. ︎
- Eigentlich kann jedes Konto die Aufforderung übermitteln, solange der Bevollmächtigte die Ankündigung gemacht hat, aber um des Pragmatismus willen nehmen wir an, dass unsere Hot-Wallet nur dasselbe Konto zur Ankündigung und Übermittlung verwendet. ︎
Web3 is the future!
Das ist der offizielle WagMedia Space Germany! Hier werden interessante und lesenswerte DotSama-Artikel durch die Wag-Media community übersetzt und öffentlich zur Verfügung gestellt. Mitmachen? Trete unserem Discord bei und werde Teil der größten News Community im DotSama Universum.
0 comments