Blockchain hausgemacht

INNOQ Hands-On Event

Bei INNOQ veranstalten wir jedes Jahr einen so genannten Hands-On-Event. Dieser ist Teil unserer regulären Mitarbeiter-Events und findet typischerweise im Frühjahr statt. Wir treffen uns alle für zwei Tage an einem Ort und versuchen mit der Programmiersprache unserer Wahl in Gruppen eine definierte Aufgabe zu lösen. Optimal also, um neue Sprachen und neue Kolleginnen und Kollegen in Gruppenarbeit kennenzulernen.

Die Aufgabenstellung lautete in diesem Jahr wie folgt: Baue eine Blockchain! Dazu gaben wir zum Einstieg einen kurzen Vortrag und versuchten zu erklären, was eine Blockchain, und insbesondere ein Block eigentlich ist. Wichtig war uns, das Thema auf das absolute Minimum zu reduzieren, um in der Kürze der Zeit ein Maximum an Verständnis für das Kernkonzept zu vermitteln. Dazu ließen wir typische Themen wie Kryptowährungen, die oft in vielen Intros mit einhergehen, bewusst aus. Wir gaben zwar einen Überblick über Einsatzszenarien und Produktmöglichkeiten, der Großteil unserer Intro beschränkte sich aber bewusst auf die Implementierung einer Blockchain und die Abgrenzung zu klassischen Datenbanken durch

  • Verkettung von Blöcken
  • Verteilung der Chain
  • Das Fehlen einer vertrauenswürdigen Instanz

Die Aufgabe für die kommenden anderthalb Tage unterteilte sich wie folgt:

Kernaufgabe: Mining von Blöcken und Verkettung

Die Hauptaufgabe war es, ein Programm zu schreiben, das ein einfaches HTTP API bereitstellt, um

  • Das Mining eines neuen Blocks anzustoßen,
  • Infos über den Node zu publizieren,
  • die gesamte Chain auszugeben

Das „Minen“ eines neuen Blocks erfolgte mit einem Proof-of-Work-Algorithmus. Jeder Client sollte einen JSON-String konstruieren, dessen SHA256-Hash mit sechs führenden Nullen beginnt. Der syntaktische Aufbau dieses Strings war wie folgt:

{
  "index": 2,
  "timestamp": 1524816285740,
  "proof": 17213004,
  "transactions": [],
  "previousBlockHash": "000000b642b67d8bea7cffed1ec990719a3f7837de5ef0f8ede36537e91cdc0e"
}

Der abgebildete Block-Kandidat erfüllt die Eigenschaft, dass dessen SHA256-Hash mit sechs führenden beginnt. Die Aufgabe jedes Clients war es nun den Wert des Attributs proof abzuändern, die JSON-Serialisierung zu bilden, erneut zu hashen und zu prüfen, ob das Kriterium erfüllt war. Für das obige Beispiel trifft das für "proof": 17213004 zu.

In einem Netzwerk kann jeder Client diese Datenstruktur syntaktisch validieren und dessen formale Korrektheit mit einem einmaligen Hashvorgang überprüfen:

$ echo -n '{"index":2,"timestamp":1524816285740,"proof":17213004,"transactions":[],"previousBlockHash":"000000b642b67d8bea7cffed1ec990719a3f7837de5ef0f8ede36537e91cdc0e"}' | shasum -a 256
000000a695226f2057f1165c91147f7ac7a725c9eeecae7275a9f327d7440f29  -

Besonderer Erwähnung bedarf hier das Attribut previousBlockHash: es zeigt auf den SHA256-Hash seines Vorgängers (in diesem Fall auf den Genesis-Block) und bildet somit die durch Hashing abgesicherte Kette von Blöcken - unsere Blockchain.

Bonusaufgabe 1: Transaktionen

Als erste Bonusaufgabe sollten Transaktionen in neuen Blöcken persistiert werden. Hierbei ging es nicht um Währungstransaktionen, sondern um simple Objekte, die einen frei wählbaren Inhalt hatten.

Den Eigentumsübergang und die damit verbundene Public-Key-Kryptografie haben wir hier bewusst ausgeklammert. Unsere Daten wurden so durch jeden neu erstellten Block weiter abgesichert.

Bonusaufgabe 2: Chain-Sync

Hierbei sollte die bestehende Chain auf mehrere Nodes repliziert werden. Dazu soll sich ein neuer Node bei einem anderen über eine HTTP-Resource registrieren können um sich über dessen Aktualisierungen benachrichtigen zu lassen.

Als Konsens galt hier: die längste, valide Chain des bestehenden Netzwerks wird übernommen.

Programmiersprachen

Die Gruppenaufteilung stand bereits vor dem Event fest (auf diese Weise lässt sich bei so einem Vorhaben sehr viel Zeit sparen), so dass die Teilnehmer sich nur noch in Tischgruppen zusammenfinden mussten. Dieses Jahr standen folgende Programmiersprachen auf dem Plan – wie immer eine illustre Mischung aus bewährtem, exotischem und brandneuem:

  • 8th
  • Bash
  • C
  • C#
  • Erlang
  • Go
  • Java
  • JavaScript
  • Kotlin
  • Python
  • Ruby
  • Rust

