So sparen Sie Ihren Ethereum DApp-Benutzern das Bezahlen von Benzin für Transaktionen

Und stattdessen zahlen Sie als DApp-Eigentümer dafür

Crosspost: Dieser Beitrag wurde ursprünglich hier veröffentlicht. Und wurde mit der Erlaubnis des Autors Mahesh Murthy veröffentlicht. [Weitere Informationen unter Zastrin.com. Bonus: Mit dem Code "BlockChannel" sparen Sie 50% auf alle Kurse.]

Einer der Reibungspunkte für die Einführung von Ethereum dapp ist, dass die Benutzer eine Gebühr für das Bezahlen von Gas (Transaktionsgebühr (txn)) entrichten müssen, damit ihre Transaktionen in der Blockchain erfasst werden. Zum Beispiel habe ich ein einfaches Abstimmungsprogramm, mit dem jeder für Kandidaten abstimmen kann, und die Abstimmungen werden in der Blockchain gespeichert. Ein Benutzer, der seine Stimme in der Blockchain aufzeichnen möchte, muss eine Transaktions- / Gasgebühr entrichten. Dies ist nicht ideal, da Sie als App-Besitzer von Ihren Anwendungsbenutzern erwarten, dass Ether für Gas bezahlt, wenn sie nur eine einfache Aktion ausführen möchten, die nichts mit Geldtransfer zu tun hat. Wenn die Transaktion jedoch in der Blockchain ausgeführt werden muss, gibt es keine andere Möglichkeit, als die Gebühr zu zahlen. Was wäre, wenn es für Benutzer eine Möglichkeit gäbe, Transaktionen sicher auszuführen (wie in unserem Beispiel für einen Kandidaten zu stimmen) und jemand anderem (möglicherweise dem Vertragsinhaber) die Transaktion in der Blockchain aufzeichnen und selbst bezahlen zu lassen?

Dank dieses Tweets von John Backus hatte ich gerade genug Informationen, um eine solche Lösung für mein Voting-App zu implementieren.

Ich wollte Details darüber mitteilen, wie ich diese Lösung für meine einfache App implementiert habe, damit mehr Leute diese Technik in ihre eigenen Apps übernehmen und sie hoffentlich verbessern können. Dieser Beitrag behandelt Folgendes:

  1. Ein sehr umfassender Überblick über die Kryptografie mit öffentlichen Schlüsseln und die digitalen Signaturen, die für das Verständnis dieser Lösung von entscheidender Bedeutung sind.
  2. Die Lösungsdetails und der neue Anwendungsfluss.
  3. Implementierungsdetails (Frontend js und Solidity-Vertragscode).
  4. Besprechen Sie mögliche Probleme und Verbesserungen.

Digitale Signaturen

Damit diese Lösung sinnvoll ist, benötigen Sie ein grundlegendes Verständnis der Funktionsweise digitaler Signaturen in der Kryptografie. Sie können diesen Abschnitt gerne überspringen, wenn Sie sich mit Kryptografie mit öffentlichen Schlüsseln auskennen. Ich werde versuchen, das Konzept von öffentlichen / privaten Schlüsseln und digitalen Signaturen auf einer sehr hohen Ebene zu erklären, empfehle jedoch, ausführlicher zu lernen - wikipedia ist ein guter Ausgangspunkt.

Die Kryptografie mit öffentlichem Schlüssel ist ein kryptografisches System, bei dem Sie zwei Schlüssel haben - den öffentlichen Schlüssel (Pu) und einen privaten Schlüssel (Pr). Sie geben Ihren öffentlichen Schlüssel an die ganze Welt weiter und behalten den privaten Schlüssel für sich. Beispiel: Ihre Ethereum-Adresse ist ein öffentlicher Schlüssel (er leitet sich eigentlich vom öffentlichen Schlüssel ab, in dieser Übung stellen wir uns den öffentlichen Schlüssel vor) und Ihr privater Schlüssel ist entweder in Ihrem Browser oder auf Ihrem Telefon / Computer gespeichert. Wie Sie wissen, muss jemand, der Ihnen Ether senden möchte, nur Ihre öffentliche (Konto-) Adresse kennen. Sie können jedoch nur auf Ihre eigenen Mittel zugreifen, da Sie der einzige sind, der Ihren privaten Schlüssel kennt.

