Als nächstes werden wir die Hauptmerkmale der Move-Sprache und ihre Hauptunterschiede zu einer anderen, bereits beliebten Sprache für intelligente Verträge - Solidity (auf der Ethereum-Plattform) - im Detail untersuchen. Das Material basiert auf einer Studie eines verfügbaren 26-seitigen Online-Whitepapers.
Einführung
Move ist eine ausführbare Bytecode-Sprache, mit der Benutzertransaktionen und intelligente Verträge ausgeführt werden. Beachten Sie zwei Punkte:
- Während Move eine Bytecode-Sprache ist, die direkt auf der virtuellen Maschine von Move ausgeführt werden kann, ist Solidity (intelligente Vertragssprache in Ethereum) eine übergeordnete Sprache, die zuerst in Bytecode kompiliert wird, bevor sie in EVM (Ethereum Virtual Machine) ausgeführt wird )
- Move kann nicht nur für die Implementierung intelligenter Verträge verwendet werden, sondern auch für Benutzertransaktionen (dazu später mehr), während Solidity eine Sprache nur für intelligente Verträge ist.
Übersetzung durch das INDEX Protocol-Projektteam. Wir haben zuvor viel Material übersetzt, das das Libra-Projekt beschreibt . Jetzt ist es an der Zeit, die Move-Sprache etwas genauer zu betrachten. Die Übersetzung wurde in Verbindung mit coolsiu gemachtEin wichtiges Merkmal von Move ist die Möglichkeit, benutzerdefinierte Ressourcentypen mit linearer Logiksemantik zu definieren: Eine Ressource kann niemals kopiert oder implizit gelöscht, sondern nur verschoben werden. Funktionell ähnelt dies den Funktionen der Rust-Sprache. Werte in Rust können jeweils nur einem Namen zugewiesen werden. Wenn Sie einem anderen Namen einen Wert zuweisen, kann er unter dem vorherigen Namen nicht mehr aufgerufen werden.

Das folgende Codefragment gibt beispielsweise einen Fehler aus:
Verwendung des verschobenen Werts 'x'. Dies liegt daran, dass es in Rust keine Speicherbereinigung gibt. Wenn Variablen den Gültigkeitsbereich verlassen, wird auch der Speicher freigegeben, auf den sie sich beziehen. Einfach ausgedrückt kann es nur einen „Eigentümer“ von Daten geben. In diesem Beispiel ist
x der ursprüngliche Eigentümer und
y wird der neue Eigentümer.
Lesen Sie hier mehr über dieses Verhalten .
Darstellung digitaler Assets in offenen Systemen
Es gibt zwei Eigenschaften von physischen Vermögenswerten, die digital schwer darzustellen sind:
- Seltenheit (Knappheit im Original - Knappheit). Die Höhe der Vermögenswerte (Ausgabe) im System sollte kontrolliert werden. Das Duplizieren vorhandener Assets muss verboten werden, und das Erstellen neuer Assets ist eine privilegierte Operation.
- Zugangskontrolle . Der Systemteilnehmer muss in der Lage sein, Assets mit Zugriffssteuerungsrichtlinien zu schützen.
Diese beiden Merkmale, die für physische Assets natürlich sind, müssen für digitale Objekte implementiert werden, wenn wir sie als Assets betrachten möchten. Zum Beispiel ein seltenes Metall - hat ein natürliches Defizit, und nur Sie haben Zugriff darauf (zum Beispiel in Ihren Händen) und können es verkaufen oder ausgeben.
Um zu veranschaulichen, wie wir zu diesen beiden Eigenschaften gekommen sind, beginnen wir mit den folgenden Sätzen:
Satz 1: Die einfachste Regel ohne Knappheit und Zugangskontrolle

- G [K]: = n bedeutet, dass die Nummer, auf die der Schlüssel K im globalen Zustand der Blockchain zugreift, mit dem neuen Wert n aktualisiert wird.
- Transaktion "Alice, 100" bedeutet, den Kontostand von Alice auf 100 zu setzen.
Die obige Lösung weist mehrere schwerwiegende Probleme auf:
- Alice kann eine unbegrenzte Anzahl von Münzen erhalten, indem sie einfach die Transaktion "Alice, 100" sendet.
- Die Münzen, die Alice an Bob sendet, sind nutzlos, da Bob sich mit derselben Technik eine unbegrenzte Anzahl von Münzen senden könnte.
Vorschlag Nr. 2: Wir berücksichtigen das Defizit

