Im zweiten Teil der Blogreihe über Blockchain ging es um Smart Contracts. In diesem Teil zeigen wir als Beispiel eine ĐApp, die wir mithilfe von Smart Contracts auf Ethereum implementiert haben.
Bookchain ist eine dezentral organisierte Bücherei, in der die Beschaffung, Lagerung und Ausleihe von Büchern durch die Benutzer erfolgt. Es gibt kein zentrales Gebäude und keine Angestellten in der Bücherei. So wie Uber keine Fahrzeuge und Airbnb keine Immobilien besitzt, braucht auch Bookchain keine eigenen Bücher. Die Bücher liegen bereits in den Bücherregalen der Benutzer. Es geht um Bücher, die man irgendwann gekauft oder geschenkt bekommen hat und in der Zukunft nicht nochmal lesen möchte. Es könnten Bücher sein, die man während des Studiums erworben hat, um sich auf einzelne Prüfungen vorzubereiten. Oder Bücher, die Eltern für ihre Kleinkinder gekauft haben, die inzwischen herangewachsen sind. Wenn man sie nicht an Freunde oder Verwandte verschenken oder auf Ebay verkaufen möchte, kann man sie mithilfe von Bookchain anderen Lesern bereitstellen und den Kaufpreis erstattet bekommen.
Benutzer können die bereits registrierten Bücher durchsuchen. Wenn sie nicht fündig werden, können sie die Community fragen, ob jemand das gesuchte Buch besitzt und registrieren könnte. Wenn ein Besitzer sein Buch registriert, stellt er es erstmal allen Benutzern der Bücherei zur Verfügung. Benutzer können das gefundene Buch beim aktuellen Besitzer anfragen und nach Hinterlegung einer Kaution übernehmen. Diese Kaution dient dazu, die Weitergabe auf beiden Seiten abzusichern. Benutzer, die Bücher behalten, beschädigen oder sich anderweitig nicht an die Regeln halten, verlieren ihre Kaution. Wenn der Benutzer das Buch gelesen hat, kann er es selbst weitergeben und bekommt seine Kaution zurück. Der ursprüngliche Eigentümer des Buches bekommt bei jeder Weitergabe einen Teil des Kaufpreises erstattet. Damit tragen alle Leser gemeinsam die Kosten eines Buches. Darüber hinaus kann er auch verfolgen, wo sich sein Buch befindet und wer es wann ausgeliehen hat. Denkbar wäre auch ein Reputationssystem, damit Benutzer sich gegenseitig bewerten können. Gegenstand der Bewertung könnte das Benutzerverhalten wie etwa die Einhaltung des vereinbarten Übergabetermins oder der Zustand der Bücher bei der Übergabe sein.
Wie läuft die Ausleihe im Detail ab? Wir gehen sie Schritt für Schritt an einem Beispiel durch. Peter hat vor langer Zeit ein Buch gekauft und entscheidet sich, es weiterzugeben. Er registriert es mithilfe der ISBN auf Bookchain. Das Buch ist sofort in seinem virtuellen Bücherregal sichtbar und freigegeben. Ein paar Tage später sieht Charly das Buch in der App und findet das Exemplar von Peter. Er fragt bei Peter an und schickt ihm eine kurze Nachricht mit seinen Kontaktdaten. Von beiden wird eine Kaution einbehalten. Peter sieht die Anfrage in seinem Bücherregal und bestätigt sie. Damit ist das Exemplar für Charly reserviert und für andere nicht mehr sichtbar. Charly sieht die Bestätigung bei seinen Anfragen. Kurze Zeit später kontaktiert Peter Charly und sie verabreden sich zur Übergabe des Buches. Beim Treffen übergibt Peter Charly das Buch und Charly bestätigt die Übernahme. Peter bekommt seine Kaution zurück. Das Buch verschwindet aus dem Bücherregal von Peter und erscheint im Bücherregal von Charly. Vorerst ist es noch gesperrt, damit Charly es in Ruhe lesen kann ohne gleich eine Anfrage zur Weitergabe zu bekommen. Nachdem Charly das Buch gelesen hat, gibt er es in seinem Bücherregal frei. Oli findet das Buch, fragt das Exemplar bei Charly an und hinterlegt eine Kaution. Charly sieht und bestätigt die Anfrage. Sie treffen sich und Oli bestätigt die Übernahme des Buches. Charly bekommt seine Kaution abzüglich des Honorars, das an Peter geht, zurück. Das Buch ist nun im Bücherregal von Oli und gesperrt, weil er es noch liest. Und so geht es weiter und weiter, solange sich noch jemand für das Buch interessiert und es sich in einem brauchbaren Zustand befindet.
Als Frontend bietet Bookchain eine hybride mobile App (s. Abbildung 1), die auf allen gängigen mobilen Geräten läuft. Wir haben sie mit Ionic 3 gebaut, um Push Notifications über Buchanfragen, Bestätigungen und Freigaben anzeigen zu können. Die Stammdaten der Bücher samt Miniaturansicht des Covers speichern wir nicht, sondern rufen sie von der Google Books API anhand der ISBN ab. Wie in Abbildung 3 ersichtlich, nutzt die Ionic App die Javascript-Bibliothek web3.js, um sich mit einer Node zu verbinden und Smart Contracts aufzurufen. Die Nodes laufen auf Rechnern an verschiedenen Standorten und bilden ein privates Ethereum-Netz. Die Entscheidung, Bookchain in einem privaten Netz anstatt des Ethereum Mainnet zu betreiben, haben wir aufgrund der Gaskosten, mit denen Transaktionen im Mainnet verbunden sind, getroffen. Für das Hosting der Ionic App haben wir uns erstmal für zentrale Dienste wie Google Play Store entschieden. In einer vollständig dezentralen Umsetzung gemäß der Vision von Web 3.0 wäre auch das Frontend eines ĐApps dezentral gehosted. Dafür bieten sich dezentrale Speicherdienste wie IPFS oder Swarm an. Letzteres gehört neben der Ethereum Virtual Machine (EVM) und Whisper zu den drei Grundbausteinen von Ethereum.
Die Backendlogik besteht aus drei Smart Contracts, die on-chain gehosted und ausgeführt werden. Der UserContract kümmert sich um die Registrierung von Benutzern und um die Verwaltung ihrer Benutzernamen und Adressen. Zum Einloggen wird neben dem Benutzernamen auch das Passwort, mit dem der Private Key des Benutzers geschützt ist, benötigt. Damit wird der Account des Benutzers entsperrt, um Transaktionen von diesem Account ans Netzwerk schicken zu können. Der BookshelfContract ist für die Registrierung der Bücher und für die Verwaltung deren aktueller Besitzer zuständig. Der Smart Contract speichert dabei lediglich die ISBN eines Buches. Zu guter Letzt verwaltet der PaymentContract die Kautionen der Benutzer und überweist bei der Rückgabe dieser Kautionen einen Teil als Honorar an den Käufer des Buches.
Da der Speicherplatz und die Ausführung von Smart Contracts kostspielig sind, haben wir versucht, so wenig Informationen wie nur möglich in den Contracts zu speichern. Stattdessen schreiben die Contracts Informationen über Events ins Log. Frontends können das Log effizient durchsuchen, um darin die relevanten Informationen zu finden, z.B. wenn sie die Adresse des Benutzers enthalten. Beispielsweise wird die Information darüber, dass eine Buchanfrage bestätigt wurde, nur in Form eines Events im Log und nicht im Speicher des BookshelfContracts gespeichert.
contract Mortal {
address internal owner;
function Mortal () public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function kill() onlyOwner() public {
selfdestruct(owner);
}
}
Alle drei Smart Contracts implementieren Design Patterns, die das Problem der Wartbarkeit (Upgradeability) adressieren: Da der Code von Smart Contracts in der Blockchain gespeichert ist, kann er nicht ohne Weiteres modifiziert werden. Das sog. Mortal-Pattern (s. oben) sorgt dafür, dass der intern gespeicherte Besitzer eines Contracts die Möglichkeit hat, diesen zu terminieren. Dabei wird geprüft, ob der Aufrufer der Methode kill() mit dem gespeicherten Besitzer übereinstimmt. Falls ja, wird das Saldo des Contracts an den Besitzer übertragen und der Contract kann danach nicht mehr aufgerufen werden. Das Permissioned-Pattern ist neben dem Mortal-Pattern eine weitere Spezialisierung des Ownable-Patterns, das einem Smart Contract einen Besitzer zuordnet. Der Besitzer und nur der Besitzer kann darin beliebig viele Adressen speichern, denen es erlaubt ist, Methoden des Contracts aufzurufen. Vor der Ausführung dieser Methoden wird geprüft, ob der Aufrufer mit einer der vom Besitzer hinzugefügten Adressen übereinstimmt. Ein Hauptproblem mit der Weiterentwicklung von Contracts ist die Migration der Daten aus der alten Version in die neue Version des Contracts. Die Daten müssen nämlich durch eine externe Anwendung aus der alten Version herausgelesen und in die neue Version gespeichert werden. Das kostet sehr viel Gas. Das Problem ist leicht zu umgehen, wenn das Datenmodell des Contracts über die Zeit stabil bleibt und sich nur noch die Logik weiterentwickelt. Um die Logik des Contracts leichter zu erweitern und etwaige Fehler zu beheben, wurden die Steuerung und die Datenhaltung in getrennten Contracts implementiert. Die Datenhaltung enthält lediglich Methoden für den Zugriff auf die Daten des jeweiligen Contracts, deren Struktur sich über die Zeit nicht ändert. So reicht es bei Änderungen der Logik lediglich den Controller-Contract in einer neuen Version bereitzustellen. Wie erfahren die externen Anwendungen, die mit dem Contract interagieren wollen, von der neuen Version des Contracts? Eine Lösung ist das sog. Hub-Pattern (s. Abbildung 3). Es erlaubt dem Besitzer (bekannt aus dem Mortal-Pattern) den einzelnen Contracts im System sprechende Namen zuzuweisen. Wenn sich ein Contract ändert, wird die neue Version unter demselben Namen wie die alte Version gespeichert und überschreibt diese. Externe Anwendungen fragen immer zuerst beim Hub nach dem Contract mit einem bestimmten Namen und rufen dann diesen auf. So wird sichergestellt, dass sie immer die aktuelle Version eines Contracts aufrufen.
In den ersten drei Teilen der Blogserie haben wir uns mit dem P2P-Netzwerk und der Datenstruktur von Blockchains sowie mit Smart Contracts beschäftigt und ihre Anwendung am Beispiel einer ĐApp gezeigt. Im letzten Teil schließen wir die Blogreihe mit Gedanken über mögliche Use Cases und das Disruptionspotenzial der Blockchain ab.
Wie können Sie Chancen und mögliche Einsatzfelder von Blockchain-Lösungen identifizieren und diese in Ihrer Organisation umsetzen? Erfahren Sie, wie wir Sie beim Thema Blockchain unterstützen können: