Patterns für dezentrale Apps auf Basis von Ethereum
Baust du die Applikation auf Basis eines Cloud-Dienstes wie AWS oder Azure auf oder nutzt du eine Blockchain-Plattform wie Ethereum? Vielleicht ist es aber auch eine Kombination aus beidem, wie es beispielsweise Ethlance.com vormacht. Wie immer in der IT gibt es viele Wege, die nach Rom führen. In diesem Artikel wirst du zwei Patterns kennenlernen, mit denen du dezentrale Apps (kurz Dapps) auf Basis von Ethereum entwickeln kannst.
Ein einfacher Use-Case, der bereits Probleme macht
Nehmen wir als Beispiel einmal einen einfachen Use-Case, bei dem ein Kunde irgendeinen beliebigen Vertrag eingeht. Dazu quittiert der Kunde – ähnlich wie beim Annehmen eines DHL-Paketes – auf einem Gerät mit seiner Unterschrift. Warum sollte man etwas so Simples mit einer Blockchain abbilden? Reicht in diesem Fall nicht ein einfacher Lambda-Service samt Datenbank auf AWS aus? Das kostet nur ein paar Euro im Monat und gut ist.
Das Problem ist nur, dass mit zunehmender Anzahl der Kunden und Transaktionen auch die Anforderungen an die Revisionssicherheit wachsen. Und in diesem Fall werden die paar Euro, die du anfangs für einen Cloud-Service ausgegeben hast, sehr schnell viel mehr, da Zugriffsrechte, Unveränderbarkeit der Daten und Archivierungsmöglichkeiten aktiviert werden müssen. Und genau hier bricht die Stunde der Blockchain an, da sie per se revisionssicher ist.
Aber schauen wir nochmals auf den einfachen Use-Case mit der Unterschrift. Wir nehmen nun an, wir hätten uns dafür entschieden, alles auf Basis der Ethereum-Plattform zu entwickeln. Wie aus Abbildung eins hervorgeht, würde eine iOS- oder Android-App den Vertragsabschluss ermöglichen. Sobald der Kunde seine Unterschrift auf dem Display tätigt, speichert die App sämtliche Transaktionsdaten samt des Unterschriftenbildes in einem sogenannten Smart Contract ab. So weit, so gut.
Allerdings meiden Dapp-Entwickler dieses Pattern #0. Der Grund hierfür ist simpel: Das Speichern von Daten in der Ethereum-Plattform ist extrem teuer. Ein paar Kilobyte Daten, die bereits von kleinen Bildern wie Unterschriften erfordert werden, können mehrere Hundert Euro einmalige Kosten verursachen. Dafür sind sie aber lebenslang abrufbar. Daher versuchen Ethereum-Entwickler, möglichst sparsam mit dem Speichern von Daten zu sein. Weniger ist mehr, lautet die Devise.
Transaktionsorchestrierung über den Dapp-Client
Um die Kosten der Speicherung von Transaktionsdaten zu reduzieren, wurden bereits 2015 auf der Devcon One Design-Patterns für Dapps diskutiert. Den meisten gemein ist, dass sie, wie in Abbildung zwei dargestellt, eine Trennung der Daten von der Blockchain vorsehen:
- Im Client wird die Transaktion in zwei Teile geteilt
- Die Bilddaten werden in ein dezentrales Dateisystem gespeichert, das wiederum einen Hash-Wert der gespeicherten Datei zurückliefert
- Anschließend wird im Smart Contract eine Transaktion durchgeführt, die den Hash-Wert der Bilddaten in die Blockchain schreibt
- Der Client muss diese Logik implementieren und die geteilte Transaktion orchestrieren
Das ist nicht optimal, da server-seitige Logik in den Client verlagert wird. Ebenso muss der Client dann dafür sorgen, dass eventuelle Transaktionsabbrüche auf der einen oder anderen Seite wieder rückgängig gemacht werden müssen.
Transaktionsorchestrierung über den Smart Contract
Seit einiger Zeit besteht aber durch die Einführung eines NodeJS-Oracles die Möglichkeit, mehr Code auf die Serverseite zu verlagern. In diesem Fall kann der Großteil Logik auf der Ethereum-Plattform implementiert werden.
Wie aus Abbildung drei hervorgeht, sendet der Client sämtliche Transaktionsdaten (inklusive des Unterschriftenbildes) an den ethereum-basierten Smart Contract. Der speichert dann die Bilddaten in einem IPFS-Dateisystem ab (in unserem Fall infura.io). Der Hash-Wert der Speicherung wird dann direkt vom Smart Contract selbst verarbeitet und in die Blockchain geschrieben.
Der Solidity-Code dazu sähe wie folgt aus:
pragma solidity ^0.4.25;
import "./usingCaptainJS_v2.sol";
contract simpleIPFSdemo is usingCaptainJS {
mapping(uint => string) signaturesByUserId;
event ContractSignedEvent(uint userId);
function SignContract(uint userId, string signatureAsBase64) public payable {
string memory fullCommand = concat("ipfs:add:ipfs.infura.io:5001:", signatureAsBase64);
string memory fileName = concat("signatureOfUser_", uintToString(userId), ".png");
string memory npm = "";
uint maxRuntime = 3;
uint gas = DEFAULT_GAS_UNITS;
uint price = DEFAULT_GAS_PRICE;
Run(userId, fullCommand, fileName, npm, maxRuntime, gas, price);
}
function CaptainsResult(uint userId, string hashValue) external onlyCaptainsOrdersAllowed {
signaturesByUserId[userId] = hashValue;
emit ContractSignedEvent(userId);
}
function() payable { }
}
Fazit und Ausblick
Bitcoin-Bashing, Blockchain-Bashing und so weiter sind heutzutage erlaubt. Viele Kryptowährungen haben im vergangenen Jahr 80 Prozent ihres Wertes verloren. Selbst McKinsey wagt sich nun aus der Deckung. Nachdem sie 2017 noch gesagt haben, dass kreative Unternehmen von Blockchain profitieren könnten, revidieren sie ihre Aussagen Anfang 2019 wieder. Aber nachdem die Luft aus der Kryptoblase gelassen wurde, haben wir nun ein solides Fundament. Wer jetzt nicht tot ist, der lebt weiter.
Und die Ethereum-Plattform ist definitiv ein Überlebender. Es hat einige Jahre gebraucht, bis Entwickler angefangen haben, Mehrwerte auf Basis der Ethereum-Plattform zu schaffen. Ähnlich wie es Entwickler von Apps auf Basis der iOS-Plattform getan haben.
Nun beginnt aber die Kryptophase zwei und Investoren und Unternehmer fokussieren sich endlich auf den Nutzen. Und dieser Nutzen basiert im Wesentlichen auf Mehrwerten, die durch Blockchain geschaffen werden. Mit den hier vorgestellten Patterns lassen sich kostenoptimierte und revisionssichere Applikationen für das digitale Zeitalter entwickeln. Inwieweit Entwickler das im Jahr 2019 umsetzen, werden wir heute in einem Jahr sehen.
Was hat denn Pattern #1 gegenüber Pattern #2 für Vorteile? Oder ist Pattern #2 schlichtweg eine bessere Weiterentwicklung?