Jetzt überwachen wir die Situation so, dass die Anzahl der
Ka- Münzen vor der Überweisungstransaktion mindestens
n beträgt. Obwohl dies das Mangelproblem löst, gibt es keine Informationen darüber, wer Alices Münzen senden kann (bisher kann dies jeder, die Hauptsache ist, nicht gegen die Regel der Mengenbeschränkungen zu verstoßen).
Proposition 3: Kombination von Defizit und Zugangskontrolle

Wir lösen dieses Problem mit dem digitalen Signaturmechanismus
verify_sig, bevor wir den
Kontostand überprüfen.
Dies bedeutet, dass Alice ihren privaten Schlüssel verwendet, um die Transaktion zu signieren und zu bestätigen, dass sie ihre Münzen besitzt.
Blockchain-Programmiersprachen
Bestehende Blockchain-Sprachen haben die folgenden Probleme (alle wurden in Move gelöst (Hinweis:
Leider spricht der Autor des Artikels in seinen Vergleichen nur Ethereum an, daher sollten Sie sie nur in diesem Zusammenhang verwenden. Die meisten der folgenden Probleme werden
beispielsweise auch in EOS gelöst )):
Indirekte Darstellung von Vermögenswerten . Ein Asset wird mit einer Ganzzahl codiert, ein ganzzahliger Wert ist jedoch nicht mit einem Asset identisch. Tatsächlich gibt es keinen Typ oder Wert, der Bitcoin / Ether / <Any Coin> darstellt! Dies macht das Schreiben von Programmen, die Assets verwenden, schwierig und fehleranfällig. Muster wie das Übertragen von Assets zu / von Prozeduren oder das Speichern von Assets in Strukturen erfordern eine spezielle Sprachunterstützung.
Das Defizit ist nicht erweiterbar . Die Sprache ist nur ein knappes Gut. Darüber hinaus sind Abhilfemaßnahmen gegen Defizite direkt in die Semantik der Sprache selbst eingebunden. Wenn ein Entwickler ein Benutzer-Asset erstellen möchte, muss er alle Aspekte der Ressource selbst sorgfältig überwachen. Dies sind nur die Probleme von intelligenten Verträgen von Ethereum.
Benutzer stellen ihre Assets, ERC-20-Standardtoken, aus, wobei sie Ganzzahlen verwenden, um sowohl die Kosten als auch die Gesamtausgabe zu bestimmen. Immer wenn neue Token erstellt werden, muss der Smart Contract Code die Einhaltung der Emissionsregeln unabhängig überprüfen. Darüber hinaus führt die indirekte Darstellung von Vermögenswerten in einigen Fällen zu schwerwiegenden Fehlern - Doppelarbeit, doppelte Ausgaben oder sogar ein vollständiger Verlust von Vermögenswerten.
Fehlende flexible Zugangskontrolle . Die einzige derzeit verwendete Zugriffssteuerungsrichtlinie ist ein Signaturschema mit asymmetrischer Kryptografie. Wie der Defizitschutz sind auch die Richtlinien zur Zugriffskontrolle tief in die Semantik der Sprache eingebettet. Das Erweitern der Sprache, damit Programmierer ihre eigenen Zugriffssteuerungsrichtlinien definieren können, ist jedoch häufig keine sehr triviale Aufgabe.
Dies gilt auch für Ethereum, wo intelligente Verträge keine native Kryptografieunterstützung für die Zugriffskontrolle bieten. Entwickler müssen die Zugriffssteuerung manuell vorschreiben, z. B. mithilfe des Modifikators onlyOwner.
Obwohl ich ein großer Fan von Ethereum bin, glaube ich, dass Asset-Eigenschaften aus Sicherheitsgründen von der Sprache nativ unterstützt werden sollten. Insbesondere die Übertragung von Ether auf einen intelligenten Vertrag beinhaltet ein dynamisches Dispatching, was zur Entstehung einer neuen Klasse von Fehlern geführt hat, die als Schwachstellen beim Wiedereintritt bekannt sind. Dynamisches Dispatching bedeutet hier, dass die Logik der Codeausführung zur Laufzeit (dynamisch) und nicht zur Kompilierungszeit (statisch) festgelegt wird.
Wenn also in Solidity Vertrag A die Funktion von Vertrag B aufruft, kann Vertrag B Code ausführen, der nicht vom Entwickler von Vertrag A bereitgestellt wurde, was zu
Sicherheitslücken beim
Wiedereintritt führen kann (Vertrag A führt versehentlich die Funktion von Vertrag B aus, um Geld vor dem tatsächlichen Abzug abzuheben Kontensalden).
Grundlagen des Sprachdesigns verschieben
Ressourcen erster Ordnung
Auf einer höheren Ebene ist die Interaktion zwischen Modulen / Ressourcen / Prozeduren in der Move-Sprache den Beziehungen zwischen Klassen / Objekten und Methoden in OOP-Sprachen sehr ähnlich.
Module in Move ähneln intelligenten Verträgen in anderen Blockchains. Das Modul deklariert Ressourcentypen und -prozeduren, die die Regeln für das Erstellen, Zerstören und Aktualisieren deklarierter Ressourcen festlegen. Aber all dies sind nur Konventionen („
Jargon “) in Move. Wenig später werden wir diesen Punkt veranschaulichen.
Flexibilität
Move erhöht die Flexibilität der Waage durch Skripterstellung. Jede Transaktion in Libra enthält ein Skript, das eigentlich das Haupttransaktionsverfahren ist. Das Skript kann entweder eine bestimmte Aktion ausführen, z. B. Zahlungen gemäß der angegebenen Empfängerliste, oder andere Ressourcen wiederverwenden, indem beispielsweise eine Prozedur aufgerufen wird, in der die allgemeine Logik angegeben ist. Aus diesem Grund bieten Move-Transaktionsskripte mehr Flexibilität. Das Skript kann sowohl einmaliges als auch sich wiederholendes Verhalten verwenden, während Ethereum nur sich wiederholende Skripte ausführen kann (Aufrufen einer Smart Contract-Methode durch Aufrufen einer Methode). Der Grund, warum es als "mehrfach" bezeichnet wird, ist, dass die Funktionen eines intelligenten Vertrags mehrfach ausgeführt werden können. (Hinweis:
Der Moment ist hier sehr heikel. Einerseits sind Transaktionsskripte in Form von Pseudo-Bytecode auch in Bitcoin. Andererseits erweitert Move diese Sprache meines Wissens tatsächlich auf das Niveau einer vollwertigen intelligenten Vertragssprache. )
Sicherheit
Das ausführbare Format von Move ist Bytecode, der einerseits eine Sprache mit einer höheren Ebene als Assembler, aber einer niedrigeren Ebene als der Quellcode ist. Der Bytecode wird in der Kette mithilfe des Bytecode-Verifizierers auf Verfügbarkeit von Ressourcen, Typen und Speichersicherheit überprüft und dann vom Interpreter ausgeführt. Dieser Ansatz ermöglicht es Move, Sicherheit für den Quellcode bereitzustellen, jedoch ohne den Kompilierungsprozess und die Notwendigkeit, dem System einen Compiler hinzuzufügen. Move zu einer Bytecode-Sprache zu machen, ist eine wirklich gute Lösung. Es ist nicht erforderlich, es aus der Quelle zu kompilieren, wie dies bei Solidity der Fall ist, und Sie müssen sich keine Gedanken über mögliche Abstürze oder Angriffe auf die Compiler-Infrastruktur machen.
Überprüfbarkeit
Wir sind bestrebt, so einfache Überprüfungen wie möglich durchzuführen, da dies alles in der Kette erfolgt (Hinweis:
Online, bei jeder Transaktion führt jede Verzögerung zu einer Verlangsamung des gesamten Netzwerks ). Das Sprachdesign ist jedoch zunächst einsatzbereit und Off-Chain-Mittel zur statischen Überprüfung. Obwohl dies vorzuziehen ist, wurde die Entwicklung von Verifizierungswerkzeugen (als separates Toolkit) bisher auf die Zukunft verschoben, und jetzt wird nur die dynamische Verifizierung in der Kette unterstützt.
Modularität
Verschiebemodule bieten Datenabstraktion und lokalisieren kritische Vorgänge an Ressourcen. Die vom Modul bereitgestellte Kapselung in Kombination mit dem vom Move-Typsystem bereitgestellten Schutz stellt sicher, dass die für die Modultypen festgelegten Eigenschaften nicht durch Code außerhalb des Moduls verletzt werden können. Dies ist ein durchdachtes Design der Abstraktion, dh die Daten innerhalb des Vertrags können nur im Rahmen der Vertragsausführung geändert werden, nicht jedoch von außen.