Ziemlich unerwartet war dann auch die Bash-Gruppe die erste, die die Basisaufgabe fertig gestellt hatte. Mangels nativer Sprachmittel entschied man sich für ein externes Programm als HTTP-Server, das statische Dateien auslieferte. Die interne Persistenz der Chain geschah also nicht in Memory, sondern im Filesystem.

Michael Neuweiler baute Blöcke unter freiem Himmel
Michael Neuweiler baute Blöcke unter freiem Himmel

Eine der zwei Erlang-Gruppen entwickelte ihre Lösung als Verbund von Master- und beliebig vielen Slave-Prozessen. Die Slave-Prozesse wickelten das Mining von neuen Blöcken mittels einer hocheffizienten NIF (Native Implemented Function) in C ab. Auf diesem Weg konnten extrem performant neue Blöcke gemined werden, mehrere zehntausend mal so schnell wie beispielsweise in der node.js-Gruppe.

Die besondere Herausforderung für uns war das JSON-Handling: Erlang selbst bietet keine nativen Strings, sondern Listen von Zeichen oder Binär-Blobs.

Christoph Iserlohn

Die Ruby-Gruppe entwickelte sogar ein eigenes UI, in dem die Blöcke der Chain mit jeweils einzigartigen Rubinen repräsentiert wurden – ganz im Geiste der pragmatischen Produktentwicklung. Obwohl keine Persistenz der Chain gefordert war (über in-memory hinaus), wurde hier in einer relationalen Datenbank (Postgres) persistiert – dank Rails und ActiveRecord war das schnell gemacht.

Auch exotische Sprachen wie 8th (ein 4th-Derivat) fanden auf dem Event ihre Verwendung. Jörg Plewe dazu:

Forth ist unglaublich einfach, so einfach, dass nicht-Forther sich das gar nicht vorstellen können (der Compiler z.B. besteht aus nur 2 Zeilen Code). Kann trotzdem alles. Ist interaktiv, Stack-basiert, leicht zu faktorieren.

Trotz der absoluten Einfachheit von 4th gab es natürlich besondere Herausforderungen:

Das Schwierigste bei der Blockchain war das Key-sortierte JSON-Rendering. Da 8th nicht über wuchtige Bibliotheken verfügt, der Webserver nur ein Paar Zeilen Beispielcode oberhalb von Sockets war, war HTTP etwas hakelig.

Die Go-Gruppe
Die Go-Gruppe

Zur Sprache Kotlin fanden sich so viele Interessenten, dass wir mehrere Gruppen bilden mussten. Eine der Gruppen verwendete ebenfalls das neue Spring Web-Programmiermodell WebFlux.

Eine der Kotlin-Gruppen
Eine der Kotlin-Gruppen

So gut wie alle Gruppen haben die Kernaufgabe der Konstruktion einer Blockchain lösen können, mehr oder weniger optimiert. Der Hackertrieb und die extrem performanten Ergebnisse der C/Erlang-Gruppe verleiteten natürlich viele dazu, ihren Mining-Algorithmus weiter zu optimieren, bevor sie sich den Bonus-Aufgaben zuwendeten.

Zusammenfassend kann man sagen, dass sich auch eine komplexe Aufgabe wie der Bau einer Blockchain auf einer Hackathon-artigen Veranstaltung lösen lässt, wenn man die Aufgabenstellung auf ein absolutes Minimum herunterbricht. In unserem Fall haben wir bewusst Komplexitätstreiber wie Public-Key-Kryptografie ausgeklammert, damit die Aufgabe lösbar bleibt. Gerade wenn man dann unterwegs beim Lösen der Aufgabe feststellt, dass solche Dinge für eine „echte“ Blockchain eben noch fehlen, ist der Lerneffekt für die Teilnehmer umso größer.

Da nicht alle unserer Mitarbeiterinnen und Mitarbeiter einen Programmier-Hintergrund haben, wollen wir den bisherigen „Programmierevent“ (nun: „Hands-On-Event“) in Zukunft auf einen breiteren inhaltlichen Sockel stellen, damit sich wirklich jeder voll einbringen kann.

Alle Repositories der Gruppen sind Open Source und stehen auf GitHub bereit. Da diese Ergebnisse im Rahmen eines anderthalbtägigen Hackathons entstanden, sind sie mit Sicherheit noch an vielen Stellen verbesserungswürdig – dennoch wollen wir die Ergebnisse unseren Lesern nicht vorenthalten. Wer wollte schließlich nicht immer schon mal wissen, wie man eine Blockchain in Bash baut?

Repositories

TAGS

Comments

Please accept our cookie agreement to see full comments functionality. Read more