Ethereum ist ein Blockchain-basiertes, offenes System, das im Gegensatz zu Bitcoin die Idee von „Smart Contracts“ als zentrales Thema hat. Damit können beliebige Geschäftsmodelle durch eine Form automatischer Agenten abgebildet werden, die auf Transaktionen reagieren und deren Code für jeden einsehbar ist. Die Regeln, die man normalerweise in juristischen Verträgen abbildet, werden damit zu ausführbaren Programmen – und die Akteure, die sich an diese Regeln halten, durch „autonome Organisationen“ ersetzt. In diesem Artikel stellen wir die Technik hinter Ethereum kurz vor und zeigen die Möglichkeiten an einem einfachem Beispiel auf.
Ethereum ist neben dem Urvater Bitcoin die zweite bekannte öffentliche Blockchain-Implementierung. Im Kern beruht sie auf den selben Konzepten: Der Zugang ist nicht begrenzt, für die Validierung von Blöcken kommt das Proof-of-work-Konzept zum Einsatz und mit Ether gibt es analog zu Bitcoin eine Währung, die universell akzeptiert wird. Der wesentliche Unterschied zwischen Ethereum und Bitcoin ist die Rolle, die ausführbarer Code spielt. Bereits in Bitcoin gibt es die Möglichkeit, als Teil von Transaktionen kleine Skripte in die Blockchain zu stellen. Tatsächlich werden diese sogar bei den Basistransaktionen wie dem Transfer von Bitcoins benutzt: Noch nicht ausgegebene „Outputs“ aus Transaktionen (UTXOs) kann nur ausgeben, wer einen Private Key besitzt, der für die Übergabe eines Parameters an ein Skript benutzt werden muss, damit dieses „true“ zurückliefert. Dieses Skript wird vom Absender in die Transaktion geschrieben, der das virtuelle Geld damit nur für gewünschten Empfänger zugänglich macht. Die Skriptsprache in Bitcoin ist eine bewusst limitierte, stackbasierte Sprache, die nicht Turing-vollständig ist. Damit wird zwar sichergestellt, dass keine Endlosschleifen entstehen und damit die Sicherheitsrisiken begrenzt sind, allerdings sind genau damit den Möglichkeiten, intelligente Skripte zu implementieren, klare Grenzen gesetzt.
An genau dieser Stelle setzt Ethereum an und stellt eine virtuelle Maschine zur Verfügung, die beliebig komplexe Programme ausführen kann. Innerhalb der Ethereum-Plattform gibt es damit neben Accounts (Konten für klassische, in der Regel menschliche Benutzer) auch Contracts. Dabei handelt es sich um eine besondere Art von Konto, eine Art Agent, der basierend auf einem Programm agiert, das in den Bytecode der Ethereum VM übersetzt wurde. Um Kontrakte in die Ethereum-Plattform zu stellen, verwenden Entwickler eine Programmiersprache, die in Ethereum-Bytecode übersetzt wird. Dieser Bytecode wird dann im Rahmen einer Transaktion in die Plattform übertragen und als Teil eines Blockes validiert. Die so erstellte Anwendung wird so selbst Teil der Plattform. Sie wird dezentral ausgeführt und daher auch als Distributed App (kurz „DApp“) bezeichnet.
Selbst das Wallet, das verwendet wird, um (im übertragenen Sinne) das eigene virtuelle Geld zu verwalten, ist nur eine solche DApp. Damit erklärt sich auch der Unterschied zwischen den beiden wichtigsten Ethereum-Clients, der am Anfang verwirrend sein kann: Mist ist der Name eines DApp-Browsers, einer Anwendung, mit der man mit beliebigen Kontrakten der Ethereum-Plattform interagieren kann. Ethereum Wallet ist der Name eines Clients, der auf Mist basiert, aber spezifisch den Zugriff auf eine voreingestellte Anwendung erlaubt, nämlich Wallet.
Ethereum ist damit eine programmierbare Blockchain-Plattform, die DApps oder auch „Smart Contracts“ unterstützt. Der Gedanke ist außerordentlich reizvoll, weil sich so mit Hilfe einer relativ einfachen Programmierumgebung sehr leicht Anwendungen erstellen lassen, die von den Blockchain-Vorteilen profitieren. Gleichzeitig sorgt die Möglichkeit zum unkomplizierten, öffentlichen Zugriff dafür, dass sich sehr leicht Experimente starten und auf Akzeptanz im Ethereum-Markt prüfen lassen.
Da die Ethereum-VM beliebig komplexe Programme ermöglicht, die dezentral validiert und damit ausgeführt werden müssen, muss sichergestellt sein, dass niemand über Gebühr Ressourcen verbraucht und z.B. die gesamte Ethereum-Plattform in eine Endlosschleife schickt. Dazu müssen Interaktionen mit Kontrakten vom Aufrufer mit „Gas“ (im Sinne von „Treibstoff“) ausgestattet werden. Die Ausführung des Programmes verbraucht diesen Treibstoff – vereinfacht gesagt kostet jede Instruktion eine bestimmte Menge. Ist der gesamte Treibstoff verbraucht, wird die Programmausführung beendet.
Sehen wir uns die Nutzung an einem einfachen Beispiel an.
Hello ShortR
Die App-Entwicklung mit Ethereum demonstrieren wir anhand von ShortR: ShortR ist ein einfacher URL-Shortener (Link-Verkürzer) auf Basis von Ethereum. Im Vergleich zu ähnlichen Diensten speichert ShortR das Mapping zwischen verkürzter und vollständiger URL unveränderlich und transparent auf der Ethereum-Blockchain. Die Daten sind somit im dezentralen Netzwerk gespeichert und selbst nach potenzieller Insolvenz eines solchen Dienste-Anbieters weiter verfügbar. Außerdem muss sich kein Nutzer Sorgen machen dass der Anbieter einen Link manipuliert und ihm somit ein anderes Ziel unterschiebt.
Die Stunde 0
Neben dem produktiven Main Network betreibt das Ethereum-Projekt auch ein Testnet. Keines der beiden öffetlichen Netzwerke ist für den Einstieg in die Entwicklung optimal. Die ersten Schritte wollen wir stattdessen mit einem eigenen Ethereum-Node auf unserem Entwicklungsrechner durchführen. Somit ersparen wir uns die fortlaufende gigabyte-zerrende Synchronisation und agieren autark vom Netzwerk.
Der Start einer jeden Blockchain ist der Genesis-Block - der erste Block in der
Kette und der einzige Block ohne Vorgänger. Während im
Bitcoin-Netzwerk der Genesis-Block in der Software festgeschrieben ist, kann
dieser bei Ethereum selbst definiert werden. Andere Nodes validieren hierüber
die Blockchain und akzeptieren neue Blöcke nur bei identischen Genesis-Block.
Über die Definition eines eigenen Genesis-Block lassen sich also beliebig viele
private Blockchains erstellen. Nach Installation von Ethereum und dem Mist-Browser
definieren wir den Genesis-Block in einem von uns erstellten Verzeichnis in der
Datei genesis-block.json
:
Nach erfolgter Initialisierung kann der Ethereum-Node gestartet werden:
Über die übergebenen Kommandozeilenparameter starten wir den Node in einem privaten Modus, aktivieren das RPC-Interface und öffnen die interaktive JavaScript-Konsole. Über das RPC-Interface können Ethereum-Clients wie Mist oder die später vorgestellte Web-App mit dem Node interagieren.
Im nun laufenden Ethereum-Node fehlt uns jetzt noch ein Account um Ether zu
verwalten und Verträge zu deployen. Wir erstellen einen Account mit dem Passwort
secret
, setzen diesen Account als Begünstigten für das Mining und starten
anschließend das Mining unseres Nodes. Dadurch sollte der von uns erstellte
Account nach und nach Belohnungen in Form der Ethereum-Währung Ether erhalten.
All das führen wir in der JavaScript-Konsole aus:
Anschließend starten wir den Mist-Browser und verbinden diesen mit dem
RPC-Interface unseres Ethereum-Nodes. Unter macOS machen wir das mit folgendem
Kommandozeilenbefehl: /Applications/Mist.app/Contents/MacOS/Mist --rpc http://localhost:8545
.
Die grafische Oberfläche des Mist-Browser startet nun (s. Abb. 1). Unser Node ist bereit für die Entwicklung.
Kontrakt-Entwicklung
Zur Entwicklung unseres Kontraktes verwenden wir Solidity, eine JavaScript-ähnliche, allerdings statisch getypte, objektorientierte Ethereum-Sprache, die praktische Datentypen für die Entwicklung von Verträgen enthält. Für die Entwicklung stehen sowohl Kommandozeilenwerkzeuge wie auch eine IDE-Unterstützung zur Verfügung. Wir benutzen der Einfachheit halber den Browser Mist und erstellen unseren einfachen Kontrakt direkt im dafür vorgehesehen Editorfenster.
Unser Kontrakt ist folgendermaßen aufgebaut:
Die erste Zeile (das so genannte Version-Pragma) beschreibt mit welcher
Compiler-Version unser Kontrakt kompiliert werden soll (in diesem Fall
mindestens 0.4.8). Mit dem Schlüsselwort contract
definieren wir die Verträge
Owned
und Shortr
. Funktionen eines Kontraktes sind in der Ethereum-VM von
jedermann aufrufbar. Unser Kontrakt hingegen besitzt eine Funktion die dem
Vertagsbesitzer als Administrator vorbehalten sein soll. Die hierfür notwendige
technische Logik definieren wir in dem Kontrakt Owned
und geben diese mit
Hilfe des Vererbungskonzepts von Soldity an den Shortr
-Kontrakt weiter. Dieses
Muster findet man in diversen Kontrakten der Ethereum-Blockchain.
Bereits hier wird die hohe Verantwortung der Entwickler deutlich da sie in Gänze für die Verträge verantwortlich sind. Dies schließt die Sicherheit explizit mit ein. Nach dem Deployment leben die Kontrakte in der Ethereum-Blockchain, führen dort ein Eigenleben und können nicht ohne weiteres geändert werden. Diese Erfahrung haben auch die Entwickler von „The Dao“ gemacht (siehe Kasten, Das DAO-Desaster). Die Solidity-Dokumentation beschreibt unter dem Punkt Security Considerations gängige Probleme sowie Empfehlungen für Entwickler.
Das DAO-Desaster
Decentralized Autonomous Organization (DAO) nennt man in der Ethereum-Community Kontrakte, die der Kollaboration nach vordefinierten Regeln dienen, analog zu den Gesellschafter- und Dienstleistungsverträgen eines Unternehmens. Der Gedanke ist reizvoll: Die Organisation ist nicht von einzelnen Personen abhängig, denen man vertrauen muss, sondern verbindlich durch den Code des Contracts definiert.
Eine solche DAO – genannt TheDAO – hat es zu trauriger Berühmtheit gebracht. Angelegt als Investmentfonds, der nach definierten Regeln Dinge kaufen und verkaufen sollte, war es bis zum einem definierten Zeitpunkt möglich, sich als Anteilseigner mit einem ensprechendem Ether-Investment einzukaufen. Die Resonanz war überwältigend: In kürzester Zeit war ein Investitionsvolumen von über 100 Mio. US-Dollar erreicht und ist damit bisher das größten Croudfunding-Projekt überhaupt. Dumm nur, dass der Contract-Code, der bekanntlich die alleinige Wahrheit darstellt, eine Sicherheitslücke enthielt, die von Unbekannten ausgenutzt wurde, um einen großen Teil dieser Summe zu „stehlen“. Die Anführungszeichen sind bedeutungsschwanger: Tatsächlich ist es Interpretationsfrage, ob das Geld tatsächlich gestohlen wurde, denn der Grund war nicht etwa ein Bug in der Ethereum-Plattform selbst, sondern schlicht ein von den meisten Anteilseignern sicherlich nicht gewünschtes Fehlverhalten des Codes. Was ist in einem solchen Fall zu tun? In der aktuellen, realen Welt würde man Strafverfolgungs- und Justizbehörden einschalten, die das, was passiert ist, auf Verstöße gegen geltendes Recht untersuchen. In diesem Fall könnte man jedoch mit Fug und Recht behaupten, dass der Code das geltende Recht ist…
Innerhalb der Ethereum-Community wurde entschieden, den Diebstahl mit einem Trick rückgängig zu machen: Es wurde eine neue Version der Ethereum-Software veröffentlicht, die alle DAO-bezogenen Transaktionen (also die ursprüngliche sowie alle daraus resultierenden) ignoriert, also praktisch die Geschichte zugunsten der Betrogenen „fälscht“. Eine solche Entscheidung kann bei Ethereum analog zu Bitcoin keine einzelne Person oder Organisation treffen – stattdessen wird sie von denjenigen, die Ethereum-Knoten betreiben, durch ihre Entscheidung, auf die neue Version zu wechseln umgesetzt oder eben nicht. Bitcoin-Veteranen und Blockchain-Enthusiasten werfen dem Projekt seitdem vor gegen das höchste Gut einer Blockchain verstoßen zu haben: der Unveränderlichkeit (Immutability). Beim Thema TheDAO hat sich gezeigt, dass dies nicht einstimmt passieren muss: Die Community hat sich gespalten in die Mehrheit, die den (je nach philosophischer Position) geschichtsfälschenden oder betrugsverhindernden „Fork“ unterstützt und diejenigen, die ihn ablehnen. Aus einem System sind damit zwei geworden und es gibt neben Ether (ETH) nun auch Ether Classic (ETC).
Die Business-Logik unseres Linkverkürzers ist im Shortr
-Kontrakt definert:
Die wichtigsten Funktionen des Kontraktes sind shorten(linkId, fullUri)
zum
Hinzufügen eines neuen bzw. getUri(linkId)
zum Lookup eines bestehenden Links.
Die Funktion mit dem gleichen Namen wie der Kontrakt (shortr(initialBaseUrl)
) ist
automatisch der Konstruktur unseres Vertrages. Auf Grundlage des Konstruktors
bietet uns der Mist-Browser Formularfelder für die initialen Werte beim Deployment
an (s. Abb. 2).
Beim Hinzufügen eines neuen Links wird eine Struct-Datenstruktur UriRecord
bestehend
aus der vollen Adresse des Links und der Account-Adresse des Erstellers unter
der verkürzenden linkId
in das interne Mapping uriRegistry
geschrieben.
Der Einfachheit halber generieren wir hier keine kryptische LinkId sondern der
Nutzer kann diese in unserem Beispiel selbst wählen. Dieser Vorgang wird abschließend über
das Event NewShortUri
publiziert sodass Clients auf dieses Ereignis reagieren können.
Die Funktion setBaseUrl(url)
ist die bereits erwähnte Funktion deren Aufruf ausschließlich
dem Vertragsbesitzer vorbehalten werden soll. Mit dieser Funktion kann der Administrator
nachträglich die baseUrl von ShortR ändern (z.B. von http://url.to/abc auf http://shortr.to/abc).
Dies geschieht mit Hilfe des an die Funktion herangestellten Modifier onlyOwner
. Hierbei
handelt es sich um eine besondere Funktion aus unserem Owned
-Kontrakt:
Die Funktion stellt sicher dass nur der Vertragsbesitzer berechtigt ist die annotierte Funktion aufzurufen. Andernfalls wird der Funktionsaufruf unterbrochen. Der Unterstrich hier wird zur Laufzeit durch den Funktionskörper der annotierten Funktion ersetzt.
Etwas auf die Kette kriegen
Den von uns verfassten Soldity-Quellcode deployen wir mit Hilfe des
Mist-Browser in unseren lokalen Ethereum-Node. Hierzu wählen wir in Mist die
Schaltflächen CONTRACTS
, DEPLOY NEW CONTRACT
und kopieren den Quellcode
in das SOLIDITY CONTRACT SOURCE CODE
-Fenster. Nach erfolgreicher Syntaxprüfung
können wir den Kontrakt deployen.
Rechts neben dem Sourcecode-Fenster wählen wir unter SELECT CONTRACT TO DEPLOY
(s. Abb. 2) den Kontrakt mit dem Namen Shortr
und übergeben darunter als
Konstruktor-Parameter eine initiale Base-Url (z.B.: http://url.to/
).
Wir starten das Deployment über die Schaltfläche DEPLOY
. Dabei legen wir die
Menge an Gas fest, die uns dies wert ist und bestätigen die Transaktion mit
dem Passwort unseres Accounts (secret, s. Abb. 3).
Damit wird unser Kontrakt der Plattform als Teil einer Transaktion bekannt gemacht, auf deren Validierung wir nun warten müssen. Dies sollte nicht länger als eine Minute dauern. Danach können wir mit dem Kontrakt interagieren, indem wir seine Methoden aufrufen:
Zugriff über Drittanwendungen
Neben der Kontrakt-Interaktion mit dem Mist-Browser (s. Abb. 4) wollen wir zeigen wie Drittanwendungen mit Verträgen und der Ethereum-Blockchain interagieren können. Hierzu haben wir eine auf NodeJS basierende Webb-App entwickelt (s. Abb. 5):
Die App erlaubt neben dem Blockchain-Lookup nach linkId und anschließender
Weiterleitung auf die zugehörige URL auch die Anlage neuer Links.
Die Anlage neuer Links kann der Nutzer über ein HTML-Formular vornehmen.
Der Lookup und Weiterleitung einer linkId erfolgt über den Aufruf von http://localhost:300/abc
.
Für JavaScript-Anwendungen stellt das Ethereum-Projekt mit web3.js eine Ethereum-API als NPM-Modul zur Verfügung. Durch Nutzung des Moduls können wir in unserer Anwendung das gleiche web3-Objekt nutzen wie der Ethereum Mist-Browser.
Der folgende Quellcode zeigt den Aufruf der getUri('abc')
-Funktion unseres
Shortr-Kontrakts:
Für den Aufruf von Kontrakt-Funktionen sind zwei Informationen notwendig: Die
Kontrakt-Adresse sowie das Kontrakt-ABI (Application Binary Interface).
Die Kontrakt-Adresse wird uns nach erfolgreichen Deployment im Mist-Browser
angezeigt. Das Application Binary Interface ist eine Schnittstellenbeschreibung
im JSON-Format. Die Beschreibung ist bereits zur Kompilierzeit bekannt und somit
statisch. In unserem Beispiel kompilieren wir unseren Vertrag einmal zur Laufzeit
und referenzieren das Kontrakt-ABI. Im Mist-Browser kann die Schnittstellenbeschreibung
beim deployten Kontrakt über die Schaltfläche Show Interface
eingesehen werden.
Der Aufruf der Funktion getUri(linkId)
hat keinen Einfluss auf den Zustand des
Vertrages. Aus diesem Grund ist für den Aufruf der Funktion keine Transaktion
notwendig. Der Aufruf ist damit „kostenlos“ und verbraucht kein Gas.
Das Speichern eines neuen Links (shorten(linkId, fulluri)
) hingegen persistiert
einen neuen Eintrag in der Ethereum-Blockchain. Bei dieser Aktion ist eine
Blockchain-Transaktion notwendig:
Zwischenfazit nach Beispiel
Das Beispiel ist mit Absicht sehr simpel gehalten: So wird unter anderem bei der Erstellung eines neuen Mappings ein bestehendes einfach überschrieben. In einer realistischen Implementierung würde man genau das ausschließen wollen. Aber es demonstriert den Prozess, Anwendungen in die Ethereum-Blockchain zu deployen und erfüllt damit den Zweck: Wie bei den meisten echten Szenarien wird nicht alles mit Blockchain-Mitteln umgesetzt, sondern nur der Teil, der davon profititiert. Ebenso üblich ist der Mechanismus, mit dem sich der Besitzer besondere Rechte einräumt. Und schließlich: Ist sie erst einmal produktiv, verhält es sich mit der Ethereum-Anwendung wie mit jeder Blockchain-Transaktion – sie ist nicht mehr rückgängig zu machen und führt ein Eigenleben.
Fazit
Der Ansatz von Ethereum, eine programmierbare Plattform zur Verfügung zu stellen, ist innovativ und ermöglicht zahlreiche Lösungen, die auf anderen Plattformen nicht oder nur mit großem Aufwand möglich sind. Der Code, der als Teil des Kontraktes deployt ist, spiegelt dabei die verbindliche Wahrheit wider – im Guten wie im Schlechten. Dessen sollte man sich unbedingt bewusst sein und je nach Risiko und Kritikalität geeignete Qualitätssicherungsmaßnahmen durchführen. Die modern wirkende, ansprechend gestaltete Plattform und die gute Dokumentation können nicht darüber hinwegtäuschen, dass es sich noch um ein sehr junges Projekt handelt, das durchaus noch unter Stabilitätsproblemen leidet. Wie bei allen anderen Distributed Ledger-Lösungen auch ist es nicht angeraten, ohne Not die Lebensersparnisse darin anzulegen. Für Experimente mit Smart Contracts in der Blockchain ist Ethereum jedoch hervorragend geeignet.