Bewertung verschieben
Ein Beispiel für ein Transaktionsskript zeigt, dass böswillige oder rücksichtslose Aktionen eines Programmierers außerhalb eines Moduls die Sicherheit von Modulressourcen nicht verletzen können. Als nächstes sehen wir uns Beispiele an, wie Module, Ressourcen und Prozeduren zum Programmieren der Libra-Blockchain verwendet werden.
Peer-to-Peer-Zahlungen

Der im Betrag angegebene Münzbetrag wird vom Guthaben des Absenders an den Empfänger überwiesen.
Es gibt mehrere neue Punkte (rot hervorgehoben):
- 0x0 : Adresse des Kontos, in dem das Modul gespeichert ist
- Währung : Modulname
- Münze : Ressourcentyp
- Der von der Prozedur zurückgegebene Münzwert ist ein Ressourcenwert mit dem Typ 0x0.Currency.Coin
- move () : Wert kann nicht mehr verwendet werden
- copy () : Wert kann später verwendet werden
Wir analysieren den Code: Im ersten Schritt ruft der Absender eine Prozedur namens
draw_from_sender aus dem in
0x0.Currency gespeicherten Modul auf. In der zweiten Phase überweist der Absender das Geld an den Empfänger und verschiebt den Wert der
Münzressource in das Einzahlungsverfahren des Moduls
0x0 .
Währung .
Hier sind drei Beispiele für Codefehler, die durch Überprüfungen zurückgewiesen werden:
Duplizieren von Geldern durch Ändern des Aufrufs zum Verschieben (Münze) zum Kopieren (Münze) . Ressourcen können nur verschoben werden. Der Versuch, die Menge einer Ressource zu duplizieren (z. B. durch Aufrufen von
copy (coin) im obigen Beispiel), führt zu einem Fehler beim Überprüfen des Bytecodes.
Wiederverwendung von Geldern durch zweimalige Angabe von Bewegung (Münze) . Durch Hinzufügen der Zeile
0x0.Currency.deposit (copy (some_other_payee), move (coin)) für das obige Beispiel kann der Absender zweimal Münzen "ausgeben" - das erste Mal mit dem Zahlungsempfänger und das zweite Mal mit
some_other_payee . Dies ist ein unerwünschtes Verhalten, das mit einem physischen Vermögenswert unmöglich ist. Glücklicherweise wird Move dieses Programm ablehnen.
Geldverlust durch Bewegungsfehler (Münze) . Wenn Sie die Ressource nicht verschieben (z. B. durch Löschen der Zeile mit dem
Verschieben (Münze) ), wird durch Überprüfen des Bytecodes ein Fehler generiert. Dies schützt Move-Programmierer vor versehentlichem oder böswilligem Geldverlust.
Währungsmodul