Die Kryptografie mit öffentlichen Schlüsseln verfügt über Algorithmen, mit denen Sie Nachrichten mit Ihrem Schlüsselpaar verschlüsseln, entschlüsseln, signieren und überprüfen können.

Sehen wir uns anhand eines Beispiels an, was das Signieren und Überprüfen einer Nachricht bedeutet. Angenommen, Benutzer Kim verfügt über ein Paar öffentliche / private Schlüssel

Pu = "0x44ac12c1e3dfd8edaf83b6f65918229d5279a6f5"

Pr = "dbc226043e390cf39280e5edfd418d7ad61931c76509270867d300f110c46506"

Zum Signieren einer Nachricht führt Kim ein Funktionszeichen ("Vote for Alice", Pr) aus, das eine alphanumerische Zeichenfolge ausgibt

signature = 0x9127112de0033555c7f6508d963d484965a953844dfcff092712102c236467a25af57edc53b63880ea39af8ce7334f6d77a8206e805305e7c6ad919d12bfae5c1b

Dies ist die digitale Signatur der Nachricht "Vote for Alice", die von Kim mit ihrem privaten Schlüssel Pr signiert wurde.

Jetzt kann jeder überprüfen, ob die Nachricht "Vote for Alice" von Kim signiert wurde, indem er die Überprüfungsfunktion ausführt. Verify ("Vote for Alice", Signatur) gibt "0x44ac12c1e3dfd8edaf83b6f65918229d5279a6f5" ​​aus. Wenn Sie bemerken, ist diese Ausgabe Kims öffentlicher Schlüssel Pu (denken Sie daran, jeder weiß, dass es Kims öffentlicher Schlüssel ist), was bedeutet, dass die Nachricht definitiv von Kim signiert wurde. Wenn Sie die Signatur oder Nachricht manipulieren (indem Sie nur ein Zeichen ändern), gibt der Überprüfungsalgorithmus einen völlig anderen öffentlichen Schlüssel aus und Sie wissen, dass die Nachricht manipuliert wurde, da der öffentliche Schlüssel sich von Pu unterscheidet.

Lösungsdetails

Wenn Sie digitale Signaturen verstehen, ist die Lösung äußerst trivial. Lassen Sie uns sehen, wie es in unserer Abstimmungsanwendung verwendet werden kann, um Benutzern die Zahlung von Gasgebühren zu ersparen, ohne ihre Stimme zu beeinträchtigen. Im Folgenden sehen Sie alle Benutzer von dapp und die von ihnen ausgeführten Aktionen.

  1. Ein Wähler gibt seine Absicht an, für einen Kandidaten zu stimmen, indem er eine Nachricht mit seinem privaten Schlüssel signiert. Sie übermitteln ihre Transaktion nicht an die Blockchain, daher wird keine Gebühr für den Versand gezahlt. Die Nachrichtenwarteschlange im obigen Diagramm ist nur ein Off-Chain-Speicherort, an dem alle Abstimmungsdetails gespeichert werden.
  2. Jeder, der bereit ist, die txn-Gebühr zu zahlen (normalerweise der Vertragsinhaber), nimmt die Unterschrift, den Namen des Kandidaten und die Kontoadresse des Wählers und übermittelt sie an die Blockchain.
  3. Der Smart Contract verwendet die Überprüfungsfunktion, um den öffentlichen Schlüssel (die Adresse des Ethereum-Kontos) basierend auf dem Namen und der Unterschrift des Kandidaten abzuleiten. Wenn der abgeleitete öffentliche Schlüssel mit der Adresse des Benutzers übereinstimmt, der die Nachricht signiert hat, wird die Abstimmung aufgezeichnet, oder die Transaktion schlägt fehl.

Implementierungsdetails

Schauen wir uns nun die tatsächliche Implementierung an und wie alle Teile zusammenpassen.

Schritt 1: Unterzeichnen Sie die Nachricht

Der erste Schritt besteht darin, die Nachricht als Wähler zu signieren. Wir werden die Funktion eth_signTypedData verwenden, um unsere Nachricht zu signieren. Diese Funktion wurde in Metamask implementiert, wodurch das Signieren von Nachrichten sehr einfach ist. Weitere Details und Diskussionen zu diesem Vorschlag finden Sie hier: https://github.com/ethereum/EIPs/pull/712. Den Code zum Signieren der Nachricht finden Sie unten.

