Dieses Mal möchte ich erklären, wie ein intelligenter Vertrag und Beispielanwendungen geschrieben werden, die in der nächsten und nachfolgenden Zeit verwendet werden. Die Artikel bis zum letzten Mal sind wie folgt.
Obwohl es sich um eine Beispielanwendung handelt, möchte ich Folgendes verwenden, das ich zuvor kurz vorgestellt habe.
Diese Anwendung verwaltet Assets sehr einfach und die folgenden 6 intelligenten Verträge werden vorbereitet.
Vertragsname | Funktion |
---|---|
AddTypeContract | Registrieren Sie den Asset-Typ |
ListTypeContract | Holen Sie sich eine Liste der Asset-Typen |
AddAssetContract | Vermögenswerte registrieren |
ListContract | Holen Sie sich eine Liste der Assets |
StateChangeContract | Ändern Sie den Status eines Assets |
AssetHistoryContract | Abrufen des Asset-Nutzungsverlaufs |
Mit diesem intelligenten Vertrag können Sie Vermögenswerte registrieren, anzeigen, ausleihen und zurückgeben. Ich möchte den Inhalt jeder Quelle sofort vorstellen, aber vorher wollen wir die Grundlagen intelligenter Verträge erläutern.
Skalare DL-Smart-Verträge können in reinem Java geschrieben werden. Es ist jedoch nicht gut, es so zu schreiben, wie Sie möchten, daher werde ich die Richtlinien vorstellen.
invoke ()
implementieren.Es gibt eine Einschränkung, dass die externe Bibliothek nicht verwendet werden kann, dies ist jedoch kein Problem, da nur die Seite des intelligenten Vertrags eine solche eindeutige Verarbeitung durchführen muss. Schauen wir uns auch den Basiscode an.
import com.scalar.ledger.contract.Contract;
import com.scalar.ledger.ledger.Ledger;
import java.util.Optional;
import javax.json.Json;
import javax.json.JsonObject;
public class MyContract extends Contract {
@Override
public JsonObject invoke(Ledger ledger, JsonObject argument, Optional<JsonObject> property) {
// read or write data and respond to clients here
}
}
Es wird nur die Methode "invoke ()" beschrieben. Da dies jedoch der tatsächlich aufgerufene Teil ist, muss er implementiert werden.
Das Argument "Ledger" ist ein Objekt für den Zugriff auf Daten vom Typ "Schlüsselwert", die in Scalar DB gespeichert sind. Daten können hinzugefügt / aktualisiert / gelesen / erfasst werden.
argument
ist ein Parameter, der an den Smart Contract übergeben wird und im JSON-Format vorliegt. Es wird empfohlen, für dieses Objekt eine Zeichenfolgeeigenschaft mit dem Namen "nonce" festzulegen. Es wird gesagt, dass ein Wert, der auf der Welt einzigartig ist, gut ist, daher denke ich, dass es besser ist, UUID zu verwenden.
property
ist der Parametersatz bei der Bereitstellung des Smart Contract. Dies kann später nicht mehr geändert werden.
Lassen Sie uns auch ein wenig über die Methode des "Ledgers" erklären.
Das erste ist "Optional
Optional<Asset> opt = ledger.get("somekey");
if (opt.isPresent()) {
Asset asset = opt.get();
int age = asset.age();
JsonObject value = asset.data();
}
Das "Alter", das hier abgerufen werden kann, gibt an, wie oft die Daten aktualisiert wurden, und wird automatisch von 0 gezählt. Als nächstes geht es um "void put (String key, JsonObject value)", das ein JSON-Objekt mit dem angegebenen Schlüssel registriert.
Optional<Asset> opt = ledger.get(name);
if (opt.isPresent()) {
return Json.createObjectBuilder()
.add("message", "Type " + name + " is already registered.")
.build();
}
ledger.put(name, Json.createObjectBuilder().build());
Implizites Schreiben ist für "Put" nicht zulässig. Stellen Sie daher sicher, dass Sie vor dem Schreiben "Get" erhalten.
Als nächstes geht es um "List
AssetFilter filter = new AssetFilter(key);
List<Asset> history = ledger.scan(filter);
for (Asset asset : history) {
String id = asset.id();
int age = asset.age();
JsonObject value = asset.data();
}
Plötzlich kam "AssetFilter" heraus, aber dies ist eine Klasse, mit der Sie den Bereich des Verlaufs angeben können.
//Alter von 5 bis 9 Jahren
new AssetFilter(id).withStartVersion(5, true).withEndVersion(10, false);
//Alter von 5 bis spätestens
new AssetFilter(id).withStartVersion(5, true);
Und soweit ist der grundlegende Teil. Es ist ein bisschen lang her, aber wenn Sie dies berücksichtigen, können Sie die Beschreibung intelligenter Verträge leicht spüren.
AddTypeContract Bei AddTypeContract wird der Asset-Typ registriert. Die gesamte Quelle ist hier Sie können es unter überprüfen, daher möchte ich hier die Punkte extrahieren und erläutern.
public static final String HOLDER_ID = "holderId";
Die erste ist eine wichtige Eigenschaft in dieser Asset-Management-Anwendung. Jeder Smart-Vertrag verfügt über eine Eigenschaft namens "Inhaber-ID", die nur zur Bereitstellungszeit festgelegt werden kann.
if (!property.isPresent() || !property.get().containsKey(HOLDER_ID)) {
throw new ContractContextException("property: `" + HOLDER_ID + "` is mandatory.");
}
Wenn der Smart-Vertrag aufgerufen wird, wird die Eigenschaft wie oben beschrieben überprüft, um die Ausführung durch andere Personen als den bereitgestellten Benutzer zu verhindern. Der Rest ist einfach und der gleiche Name wird überprüft.
Optional<Asset> type = ledger.get(holderId + "-" + name);
if (type.isPresent()) {
return Json.createObjectBuilder()
.add(RESULT, FAILURE)
.add(MESSAGE, "Type " + name + " is already registered.")
.build();
}
ledger.put(holderId + "-" + name, Json.createObjectBuilder().build());
Und schließlich wird der Asset-Typ zum Wert des Schlüssels von "Inhaber-ID +" - "+ TYP" hinzugefügt.
JsonObject newType = Json.createObjectBuilder().add(NAME, name).build();
ledger.get(holderId + "-" + TYPE);
ledger.put(holderId + "-" + TYPE, newType);
ListTypeContract ListTypeContract ist ein Prozess, der eine Liste der registrierten Asset-Typen zurückgibt. Die Quelle ist hier Ich werde.
Da die Verarbeitung von "Inhaber-ID" üblich ist, ist die Verarbeitung einfach, wenn Sie die Erklärung weglassen, da es sich nur um Datenerfassung handelt.
AssetFilter filter = new AssetFilter(holderId + "-" + TYPE);
List<Asset> history = ledger.scan(filter);
if (history.isEmpty()) {
return Json.createObjectBuilder()
.add(RESULT, FAILURE)
.add(MESSAGE, "No types were registered. Use am add-type to create one.")
.build();
}
JsonArrayBuilder builder = Json.createArrayBuilder();
for (Asset h : history) {
JsonObject type =
Json.createObjectBuilder().add(TYPE, h.data().getString(NAME)).add(AGE, h.age()).build();
builder.add(type);
}
JsonArray types = builder.build();
Wenn keine Daten vorhanden sind, wird ein Fehler zurückgegeben, und wenn Daten vorhanden sind, werden diese als Array zurückgegeben.
AddAssetContract Der folgende AddAssetContract ähnelt AddTypeContract, registriert jedoch ein Asset nach Typ. Die Quelle ist hier.
Es ist im Grunde dasselbe wie AddTypeContract, hat jedoch viele erforderliche Argumente.
if (!argument.containsKey(TYPE)
|| !argument.containsKey(ASSET)
|| !argument.containsKey(TIMESTAMP)
|| !argument.containsKey(ID)) {
throw new ContractContextException("wrong argument.");
}
Ich werde die Prüfung des Typs und der Existenz von Vermögenswerten nicht erläutern, aber danach speichern Sie den Kreditstatus und den Namen.
JsonObject assetStatusJson =
Json.createObjectBuilder().add(TIMESTAMP, timestamp).add(STATUS, IN_STOCK).build();
ledger.put(holderId + "-" + id, assetStatusJson);
JsonObject assetNameJson = Json.createObjectBuilder().add(ID, id).add(NAME, name).build();
ledger.put(holderId + "-" + type, assetNameJson);
ListContract Wie Sie sich vorstellen können, ist ListContract im Grunde dasselbe wie ListTypeContract. Dies ist hier Wird sein.
Im Vergleich zu ListTypeContract ist das Argument "type" erforderlich und gibt eine Liste der Assets des angegebenen "type" zurück. Der Grund, warum die Verarbeitung etwas länger dauert, besteht darin, dass der Kreditstatus von einer anderen Verarbeitung erfasst wird.
JsonArrayBuilder assetsBuilder = Json.createArrayBuilder();
for (Asset asset : assetList) {
JsonObject data = asset.data();
if (data.size() == 0) { // initiated one, ignore it
continue;
}
String id = data.getString(ID);
String name = data.getString(NAME);
Optional<Asset> borrowingStatus = ledger.get(holderId + "-" + id);
if (!borrowingStatus.isPresent()) {
/**
* Abnormal case. We found an asset in list but no borrowing status record. Just ignore it
*/
continue;
}
JsonObjectBuilder statusBuilder = Json.createObjectBuilder();
statusBuilder
.add(ID, id)
.add(NAME, name)
.add(TIMESTAMP, borrowingStatus.get().data().getJsonNumber(TIMESTAMP).longValue())
.add(STATUS, borrowingStatus.get().data().getString(STATUS));
if (borrowingStatus.get().data().containsKey(HOLDER_ID)) {
statusBuilder.add(HOLDER_ID, borrowingStatus.get().data().getString(HOLDER_ID));
}
assetsBuilder.add(statusBuilder.build());
}
StateChangeContract Der folgende StateChangeContract ist der Hauptteil dieser Anwendung. Verantwortlich für die Verwaltung des Ausleih- / Rückgabestatus. Die Quelle ist hier.
Der Vorgang ist einfach, auch wenn er als main bezeichnet wird. Wenn derselbe Status wie der aktuelle angegeben wird, wird ein Fehler zurückgegeben.
if (data.getString(STATUS).equals(newStatus)) {
return Json.createObjectBuilder()
.add(RESULT, FAILURE)
.add(
MESSAGE,
String.format(
"Asset is already %s.", ON_LOAN.equals(newStatus) ? "borrowed" : "returned"))
.build();
}
Der Rest ist der Prozess der Änderung des Status zum Zeitpunkt der Ausleihe / Rückgabe.
JsonObjectBuilder newDataBuilder = Json.createObjectBuilder();
if (newStatus.equals(ON_LOAN)) {
newDataBuilder.add(HOLDER_ID, holderId).add(TIMESTAMP, timestamp).add(STATUS, newStatus);
} else if (newStatus.equals(IN_STOCK)) {
if (!data.containsKey(HOLDER_ID)) {
return Json.createObjectBuilder()
.add(RESULT, FAILURE)
.add(MESSAGE, "Can not return asset without holderId")
.build();
}
if (!data.getString(HOLDER_ID).equals(holderId)) {
return Json.createObjectBuilder()
.add(RESULT, FAILURE)
.add(MESSAGE, "Can not return asset borrowed by another user")
.build();
}
newDataBuilder.add(TIMESTAMP, timestamp).add(STATUS, newStatus);
}
ledger.put(holderId + "-" + id, newDataBuilder.build());
Hier wird die Prüfung mit "Inhaber-ID" durchgeführt, und eine Warnmeldung wird auch ausgegeben, wenn der Benutzer anders ist.
AssetHistoryContract Der endgültige AssetHistoryContract ist ein Prozess, der den bisherigen Kreditverlauf durch Angabe der ID des Assets zurückgibt. Die Quelle ist hier Ich werde.
Es ist eine Spezifikation, die einen Fehler zurückgibt, wenn kein Verlauf vorhanden ist.
AssetFilter filter = new AssetFilter(holderId + "-" + id);
List<Asset> borrowingHistory = ledger.scan(filter);
if (borrowingHistory.isEmpty()) {
return Json.createObjectBuilder()
.add(RESULT, FAILURE)
.add(MESSAGE, "This asset is not registered")
.build();
}
Wenn es einen Verlauf gibt, wird dieser als Array zurückgegeben.
JsonArrayBuilder builder = Json.createArrayBuilder();
JsonObjectBuilder borrowingRecordBuilder = Json.createObjectBuilder();
for (Asset history : borrowingHistory) {
borrowingRecordBuilder
.add(TIMESTAMP, history.data().getJsonNumber(TIMESTAMP).longValue())
.add(STATUS, history.data().getString(STATUS))
.add(AGE, history.age());
if (history.data().containsKey(HOLDER_ID)) {
borrowingRecordBuilder.add(HOLDER_ID, history.data().getString(HOLDER_ID));
}
builder.add(borrowingRecordBuilder.build());
}
Es war also eine Erklärung, wie man einen intelligenten Vertrag schreibt und woher eine Asset-Management-Anwendung stammt. Ab dem nächsten Mal möchte ich darauf eingehen, wie der Emulator mit dieser Quelle verwendet wird.
Recommended Posts