Jedes Konto kann 0 oder mehr Module (als Rechtecke dargestellt) und einen oder mehrere Ressourcenwerte (als Zylinder dargestellt) enthalten. Ein Konto bei
0x0 enthält beispielsweise ein
0x0.Currency- Modul und einen Ressourcenwert vom Typ
0x0.Currency.Coin . Das Konto bei
0x1 verfügt über zwei Ressourcen und ein Modul. Das Konto bei
0x2 hat zwei Module und einen Ressourcenwert.
Einige Punkte:
- Das Transaktionsskript ist atomar - entweder vollständig oder gar nicht ausgeführt.
- Ein Modul ist ein langlebiger Code, der weltweit verfügbar ist.
- Der globale Status ist als Hash-Tabelle strukturiert, wobei der Schlüssel die Kontoadresse ist
- Konten dürfen nicht mehr als einen Ressourcenwert dieses Typs und nicht mehr als ein Modul mit einem bestimmten Namen enthalten (ein Konto bei 0x0 kann keine zusätzliche Ressource 0x0 enthalten. Currency.Coin oder ein anderes Modul namens Currency )
- Die Adresse des deklarierten Moduls ist Teil des Typs ( 0x0.Currency.Coin und 0x1.Currency.Coin sind separate Typen, die nicht austauschbar verwendet werden können).
- Programmierer können mehrere Instanzen dieses Ressourcentyps im Konto speichern, indem sie ihre benutzerdefinierte Ressource definieren - ( Ressource TwoCoins {c1: 0x0.Currency.Coin, c2: 0x0.Currency.Coin} )
- Sie können eine Ressource ohne Konflikte anhand ihres Namens referenzieren . Sie können beispielsweise mit TwoCoins.c1 und TwoCoins.c2 auf zwei Ressourcen verweisen .
Coin Resource Ad

