In den letzten zwei Wochen lag unser primärer Fokus auf den POC5 -Kompatibilität, und es war definitiv ein langer Weg. Zu den Änderungen an der VM gehören:
- Der neue Init/Code -Mechanismus: Wenn Sie einen Vertrag erstellen, wird im Grunde genommen der angegebene Code sofort ausgeführt, und dann wird der Rückgabewert dieses Codes der Code des Vertrags. Dies ermöglicht es uns, den Vertragsinitialisierungscode zu haben, aber dennoch das gleiche Format von festhalten [nonce, price, gas, to, value, data] Sowohl für Transaktionen als auch für die Vertragserstellung erleichtert auch die Erstellung neuer Verträge über Weiterleitungsverträge
- Transaktions- und Vertragsdaten neu bestellen: Die Bestellung ist jetzt [nonce, price, gas, to, value, data] in Transaktionen und [gas, to, value, datain, datainsz, dataout, dataoutsz] in Nachrichten. Beachten Sie, dass die Schlangen die Parameter Send (an Wert, Gas), O = MSG (an Wert, Gas, Datain, DATAINSZ) und O = MSG (bis, Value, DATain, DATAINSZ, DATAUSZ) behält.
- Gebührenanpassungen: Die Erstellung der Transaktionen hat jetzt eine Gebühr von 500 Gas und mehrere andere Gebühren wurden aktualisiert.
- Die Codecopy- und CallDatacopy -Opcodes: CodeCopy nimmt Code_index, mem_index, len als Argumente und kopiert den Code von Code_index … code_index+len-1 zu memor mem_index … mem_index+len-1. Diese sind sehr nützlich, wenn sie mit Init/Code kombiniert werden. Es gibt jetzt auch codesze.
Die größten Veränderungen waren jedoch in der Architektur, die das Protokoll umgibt. Auf der GUI -Seite entwickeln sich die Kunden von C ++ und GO rapide weiter und wir werden in Kürze weitere Updates von dieser Seite kommen. Wenn Sie Ethereum genau verfolgt haben, haben Sie wahrscheinlich gesehen Dennys Lottoeine vollständige Implementierung einer Lotterie sowie GUI, geschrieben und im C ++ – Client ausgeführt. Von hier an wird der C ++-Client ein Entwickler-orientierteres Werkzeug sein, während sich der GO-Client darauf konzentriert, eine vom Benutzer ausgerichtete Anwendung zu sein (oder vielmehr Meta-Anwendung). Auf der Compiler -Seite hat die Schlange eine Reihe erheblicher Verbesserungen erfahren.
Erstens der Code. Sie können in den Schlangen Compiler unter der Motorhaube schauen und können sehen Alle Funktionenverfügbar, zusammen mit ihren genauen Übersetzungen in den EVM -Code. Zum Beispiel haben wir:
72: [‘access’, 2, 1,
73: [”, ”, 32, ‘MUL’, ‘ADD’, ‘MLOAD’]],
Dies bedeutet, dass der Zugriff (x, y) unter der Motorhaube tatsächlich tut, dass er rekursiv das eigentliche X und Y kompiliert, und dann den Speicher in Index x + y * 32 laden; Daher ist X der Zeiger auf den Beginn des Arrays und Y ist der Index. Diese Codestruktur gibt es seit POC4, aber jetzt habe ich die Meta-Sprache, mit der Übersetzungen noch weiter beschrieben werden, noch weiter verbessert, um auch dann einzubeziehen, auch wenn, während und init/code in dieser Konstruktion (bevor sie Sonderfälle waren); Jetzt bleiben nur SET und SEQ als besondere Fälle, und wenn ich wollte, könnte ich SEQ sogar entfernen, indem ich es neu eingestuft habe Regel umschreiben.
Die bisher größten Veränderungen waren die Kompatibilität von POC5. Wenn Sie beispielsweise Serpent Compile_to_Assembly ‘return (msg.data ausführen[0]*2) ‘Sie werden sehen:
[“begincode_0″, “CALLDATACOPY”, “RETURN”, “~begincode_0”, “#CODE_BEGIN”, 2, 0, “CALLDATALOAD”, “MUL”, “MSIZE”, “SWAP”, “MSIZE”, “MSTORE”, 32, “SWAP”, “RETURN”, “#CODE_END”, “~endcode_0”]
Der tatsächliche Code gibt es nur:
[2, 0, “CALLDATALOAD”, “MUL”, “MSIZE”, “SWAP”, “MSIZE”, “MSTORE”, 32, “SWAP”, “RETURN”]
Wenn Sie sehen möchten, was hier vor sich geht, gehen Sie davon aus, dass eine Nachricht mit ihrem ersten Datum 5 ist. Wir haben also:
2 -> Stack: [2]
0 -> Stack: [2, 0]
CallDataload -> Stack: [2,5]
Mul -> Stack: [10]
MSIZE -> Stack: [10, 0]
Tausch -> Stack: [0, 10]
MSIZE -> Stack: [0, 10, 0]
MStore -> Stack: [0]Erinnerung: [0, 0, 0 … 10]
32 -> Stack: [0, 32]Erinnerung: [0, 0, 0 … 10]
Tausch -> Stack: [32, 0]Erinnerung: [0, 0, 0 … 10]
ZURÜCKKEHREN
Die letzte Rückkehr gibt die 32 Speicherbytes ab 0 oder ab oder [0, 0, 0 … 10]oder die Nummer 10.
Lassen Sie uns nun den Wrapper -Code analysieren.
[“begincode_0″, “CALLDATACOPY”, “RETURN”, “~begincode_0”, “#CODE_BEGIN”, ….. , “#CODE_END”, “~endcode_0”]
Ich bin der oben erläuterte innere Code elidiert, um die Dinge klarer zu machen. Das erste, was wir sehen, sind zwei Etiketten, Begincode_0 undEndcode_0 und die Wachen von #Code_Begin und #Code_end. Die Beschriftungen markieren den Anfang und das Ende des inneren Code, und die Wachen sind für die späteren Phasen des Compilers da, was versteht, dass alles zwischen den Wachen zusammengestellt werden sollte, als ob es sich um ein separates Programm handelt. Schauen wir uns nun die ersten Teile des Codes an. In diesem Fall haben wir ~ Begincode_0 an Position 10 und ~ Endcode_0 an Position 24 im endgültigen Code. Endcode_0 wird verwendet, um auf diese Positionen zu verweisen, und $ Begincode_0.endcode_0 bezieht sich auf die Länge des Intervalls zwischen ihnen.
14 -> Stack: [14]
DUP -> Stack: [14, 14]
MSIZE -> Stack: [14, 14, 0]
Tausch -> Stack: [14, 0, 14]
MSIZE -> Stack: [14, 0, 14, 0]
10 -> Stack: [14, 0, 14, 0, 10]
CallDatacopy -> Stack: [14, 0] Erinnerung: [ … ]
ZURÜCKKEHREN
Beachten Sie, wie die erste Hälfte des Codes den Stapel geschickt eingerichtet hat, damit der innere Code in Speicherindizes 0… 13 drückt, und dann sofort diesen Speicherblock zurückgeben. Im endgültigen kompilierten Code 600E515B525B600A37F26002600035025B525B54602052F2 sitzt der innere Code gut rechts vom Initialisierercode, der ihn einfach zurückgibt. In komplexeren Verträgen können Initialisierer auch Funktionen wie das Festlegen bestimmter Speicherschläge auf Werte oder sogar anrufen oder andere Verträge erstellen.
Lassen Sie uns nun die neueste und unterhaltsamste Funktion von Serpent: Importe vorstellen. Ein gängiger Anwendungsfall im Vertragsland ist, dass Sie einem Vertrag die Möglichkeit geben möchten, neue Verträge auszuschöpfen. Problem ist, wie Sie den Code für die hervorgebrachten Verträge in die Spawner -Verträge einfügen? Zuvor war die einzige Lösung der unangenehme Ansatz, zuerst die neueren Verträge zusammenzustellen und dann den kompilierten Code in ein Array zu bringen. Jetzt haben wir eine bessere Lösung: Import.
Legen Sie Folgendes in returnten.se:::
x = create (tx.gas – 100, 0, import (mul2.se)) return (msg (x, 0, tx.gas -100,[5]1))
Stellen Sie nun Folgendes in mul2.se ein:
return (msg.data[0]*2)
Wenn Sie jetzt eine Schlange kompilieren, returnten.se und den Vertrag ausführenSie bemerken das, voila, es kehrt zehn zurück. Der Grund dafür ist offensichtlich. Der Returnten.se -Vertrag erstellt eine Instanz des MUL2.SE -Vertrags und nennt ihn dann mit dem Wert 5. mul2.se, wie der Name schon sagt, ein Doppel, und es gibt daher 5*2 = 10. Beachten Sie, dass der Import keine Funktion im Standard -Sinne ist. x = import (‘123.se’) schlägt fehl und funktioniert nur im sehr spezifischen Kontext von Create.
Nehmen wir nun an, Sie erstellen einen 1000-Line-Monstervertrag und möchten ihn in Dateien aufteilen. Dazu verwenden wir Inset. Intouter.se, setzen:
Wenn msg.data[0] == 1: Einschub (inner.SE)
Und in innere.se, setzen:
Rückkehr (3)
Ausführen von Serpent Compile Outer.[0] Argument ist gleich eins. Und das ist alles, was es gibt.
Zu den bevorstehenden Aktualisierungen der Schlange gehören:
- Eine Verbesserung dieses Mechanismus, sodass der innere Code nicht zweimal geladen wird, wenn Sie versuchen, importieren, zweimal mit demselben Dateinamen zu verwenden
- String -Literale
- Raum- und Codeeffizienzverbesserungen für Array-Literale
- Ein Debugging -Dekorateur (dh eine Kompilierungsfunktion, die Ihnen sagt, welche Schlangenlinien entsprechen, welche Bytes kompilierter Code)
Kurzfristig werden sich meine eigene Anstrengung jedoch auf Bugfixes, eine Cross-Client-Testsuite, konzentrieren und fortgesetzt Ethereumjs-lib.