Eine wirklich wichtige Sache, die zu beachten ist, ist, dass eth_signTypedData intern die Nachricht hasht und die gehashte Nachricht das ist, was signiert wird. Weitere Informationen zum Hashing finden Sie hier unter typedSignatureHash-Funktion.

Schritt 2: Reichen Sie die unterzeichnete Abstimmung in der Blockchain ein

Da dies nur eine Demo-Anwendung ist, speichern wir die Signatur und andere Details nirgendwo. Es wird direkt auf der Seite angezeigt, nachdem die Nachricht signiert wurde. Jeder kann diese Angaben nehmen und an die Blockchain übermitteln. Hier ist der Code, der die Abstimmung an die Blockchain übermittelt:

Schritt 3: Überprüfen Sie die Abstimmungsdetails im Smart-Vertrag

Wir überprüfen jetzt im Smart-Vertrag, ob die übermittelten Abstimmungsdaten gültig sind, und zeichnen dann die Abstimmung auf.

Zeppelin hat eine praktische Bibliothek namens ECRecovery, mit der wir die signierte Nachricht überprüfen können. Die Funktion voteForCandidate überprüft die signierte Nachricht (Wiederherstellungsfunktion) und aktualisiert die Stimmenzahl, wenn die Überprüfung erfolgreich ist.

Wenn Sie sich erinnern, habe ich bereits erwähnt, dass eth_signTypedData die Nachricht ("Vote for Alice") vor dem Signieren hascht. Die Solidity Recover-Funktion kennt die in eth_signTypedData verwendete Hashing-Funktion nicht und kann daher die Meldung "Vote for Alice" nicht überprüfen. Es muss den Hash der Nachricht "Vote for Alice" generieren und dann verifizieren. Anstatt den Hash im Vertrag zu generieren, werden alle Nachrichten im Voraus gehasht und im Konstruktor übergeben, sodass die Suche bei der Überprüfung einfach ist. Der Code zum Generieren des Hashs befindet sich in der folgenden Migrationsdatei

Das ist alles, was Sie brauchen, um die neue Anwendung zum Laufen zu bringen!

Ich habe eine kurze Demo erstellt, um zu zeigen, wie diese Anwendung funktioniert

Der gesamte Arbeitscode ist hier: https://github.com/maheshmurthy/ethereum_voting_dapp/tree/master/chapter4

Die Demo-Anwendung finden Sie hier: https://www.zastrin.com/voting-dapp-without-paying-gas.html

Mögliche Probleme zu beheben

Beim Erstellen eines echten Dapps mit dieser Technik sind einige Punkte zu beachten. Einige von ihnen sind unten aufgeführt:

  1. Wo werden die signierten Nachrichten gespeichert? Sie können eine Art Warteschlangensystem verwenden, um diese Nachrichten zu speichern.
  2. Was ist die Garantie, dass die signierte Nachricht schließlich an die Blockchain gesendet wird?
  3. Das Speichern des Hash aller Nachrichten in der Blockchain ist nicht ideal. Was ist die beste Lösung dafür?

Wenn Sie darüber nachdenken, wie Sie diese Probleme beheben können, oder wenn Sie Fehler in dieser Lösung feststellen, hinterlassen Sie bitte einen Kommentar!

Hinweis: Anscheinend ist die API eth_signTypedData immer noch nicht stabil und wurde nur von der Metamask implementiert. Bitte beachten Sie dies, wenn Sie diese Technik im Mainnet / in der Produktion einsetzen möchten.

Weitere Lektüre

https://en.wikipedia.org/wiki/Public-key_cryptography

https://en.wikipedia.org/wiki/Digital_signature

https://github.com/danfinlay/js-eth-personal-sign-examples/

https://danfinlay.github.io/js-eth-personal-sign-examples/

https://github.com/ethereum/EIPs/pull/712

Vielen Dank an Chris Whinfrey und Febin John James für die Durchsicht der Entwürfe dieses Artikels.

Lern mehr

Wenn Sie lernen möchten, dezentrale Ethereum-Anwendungen zu erstellen, habe ich einige interessante Kurse unter www.zastrin.com