Ein Modul namens
Währung und ein Ressourcentyp namens
MünzeEinige Punkte:
- Coin ist eine Einzelfeldstruktur vom Typ u64 (64-Bit-Ganzzahl ohne Vorzeichen)
- Nur Prozeduren des Währungsmoduls können Münzwerte erstellen oder zerstören.
- Andere Module und Skripte können das Wertefeld nur durch offene Prozeduren schreiben oder referenzieren, die vom Modul bereitgestellt werden.
Implementierung der Einzahlung

Bei diesem Verfahren wird die
Münzressource als Eingabe verwendet und mit der im Konto des Empfängers gespeicherten Münzressource kombiniert:
- Zerstören Sie die Münzeingaberessource und zeichnen Sie ihren Wert auf.
- Abrufen eines Links zu einer eindeutigen Münzressource, die im Konto des Empfängers gespeichert ist.
- Ändern des Werts des Münzbetrags um den Wert, der beim Aufruf der Prozedur im Parameter übergeben wird.
Einige Punkte:
- Auspacken, BorrowGlobal - integrierte Verfahren
- Das Entpacken von <T> ist die einzige Möglichkeit, eine Ressource vom Typ T zu löschen. Die Prozedur führt die Ressource zur Eingabe, zerstört sie und gibt den Wert zurück, der den Feldern der Ressource zugeordnet ist.
- BorrowGlobal <T> akzeptiert die Adresse als Eingabe und gibt einen Link zu einer eindeutigen Instanz von T zurück, die von dieser Adresse veröffentlicht wurde (deren Eigentümer sie ist)
- & mut Coin ist ein Link zur Coin- Ressource
Implementieren Sie draw_from_sender

Dieses Verfahren:
- Ruft einen Link zu einer eindeutigen Münzressource ab , die mit dem Konto des Absenders verknüpft ist
- Verringert den Wert der Münzressource um den angegebenen Betrag
- Erstellt eine neue Münzressource mit einem aktualisierten Kontostand und gibt sie zurück.
Einige Punkte:
- Die Einzahlung kann von jedem angerufen werden, aber draw_from_sender hat nur Zugriff auf die Münzen des aufrufenden Kontos
- GetTxnSenderAddress ähnelt msg.sender in Solidity
- RejectUnless ist ähnlich wie in Solidity erforderlich . Wenn diese Prüfung fehlschlägt, wird die Transaktion gestoppt und alle Änderungen werden zurückgesetzt.
- Pack <T> ist auch eine integrierte Prozedur, die eine neue Ressource vom Typ T erstellt.
- Wie <T> entpacken kann Pack <T> nur innerhalb des Moduls aufgerufen werden, in dem die Ressource T beschrieben ist
Fazit
Wir haben die Hauptmerkmale der Move-Sprache untersucht, sie mit Ethereum verglichen und uns auch mit der grundlegenden Syntax von Skripten vertraut gemacht. Abschließend empfehle ich dringend, das
Original- Whitepaper durchzusehen. Es enthält viele Details zu den Prinzipien des Programmiersprachenentwurfs sowie viele nützliche Links.