5 Wege, wie die Entwicklung von Ergo-Anwendungen dank Appkit für immer verändert wird
3. Dezember 2019

Dank an Robert Kornacki und Denys Zadorozhnyi.
Ergo Appkit ist eine Bibliothek für
polyglotte Entwicklung von Ergo-Anwendungen basierend auf
GraalVM. GraalVM hat viele großartige
Anwendungsfälle. In diesem Artikel werden wir einige der Appkit
Funktionen, die von GraalVM geerbt wurden, durchgehen und Ihnen Schritt für Schritt zeigen, wie Sie davon profitieren können.
- 0. Beispiel-Szenario
- 1. Java Ergo App Entwicklung
- 2. Ressourcenfreundliche, schnell startende Ergo-Anwendungen
- 3. Entwickeln Sie Ergo-Anwendungen in JavaScript, Python, Ruby
- 4. Ergo Native Shared Libraries
- 5. Debuggen Sie Ihre polyglotte Ergo-Anwendung
Beispiel-Szenario
Wir werden eine einfache Konsolenanwendung (genannt
FreezeCoin)
in Java erstellen, die die Appkit-Bibliothek verwendet. Mit Appkit werden wir in der Lage sein, programmgesteuert eine neue Transaktion an einen Ergo-Knoten zu senden. Die
Transaktion wird einen bestimmten Betrag an Erg in eine neue Box übertragen, die durch den
folgenden Ergo-Vertrag geschützt ist, der in ErgoScript geschrieben ist (siehe diese
introduction und mehr fortgeschrittene
Beispiele, um mehr über ErgoScript zu erfahren).
// Freezer Vertrag
{
// Parameter
// freezeDeadline: Int - eine zukünftige Blocknummer, nach der die Box ausgegeben werden kann
// ownerPk: SigmaProp - öffentlicher Schlüssel des neuen Boxbesitzers
sigmaProp(HEIGHT > freezeDeadline) && ownerPk
}
Kurz gesagt, eine Box (und damit die Mittel innerhalb der Box) sind unter einem Vertrag (oder Skript) auf der Ergo-Blockchain gesperrt. Damit die Box ausgegeben werden kann, muss der Vertrag als wahr ausgewertet werden. Daher muss die Person, die die Box ausgeben möchte, sicherstellen, dass der Vertrag basierend auf der kodierten Logik innerhalb des Vertrags als wahr ausgewertet wird.
Unser oben genannter Freezer-Vertrag überprüft die folgenden Bedingungen, bevor er die Box zur Ausgabe zulässt:
-
Die aktuelle Blocknummer der Ergo-Blockchain (auch bekannt als Blockchain-HÖHE) ist
größer als die angegebene Frist -
Die Ausgabetransaktion muss vom Besitzer des geheimen Schlüssels, der dem ownerPk öffentlichen Schlüssel entspricht, signiert werden.
Die erste Bedingung verbietet es jedem, die Box vor dem Erreichen der angegebenen Höhe der Ergo-Blockchain auszugeben. Da neue Blöcke auf der Blockchain im Durchschnitt alle 2 Minuten abgebaut werden, ist es einfach, jede gewünschte Verzögerungsdauer wie 1 Tag, 1 Woche oder 1 Monat zu definieren. (d.h. (60 / 2) * 24 * 7 = 5040, was die Anzahl der Blöcke pro Woche ist).
Wir werden nun im Detail darauf eingehen, wie wir diesen Freezer-Vertrag nehmen und ihn mit der Apkit-Bibliothek integrieren können, um die FreezeCoin-Konsolenanwendung zu erstellen, damit jeder und jede die Möglichkeit hat, ihre Münzen einzufrieren, wenn sie dies wünschen. (Zugegeben, dieser Vertrag/dApp ist nicht wirklich nützlich, jedoch ist es ein effektives einfaches Beispiel, um zu zeigen, wie dieser Technologiestack funktioniert, damit Sie selbst nützliche dApps entwickeln können.)
1. Java Ergo App Entwicklung
Appkit zielt darauf ab, eine Reihe von Schnittstellen bereitzustellen, die idiomatisch
in Java verwendet werden können. Wenn Sie ein Java-Veteran sind, werden Sie sich mit Appkit sofort wohlfühlen.
Bitte folgen Sie den Einrichtungsanweisungen für GraalVM und
Appkit, wenn Sie die untenstehenden Beispiele reproduzieren möchten.
Um Appkit in unserer Java-Implementierung von FreezeCoin zu verwenden, müssen wir die
folgende Abhängigkeit in der gradle
Datei hinzufügen.
dependencies {
implementation("org.ergoplatform", "ergo-appkit_2.12", "3.1.0", "compile")
...
}
Darüber hinaus muss Appkit/unserer Anwendung zur Laufzeit über die REST-API mit einem Ergo-Knoten verbunden werden. Oft wird der Knoten lokal ausgeführt und ist unter http://localhost:9052/ verfügbar. Dies ist das Standardszenario für jeden, der einen Vollknoten eingerichtet hat, indem er diesen Anweisungen gefolgt ist und die Standardkonfiguration verwendet.
Daher gehen wir davon aus, dass Sie Ihren Ergo-Knoten eingerichtet und gestartet haben, sodass er für Tests der Anwendung verfügbar ist.
Als nächstes muss unsere Anwendung wissen, wie sie sich mit unserem lokal laufenden Knoten verbinden kann, zusätzlich zu anderen verschiedenen Einstellungen, um ordnungsgemäß zu funktionieren. Wir werden eine JSON-Datei mit den folgenden
Konfigurationsparametern verwenden, die unsere FreezeCoin-App beim Start lädt.
{
"node": {
"nodeApi": {
"apiUrl": "http://localhost:9052/",
"apiKey": "geben Sie hier Ihren geheimen apiKey ein, der während der Knoten-Einrichtung generiert wurde"
},
"wallet": {
"mnemonic": "der mnemonic Schlüssel, der verwendet wird, um das Wallet des Knotens zu initialisieren oder wiederherzustellen",
"password": "das Passwort, das Sie gewählt haben, um das Wallet zu schützen",
"mnemonicPassword": "das Passwort, das Sie gewählt haben, um den mnemonic zu schützen"
},
"networkType": "TESTNET"
},
"parameters": {
"newBoxSpendingDelay": "30",
"ownerAddress": "3WzR39tWQ5cxxWWX6ys7wNdJKLijPeyaKgx72uqg9FJRBCdZPovL"
}
}
Hier ist apiKey der geheime Schlüssel, der für die API-Authentifizierung erforderlich ist und wie beschrieben
hier erworben werden kann.
Ihr mnemonic ist der geheime Satz, der während der Einrichtung eines neuen
Wallets erhalten wurde.
Wie unsere App funktioniert, ist, dass der Benutzer sie über die Befehlszeile startet und ein Argument bereitstellt. Dieses Argument ist der Betrag (in NanoErgs), den er unter dem Freezer-Vertrag, den wir oben geschrieben haben, einfrieren/sperren möchte.
Unser erster Schritt für unsere FreezeCoin-App wird sein, die Konfigurations-JSON-Datei zu lesen, die wir gerade erstellt haben, und das Befehlszeilenargument vom Benutzer zu akzeptieren:
public static void main(String[] args) {
long amountToSend = Long.parseLong(args[0]); // positiver Wert in NanoErg
ErgoToolConfig conf = ErgoToolConfig.load("freeze_coin_config.json");
// der Rest des Codes wird unten besprochen
...
}
Mit diesen Informationen können wir nun die Ausgabeverzögerung und die Besitzeradresse abrufen, die in der JSON-Konfigurationsdatei definiert wurden.
int newBoxSpendingDelay = Integer.parseInt(conf.getParameters().get("newBoxSpendingDelay"));
Address ownerAddress = Address.create(conf.getParameters().get("ownerAddress"));
Als nächstes müssen wir uns von unserer Java-Anwendung mit dem laufenden Ergo-Knoten verbinden, damit wir die Daten, die wir gerade geparst haben, verwenden und etwas on-chain posten können. Dies geschieht durch die Erstellung einer ErgoClient-Instanz, die ebenfalls unsere vordefinierten Werte für unseren Knoten aus der JSON-Konfigurationsdatei verwendet.
ErgoNodeConfig nodeConf = conf.getNode();
ErgoClient ergoClient = RestApiErgoClient.create(nodeConf);
Jetzt, da wir eine Instanz von ErgoClient haben,
können wir jeden Codeblock ausführen und haben Zugriff auf den aktuellen Blockchain-Kontext.
String txJson = ergoClient.execute((BlockchainContext ctx) -> {
// verwenden Sie ctx hier, um eine neue Transaktion zu erstellen und zu signieren
// und senden Sie sie dann an den Knoten
});
Die Lambda-Funktion, die an execute übergeben wird, wird aufgerufen, wenn der aktuelle Blockchain-Kontext
vom Ergo-Knoten geladen wird. In dieser Lambda-Funktion
werden wir unsere Anwendungslogik unterbringen.
Zuerst beginnen wir mit einigen Hilfsfunktionen.
// Zugriff auf das Wallet, das im Ergo-Knoten eingebettet ist
// (unter Verwendung des Wallets, das über den mnemonic in freeze_coin_config.json angegeben wurde)
ErgoWallet wallet = ctx.getWallet();
// berechnen Sie den Gesamtbetrag an NanoErgs, den wir an die neue Box senden müssen
// einschließlich der Zahlung von Transaktionsgebühren
long totalToSpend = amountToSend + Parameters.MinFee;
// Anfrage nach ungenutzten Boxen, die den erforderlichen Betrag an NanoErgs aus dem Wallet abdecken
Optional<List<InputBox>> boxes = wallet.getUnspentBoxes(totalToSpend);
if (!boxes.isPresent())
throw new ErgoClientException(
"Nicht genügend Münzen in Ihrem angegebenen Wallet, um " + totalToSpend + " zu bezahlen", null);
// erstellen Sie einen "Prover", der ein spezielles Objekt ist, das zum Signieren der Transaktion verwendet wird
// der Prover sollte mit den Geheimnissen Ihres Wallets konfiguriert werden, die erforderlich sind, um Signaturen (d.h. Beweise) zu generieren
ErgoProver prover = ctx.newProverBuilder()
.withMnemonic(
nodeConf.getWallet().getMnemonic(),
nodeConf.getWallet().getPassword())
.build();
An diesem Punkt haben wir die Eingabeboxen für unsere Ausgabetransaktion ausgewählt, aber wir müssen jetzt eine Ausgabebox mit dem angegebenen amountToSend erstellen, die unter dem Freezer-Vertrag gesperrt ist.
// die einzige Möglichkeit, eine Transaktion zu erstellen, besteht darin, den tx-Builder zu verwenden, der aus dem Kontext erhalten wurde
// der Builder verwendet den Kontext, um auf die erforderlichen Blockchain-Daten zuzugreifen.
UnsignedTransactionBuilder txB = ctx.newTxBuilder();
// erstellen Sie eine neue Box mit dem neuen Builder, der vom Transaktions-Builder erhalten wurde
// in diesem Fall kompilieren wir einen neuen ErgoContract aus dem Freezer ErgoScript-Code
OutBox newBox = txB.outBoxBuilder()
.value(amountToPay)
.contract(ctx.compileContract(
ConstantsBuilder.create()
.item("freezeDeadline", ctx.getHeight() + newBoxSpendingDelay)
.item("ownerPk", ownerAddress.getPublicKey())
.build(),
"{ sigmaProp(HEIGHT > freezeDeadline) && ownerPk }"))
.build();
Beachten Sie, dass zur Kompilierung des ErgoContract aus dem Quellcode des Freezer-Skripts die Methode compileContract
verlangt, dass wir Werte für benannte Konstanten bereitstellen, die innerhalb des Skripts verwendet werden.
Wenn keine solchen Konstanten verwendet werden, kann ConstantsBuilder.empty() übergeben werden.
In diesem Fall übergeben wir den öffentlichen Schlüssel des neuen Boxbesitzers in den ownerPk
Platzhalter im Skript. Um es zu wiederholen, bedeutet dies, dass die Box nur vom Besitzer des
entsprechenden geheimen Schlüssels ausgegeben werden kann.
Als nächstes erstellen wir eine nicht signierte Transaktion mit allen Daten, die wir bisher zusammengestellt haben.
// geben Sie dem Transaktions-Builder an, welche Boxen wir ausgeben werden, welche Ausgaben
// erstellt werden sollen, die gesamten Transaktionsgebühren und die Adresse, an die das Wechselgeld gesendet werden soll
UnsignedTransaction tx = txB.boxesToSpend(boxes.get())
.outputs(newBox)
.fee(Parameters.MinFee)
.sendChangeTo(prover.getP2PKAddress())
.build();
Und schließlich:
- Verwenden Sie den Prover, um die erstellte Transaktion zu signieren
- Dadurch erhalten Sie eine
SignedTransaction-Instanz - Verwenden Sie den Blockchain-Kontext, um die signierte Transaktion an
den Ergo-Knoten zu senden.
Die resultierende txId kann verwendet werden, um auf diese Transaktion
später zu verweisen, jedoch verwenden wir sie hier nicht.
SignedTransaction signed = prover.sign(tx);
String txId = ctx.sendTransaction(signed);
return signed.toJson(true);
Wie Sie vielleicht bemerkt haben, zeigen wir in unserem letzten Schritt, dass es möglich ist, die signierte
Transaktion in einen JSON-String mit aktivierter schöner Ausgabe zu serialisieren. Schauen Sie sich den vollständigen
Quellcode
für weitere Details an und verwenden Sie ihn als Vorlage in Ihrer eigenen
Anwendung.
Jetzt, da der gesamte Code festgelegt ist, können wir unsere FreezeCoin-Anwendung mit den folgenden Schritten ausführen
(angenommen, Sie befinden sich im Verzeichnis, in dem Sie
ergo-appkit-examples geklont haben).
$ pwd
das/verzeichnis/in/dem/sie/ergo-appkit-examples/geklohnt/haben
$ ./gradlew clean shadowJar
Dies wird die Datei build/libs/appkit-examples-3.1.0-all.jar erstellen, die
unsere FreezeCoin-Java-Anwendung und alle ihre Abhängigkeiten in einer einzigen Fat-JAR enthält.
Beachten Sie, dass dieser Schritt nach Änderungen am Java-Quellcode unserer Anwendung wiederholt werden muss.
Nachdem wir unsere Anwendung erstellt haben, können wir jetzt unsere FreezeCoin-App verwenden:
$ java -cp build/libs/appkit-examples-3.1.0-all.jar \
org.ergoplatform.appkit.examples.FreezeCoin 1000000000
Sie erhalten etwas in der Art von dieser Ausgabe in der Konsole.
Und damit wurde Ihre Transaktion vom Ergo-Knoten akzeptiert und ins Netzwerk übertragen, wo sie im Transaktionspool auf die Hinzufügung zu einem Block wartet. Sobald ein Miner sie auswählt und zu einem Block hinzufügt, werden Ihre Münzen offiziell "eingefroren" in der neu geschaffenen Box basierend auf den Werten, die Sie der FreezeCoin-Anwendung bereitgestellt haben.
Das Beispiel geht davon aus, dass der Ergo-Knoten (und das eingebettete Wallet) dem
FreezeCoin-Benutzer gehört. Dies ist jedoch nicht unbedingt erforderlich, und die Appkit-Schnittstellen
können verwendet werden, um neue Transaktionen mit beliebigen öffentlichen Ergo
Knoten zu erstellen und zu senden.
2. Ressourcenfreundliche, schnell startende Ergo-Anwendungen
Wie Sie vielleicht wissen, hat die Verwendung von Java für kurzlaufende Prozesse viele Nachteile.
Anwendungen neigen dazu, unter langen Startzeiten und relativ hohem Speicherverbrauch zu leiden.
Lassen Sie uns FreezeCoin mit dem Zeitbefehl ausführen, um
die tatsächliche (Wand-Uhr verstrichene Zeit) zu erhalten, die das gesamte Programm benötigt, um von
Anfang bis Ende zu laufen. Wir verwenden das -l-Flag, um den Speicherverbrauch ebenfalls anzuzeigen.
$ /usr/bin/time -l java -cp build/libs/appkit-examples-3.1.0-all.jar \
org.ergoplatform.appkit.examples.FreezeCoin 1000000000
...
4.97 real 8.41 user 0.69 sys
513703936 maximale Größe des Resident Set
0 durchschnittliche Größe des gemeinsamen Speichers
0 durchschnittliche Größe der nicht geteilten Daten
0 durchschnittliche Größe des nicht geteilten Stacks
125010 Seitenrückgaben
1216 Seitenfehler
0 Swaps
0 Block-Eingabeoperationen
0 Block-Ausgabeoperationen
13 gesendete Nachrichten
86 empfangene Nachrichten
1 empfangene Signale
2384 freiwillige Kontextwechsel
17409 unfreiwillige Kontextwechsel
Wie oben zu sehen, benötigte diese winzige Anwendung 2 parallele Threads fast 4
Sekunden, um zu laufen. Die meiste Zeit kann dem JVM-Start und
dem Hintergrund-JIT-Compiler zugeschrieben werden. Dies ist eine ziemlich unterdurchschnittliche Leistung, und wir wissen, dass wir es viel besser machen können.
Glücklicherweise bietet GraalVM uns die perfekte Lösung.
Wir können dieses inhärente Problem mit der JVM lösen, indem wir den Java-Code
im Voraus in ein natives ausführbares Bild über GraalVM kompilieren. Dies überspringt die Notwendigkeit, den Java-Just-in-Time-Compiler
zur Laufzeit zu verwenden.
Die Erfahrung für uns (die Entwickler, die GraalVM verwenden) ist der konventionellen Compiler wie gcc sehr ähnlich. Beachten Sie,
dass wir möglicherweise zuerst ./gradlew clean shadowJar ausführen müssen.
$ ./gradlew clean shadowJar
$ native-image --no-server \
-cp build/libs/appkit-examples-3.1.0-all.jar\
--report-unsupported-elements-at-runtime\
--no-fallback -H:+TraceClassInitialization -H:+ReportExceptionStackTraces\
-H:+AddAllCharsets -H:+AllowVMInspection -H:-RuntimeAssertions\
--allow-incomplete-classpath \
--enable-url-protocols=http,https org.ergoplatform.appkit.examples.FreezeCoin freezecoin
[freezecoin:3133] classlist: 35,217.78 ms
[freezecoin:3133] (cap): 6,063.07 ms
[freezecoin:3133] setup: 8,268.99 ms
[freezecoin:3133] (typeflow): 60,238.25 ms
[freezecoin:3133] (objects): 33,009.06 ms
[freezecoin:3133] (features): 4,796.86 ms
[freezecoin:3133] analysis: 102,876.01 ms
[freezecoin:3133] (clinit): 11,642.43 ms
[freezecoin:3133] universe: 13,718.96 ms
[freezecoin:3133] (parse): 5,053.18 ms
[freezecoin:3133] (inline): 18,317.24 ms
[freezecoin:3133] (compile): 44,806.82 ms
[freezecoin:3133] compile: 72,288.24 ms
[freezecoin:3133] image: 7,955.29 ms
[freezecoin:3133] write: 2,872.25 ms
[freezecoin:3133] [total]: 243,813.30 ms
Der einfache Befehl oben erzeugt ein vollständiges natives ausführbares Programm namens freezecoin.
Um es zu betonen, dieses ausführbare Programm ist kein bloßer Launcher für die JVM. Tatsächlich verlinkt es nicht zur JVM oder bündelt
die JVM in irgendeiner Weise. native-image kompiliert den FreezeCoin-Code sowie alle
Java-Bibliotheken, von denen er abhängt, bis hinunter zu einfachem Maschinencode.
Wenn wir uns die Bibliotheken ansehen, die freezecoin verwendet, sehen Sie, dass es nur Standard-Systembibliotheken verwendet. Daher können wir nur dieses eine ausführbare Programm auf ein anderes System verschieben,
das keine JVM installiert hat, und es wird dort ohne Probleme ausgeführt.
$ otool -L freezecoin # ldd freezecoin auf Linux
freezecoin:
/usr/lib/libSystem.B.dylib (Kompatibilitätsversion 1.0.0, aktuelle Version 1252.50.4)
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (Kompatibilitätsversion 150.0.0, aktuelle Version 1455.12.0)
/usr/lib/libz.1.dylib (Kompatibilitätsversion 1.0.0, aktuelle Version 1.2.11)
Wenn wir dieses neue freezecoin-ausführbare Programm zeitlich messen, können wir sehen, dass es ungefähr 8x schneller startet und
rund 6x weniger Speicher verwendet. Was das bedeutet, ist, dass Sie diese spürbare Pause, die Sie immer haben, wenn Sie ein
kurzlaufendes Programm mit der JVM ausführen, nicht spüren.
$ DYLD_LIBRARY_PATH=$GRAAL_HOME/jre/lib /usr/bin/time -l ./freezecoin 1800000000
0.43 real 0.15 user 0.03 sys
81289216 maximale Größe des Resident Set
0 durchschnittliche Größe des gemeinsamen Speichers
0 durchschnittliche Größe der nicht geteilten Daten
0 durchschnittliche Größe des nicht geteilten Stacks
20079 Seitenrückgaben
0 Seitenfehler
0 Swaps
0 Block-Eingabeoperationen
0 Block-Ausgabeoperationen
13 gesendete Nachrichten
86 empfangene Nachrichten
0 empfangene Signale
11 freiwillige Kontextwechsel
138 unfreiwillige Kontextwechsel
Dies ist nur einer der großartigen Vorteile von GraalVM, die wir mit Appkit nutzen können.
3. Entwickeln Sie Ergo-Anwendungen in JavaScript, Python, Ruby
GraalVM unterstützt das sogenannte polyglotte Programmieren, bei dem verschiedene Komponenten einer
Anwendung mit der am besten geeigneten Sprache entwickelt werden können und dann
nahtlos zur Laufzeit kombiniert werden. Auf diese Weise kann eine einzigartige Bibliothek, die beispielsweise in
Java geschrieben ist, in einer Node.js-Anwendung, die in JavaScript geschrieben ist, verwendet werden.
Um polyglottes Programmieren zu unterstützen, hat die GraalVM-Plattform ihre eigenen Hochleistungs-
Implementierungen beliebter Sprachen. Wir werden dies für unser FreezeCoin-Beispielprojekt nutzen, um Ihnen zu zeigen, wie einfach es ist, Ihre bevorzugte Sprache zu verwenden.
Bevor Sie die folgenden Beispiele (in JavaScript, Python und Ruby) ausführen, stellen Sie bitte sicher, dass Sie die
Java-Version von FreezeCoin lokal zum Laufen gebracht haben, um sicherzustellen, dass alles korrekt eingerichtet ist.
JavaScript
GraalVM kann JavaScript und
Node.js
Anwendungen sofort ausführen. Es ist kompatibel mit der ECMAScript 2019
Spezifikation.
Zusätzlich akzeptieren die Launcher js und node spezielle --jvm und --polyglot
Befehlszeilenoptionen, die es JS-Skripten ermöglichen, auf Java-Objekte und -Klassen zuzugreifen.
Da dies der Fall ist, kann eine JS-Implementierung von FreezeCoin leicht unter Verwendung der Appkit
API-Schnittstelle geschrieben werden.
Bitte sehen Sie sich den vollständigen Quellcode der FreezeCoin JS
Implementierung
für Details an.
Der folgende Befehl verwendet den node-Launcher, um das FreezeCoin.js-Skript auszuführen.
$ node --jvm --vm.cp=build/libs/appkit-examples-3.1.0-all.jar \
js-examples/FreezeCoin.js 1000000000
Beachten Sie, dass die Pfade im Befehl relativ zum Stammverzeichnis des
ergo-appkit-examples-Projektverzeichnisses sind.
Python
GraalVM kann Python
Skripte ausführen, obwohl
die Python-Implementierung noch experimentell ist (siehe auch
Kompatibilitätsabschnitt
für Details).
Python-Beispiel von
FreezeCoin
kann mit dem folgenden Befehl ausgeführt werden:
$ graalpython --jvm --polyglot --vm.cp=build/libs/appkit-examples-3.1.0-all.jar \
python-examples/FreezeCoin.py 1900000000
Ruby
GraalVM kann Ruby
Skripte mit der
TruffleRuby-Implementierung ausführen, die jedoch noch experimentell ist (siehe auch
Kompatibilitätsabschnitt
für Details).
TruffleRuby zielt darauf ab, vollständig kompatibel mit der Standardimplementierung von Ruby, MRI, Version 2.6.2 zu sein.
Ruby-Beispiel von
FreezeCoin
kann mit dem folgenden Befehl ausgeführt werden:
$ truffleruby --polyglot --jvm --vm.cp=build/libs/appkit-examples-3.1.0-all.jar \
ruby-examples/FreezeCoin.rb 1900000000
4. Ergo Native Shared Libraries
Ein weiterer großer Vorteil von GraalVM ist, dass wir Java-Klassen in eine native Shared Library anstelle eines ausführbaren Programms kompilieren können.
Um dies zu tun, erklären wir eine oder mehrere statische Methoden als @CEntryPoint.
public class FreezeCoin {
...
/**
* Einstiegspunkt, der von C aufgerufen werden kann und {@link FreezeCoin#sendTx} umschließt
*/
@CEntryPoint(name = "sendTx")
public static void sendTxEntryPoint(
IsolateThread thread,
SignedWord amountToSendW,
CCharPointer configFileNameC,
CCharPointer resBuffer, UnsignedWord bufferSize) throws FileNotFoundException {
long amountToSend = amountToSendW.rawValue();
// Konvertieren Sie die C-Zeichenfolgen in die Ziel-Java-Zeichenfolgen.
String configFileName = CTypeConversion.toJavaString(configFileNameC);
String txJson = sendTx(amountToSend, configFileName);
// das resultierende Zeichenfolgen in den bereitgestellten Puffer einfügen
CTypeConversion.toCString(txJson, resBuffer, bufferSize);
}
...
}
Wir können dann in eine Shared Library und eine automatisch generierte Header-Datei kompilieren. Beachten Sie die Verwendung der --shared-Option.
$ native-image --no-server \
-cp build/libs/appkit-examples-3.1.0-all.jar\
--report-unsupported-elements-at-runtime\
--no-fallback -H:+TraceClassInitialization -H:+ReportExceptionStackTraces\
-H:+AddAllCharsets -H:+AllowVMInspection -H:-RuntimeAssertions\
--allow-incomplete-classpath \
--enable-url-protocols=http,https
--shared -H:Name=libfreezecoin -H:Path=c-examples
$ otool -L c-examples/libfreezecoin.dylib
c-examples/libfreezecoin.dylib:
.../c-examples/libfreezecoin.dylib (Kompatibilitätsversion 0.0.0, aktuelle Version 0.0.0)
/usr/lib/libSystem.B.dylib (Kompatibilitätsversion 1.0.0, aktuelle Version 1252.50.4)
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (Kompatibilitätsversion 150.0.0, aktuelle Version 1455.12.0)
/usr/lib/libz.1.dylib (Kompatibilitätsversion 1.0.0, aktuelle Version 1.2.11)
Jetzt haben wir die Möglichkeit, ein C
Programm
zu schreiben, das die Bibliothek verwendet.
Die Schnittstelle zu unserer nativen Bibliothek hat ein wenig
Boilerplate (da die VM einen Heap, Threads, einen Garbage Collector
und mehr verwalten muss), und daher müssen wir eine Instanz erstellen und sie
unserem Hauptthread bereitstellen.
#include <stdlib.h>
#include <stdio.h>
#include <libfreezecoin.h>
int main(int argc, char **argv) {
graal_isolate_t *isolate = NULL;
graal_isolatethread_t *thread = NULL;
if (graal_create_isolate(NULL, &isolate, &thread) != 0) {
fprintf(stderr, "graal_create_isolate Fehler\n");
return 1;
}
char * configFileName = "freeze_coin_config.json";
// erhalten Sie amountToSend von den cmd-Argumenten und rufen Sie die Transaktionsgenerierung auf
long amountToSend = atol(argv[1]);
char result[1024 * 16];
sendTx(thread, amountToSend, configFileName, result, sizeof(result));
// das serialisierte Ergebnis ausgeben
printf("%s\n", result);
if (graal_detach_thread(thread) != 0) {
fprintf(stderr, "graal_detach_thread Fehler\n");
return 1;
}
return 0;
}
Wir können dies mit unseren Standard-Systemwerkzeugen kompilieren und unser ausführbares Programm problemlos ausführen (setzen Sie LD_LIBRARY_PATH=. auf Linux).
$ clang -Ic-examples -Lc-examples -lfreezecoin c-examples/freezecoin.c -o call_freezecoin
$ otool -L call_freezecoin
$ DYLD_LIBRARY_PATH=$GRAAL_HOME/jre/lib ./call_freezecoin 1000000000
5. Debuggen Sie Ihre polyglotte Ergo-Anwendung
Sie können JS, Python und Ruby in IntelliJ debuggen, aber wenn aus irgendeinem Grund dies nicht für Sie funktioniert oder nicht mit Ihrem bevorzugten Editor übereinstimmt, bietet GraalVM eine andere Option.
Alle GraalVM-Sprachen (außer Java) sind mit dem gemeinsamen
Truffle-Framework implementiert.
Truffle ermöglicht es, Werkzeuge wie Debugger einmal zu implementieren und für alle unterstützten Sprachen verfügbar zu machen.
Daher können wir unser Programm mit dem Flag --inspect ausführen, das uns einen Link gibt, den wir in Chrome öffnen können, und das Programm im Debugger pausiert.
$ ruby --polyglot --jvm --inspect --vm.cp=build/libs/appkit-examples-3.1.0-all.jar \
ruby-examples/FreezeCoin.rb 1900000000
Debugger hört auf Port 9229.
Um mit dem Debuggen zu beginnen, öffnen Sie die folgende URL in Chrome:
chrome-devtools://devtools/bundled/js_app.html?ws=127.0.0.1:9229/30c7da1e-7558a47d09b
...
Von hier aus können wir Haltepunkte setzen und die Ausführung fortsetzen. Wenn es bricht, sehen wir
Werte der Variablen, können wieder fortfahren, bis zum nächsten Haltepunkt, und alles tun, was wir von Debuggern erwarten.

Fazit
Und damit gesagt und getan, sehen wir, wie einfach es ist, Appkit zu verwenden, um
Ergo-Anwendungen zu entwickeln. Appkit basiert auf denselben Kernbibliotheken, die
bei der Implementierung des Ergo-Konsensprotokolls verwendet wurden. Diese Bibliotheken umfassen
den ErgoScript-Compiler, Kryptografie, Bytecode-Interpreter, Datenserialisierer
und die anderen Kernkomponenten. Mit GraalVM können wir diese bewährten
und getesteten Komponenten in verschiedenen Anwendungsbereichen ohne Änderungen
oder Neuschreibungen selbst wiederverwenden.
Egal, ob Sie Java, JavaScript, Python oder Ruby verwenden, Sie können
von Appkit mit GraalVM profitieren, um den Prozess der
Interaktion mit der Ergo-Blockchain erheblich zu vereinfachen, während Sie native (d)Apps erstellen.
Bleiben Sie dran. In zukünftigen Beiträgen werden wir Ihnen andere interessante potenzielle
Anwendungen vorstellen, die von Appkit unterstützt werden.
Referenzen
Share post
13. August 2025
12. August 2025
9. Juli 2025
12. Mai 2025
9. Dezember 2024
19. August 2024
