Implementierung einer einfachen Blockchain in Java

1. Übersicht

In diesem Tutorial lernen wir die grundlegenden Konzepte der Blockchain-Technologie kennen. Wir werden auch eine Basisanwendung in Java implementieren, die sich auf die Konzepte konzentriert.

Weiter werden wir einige fortgeschrittene Konzepte und praktische Anwendungen dieser Technologie diskutieren.

2. Was ist Blockchain?

Lassen Sie uns zunächst verstehen, was genau Blockchain ist.

Nun, es geht auf das Whitepaper zurück, das Satoshi Nakamoto 2008 auf Bitcoin veröffentlicht hat.

Blockchain ist ein dezentrales Informationsbuch . Es besteht aus Datenblöcken, die mithilfe von Kryptografie verbunden sind. Es gehört zu einem Netzwerk von Knoten, die über das öffentliche Netzwerk verbunden sind. Wir werden dies besser verstehen, wenn wir später versuchen, ein grundlegendes Tutorial zu erstellen.

Es gibt einige wichtige Attribute, die wir verstehen müssen. Gehen wir sie also durch:

  • Manipulationssicher : In erster Linie sind Daten als Teil eines Blocks manipulationssicher . Jeder Block wird durch einen kryptografischen Digest referenziert, der allgemein als Hash bezeichnet wird, wodurch der Block manipulationssicher wird.
  • Dezentral: Die gesamte Blockchain ist im gesamten Netzwerk vollständig dezentralisiert . Dies bedeutet, dass es keinen Masterknoten gibt und jeder Knoten im Netzwerk dieselbe Kopie hat.
  • Transparent: Jeder am Netzwerk teilnehmende Knoten validiert und fügt seiner Kette durch Konsens mit anderen Knoten einen neuen Block hinzu . Somit hat jeder Knoten vollständige Sichtbarkeit der Daten.

3. Wie funktioniert Blockchain?

Lassen Sie uns nun verstehen, wie Blockchain funktioniert.

Die Grundeinheiten einer Blockchain sind Blöcke . Ein einzelner Block kann mehrere Transaktionen oder andere wertvolle Daten kapseln:

3.1. Einen Block abbauen

Wir repräsentieren einen Block durch einen Hashwert. Das Generieren des Hashwerts eines Blocks wird als "Mining" des Blocks bezeichnet. Das Mining eines Blocks ist in der Regel rechenintensiv, da es als „Arbeitsnachweis“ dient.

Der Hash eines Blocks besteht normalerweise aus den folgenden Daten:

  • In erster Linie besteht der Hash eines Blocks aus den Transaktionen, die er kapselt
  • Der Hash besteht auch aus dem Zeitstempel der Blockerstellung
  • Es enthält auch eine Nonce, eine beliebige Zahl, die in der Kryptographie verwendet wird
  • Schließlich enthält der Hash des aktuellen Blocks auch den Hash des vorherigen Blocks

Mehrere Knoten im Netzwerk können gleichzeitig um den Abbau des Blocks konkurrieren . Neben der Generierung des Hashs müssen die Knoten auch überprüfen, ob die im Block hinzugefügten Transaktionen legitim sind. Der erste, der einen Block abbaut, gewinnt das Rennen!

3.2. Hinzufügen eines Blocks zur Blockchain

Während das Mining eines Blocks rechenintensiv ist, ist es relativ viel einfacher zu überprüfen, ob ein Block legitim ist . Alle Knoten im Netzwerk nehmen an der Überprüfung eines neu abgebauten Blocks teil.

Auf diese Weise wird ein neu abgebauter Block im Konsens der Knoten in die Blockchain eingefügt .

Jetzt stehen mehrere Konsensprotokolle zur Verfügung, die wir zur Überprüfung verwenden können. Die Knoten im Netzwerk verwenden dasselbe Protokoll, um böswillige Zweige der Kette zu erkennen. Daher wird ein böswilliger Zweig, selbst wenn er eingeführt wird, bald von der Mehrheit der Knoten abgelehnt.

4. Grundlegende Blockchain in Java

Jetzt haben wir genug Kontext, um eine Basisanwendung in Java zu erstellen.

Unser einfaches Beispiel hier zeigt die grundlegenden Konzepte, die wir gerade gesehen haben. Eine Anwendung für die Produktion ist mit vielen Überlegungen verbunden, die den Rahmen dieses Lernprogramms sprengen. Wir werden jedoch später auf einige fortgeschrittene Themen eingehen.

4.1. Block implementieren

Zunächst müssen wir ein einfaches POJO definieren, das die Daten für unseren Block enthält:

public class Block { private String hash; private String previousHash; private String data; private long timeStamp; private int nonce; public Block(String data, String previousHash, long timeStamp) { this.data = data; this.previousHash = previousHash; this.timeStamp = timeStamp; this.hash = calculateBlockHash(); } // standard getters and setters }

Lassen Sie uns verstehen, was wir hier gepackt haben:

  • Hash des vorherigen Blocks, ein wichtiger Teil zum Aufbau der Kette
  • Die tatsächlichen Daten, alle Informationen mit Wert, wie ein Vertrag
  • Der Zeitstempel der Erstellung dieses Blocks
  • Eine Nonce, eine beliebige Zahl, die in der Kryptographie verwendet wird
  • Schließlich wird der Hash dieses Blocks basierend auf anderen Daten berechnet

4.2. Berechnung des Hash

Wie berechnen wir nun den Hash eines Blocks? Wir haben eine Methode berechneBlockHash verwendet, aber noch keine Implementierung gesehen. Bevor wir diese Methode implementieren, lohnt es sich, etwas Zeit zu investieren, um zu verstehen, was genau ein Hash ist.

Ein Hash ist eine Ausgabe von etwas, das als Hash-Funktion bekannt ist. Eine Hash-Funktion ordnet Eingabedaten beliebiger Größe Ausgabedaten fester Größe zu . Der Hash reagiert sehr empfindlich auf Änderungen der Eingabedaten, wie klein diese auch sein mögen.

Darüber hinaus ist es unmöglich, die Eingabedaten nur aus ihrem Hash zurückzugewinnen. Diese Eigenschaften machen die Hash-Funktion in der Kryptographie sehr nützlich.

Lassen Sie uns sehen, wie wir den Hash unseres Blocks in Java generieren können:

public String calculateBlockHash() { String dataToHash = previousHash + Long.toString(timeStamp) + Integer.toString(nonce) + data; MessageDigest digest = null; byte[] bytes = null; try { digest = MessageDigest.getInstance("SHA-256"); bytes = digest.digest(dataToHash.getBytes(UTF_8)); } catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) { logger.log(Level.SEVERE, ex.getMessage()); } StringBuffer buffer = new StringBuffer(); for (byte b : bytes) { buffer.append(String.format("%02x", b)); } return buffer.toString(); }

Hier passieren ziemlich viele Dinge, lassen Sie uns sie im Detail verstehen:

  • Zuerst verketten wir verschiedene Teile des Blocks, um einen Hash daraus zu generieren
  • Dann erhalten wir eine Instanz der SHA-256-Hash-Funktion von MessageDigest
  • Dann generieren wir den Hash-Wert unserer Eingabedaten, bei dem es sich um ein Byte-Array handelt
  • Schließlich transformieren wir das Byte-Array in eine Hex-Zeichenfolge. Ein Hash wird normalerweise als 32-stellige Hex-Zahl dargestellt

4.3. Haben wir den Block schon abgebaut?

Bisher klingt alles einfach und elegant, bis auf die Tatsache, dass wir den Block noch nicht abgebaut haben. Was genau bedeutet es also, einen Block abzubauen, was die Entwickler schon seit einiger Zeit begeistert?

Das Mining eines Blocks bedeutet das Lösen einer rechenintensiven Aufgabe für den Block. Während die Berechnung des Hash eines Blocks etwas trivial ist, ist es nicht so, den Hash zu finden, der mit fünf Nullen beginnt. Noch komplizierter wäre es, einen Hash zu finden, der mit zehn Nullen beginnt, und wir bekommen eine allgemeine Vorstellung.

Wie genau können wir das tun? Ehrlich gesagt ist die Lösung viel weniger ausgefallen! Mit brutaler Gewalt versuchen wir, dieses Ziel zu erreichen. Wir nutzen hier nonce:

public String mineBlock(int prefix) { String prefixString = new String(new char[prefix]).replace('\0', '0'); while (!hash.substring(0, prefix).equals(prefixString)) { nonce++; hash = calculateBlockHash(); } return hash; }

Mal sehen, was wir hier versuchen, sind:

  • Wir definieren zunächst das Präfix, das wir finden möchten
  • Dann prüfen wir, ob wir die Lösung gefunden haben
  • Wenn nicht, erhöhen wir die Nonce und berechnen den Hash in einer Schleife
  • Die Schleife geht weiter, bis wir den Jackpot knacken

Wir beginnen hier mit dem Standardwert von nonce und erhöhen ihn um eins. Es gibt jedoch ausgefeiltere Strategien, um eine Nonce in realen Anwendungen zu starten und zu erhöhen . Außerdem überprüfen wir unsere Daten hier nicht, was normalerweise ein wichtiger Teil ist.

4.4. Lassen Sie uns das Beispiel ausführen

Nachdem wir unseren Block zusammen mit seinen Funktionen definiert haben, können wir damit eine einfache Blockchain erstellen. Wir werden dies in einer ArrayList speichern :

List blockchain = new ArrayList(); int prefix = 4; String prefixString = new String(new char[prefix]).replace('\0', '0');

Zusätzlich haben wir ein Präfix von vier definiert, was effektiv bedeutet, dass unser Hash mit vier Nullen beginnen soll.

Mal sehen, wie wir hier einen Block hinzufügen können:

@Test public void givenBlockchain_whenNewBlockAdded_thenSuccess() { Block newBlock = new Block( "The is a New Block.", blockchain.get(blockchain.size() - 1).getHash(), new Date().getTime()); newBlock.mineBlock(prefix); assertTrue(newBlock.getHash().substring(0, prefix).equals(prefixString)); blockchain.add(newBlock); }

4.5. Blockchain-Überprüfung

Wie kann ein Knoten überprüfen, ob eine Blockchain gültig ist? Während dies ziemlich kompliziert sein kann, lassen Sie uns über eine einfache Version nachdenken:

@Test public void givenBlockchain_whenValidated_thenSuccess() { boolean flag = true; for (int i = 0; i < blockchain.size(); i++) { String previousHash = i==0 ? "0" : blockchain.get(i - 1).getHash(); flag = blockchain.get(i).getHash().equals(blockchain.get(i).calculateBlockHash()) && previousHash.equals(blockchain.get(i).getPreviousHash()) && blockchain.get(i).getHash().substring(0, prefix).equals(prefixString); if (!flag) break; } assertTrue(flag); }

Hier führen wir drei spezifische Überprüfungen für jeden Block durch:

  • Der gespeicherte Hash des aktuellen Blocks ist tatsächlich das, was er berechnet
  • Der im aktuellen Block gespeicherte Hash des vorherigen Blocks ist der Hash des vorherigen Blocks
  • Der aktuelle Block wurde abgebaut

5. Einige erweiterte Konzepte

Während unser grundlegendes Beispiel die grundlegenden Konzepte einer Blockchain hervorhebt, ist es sicherlich nicht vollständig. Um diese Technologie in die Praxis umzusetzen, müssen einige andere Überlegungen berücksichtigt werden.

Obwohl es nicht möglich ist, alle zu detaillieren, gehen wir einige der wichtigsten durch:

5.1. Transaktionsüberprüfung

Calculating the hash of a block and finding the desired hash is just one part of mining. A block consists of data, often in the form of multiple transactions. These must be verified before they can be made part of a block and mined.

A typical implementation of blockchain sets a restriction on how much data can be part of a block. It also sets up rules on how a transaction can be verified. Multiple nodes in the network participate in the verification process.

5.2. Alternate Consensus Protocol

We saw that consensus algorithm like “Proof of Work” is used to mine and validate a block. However, this is not the only consensus algorithm available for use.

There are several other consensus algorithms to choose from, like Proof of Stake, Proof of Authority, and Proof of Weight. All of these have their pros and cons. Which one to use depends upon the type of application we intend to design.

5.3. Mining Reward

A blockchain network typically consists of voluntary nodes. Now, why would anyone want to contribute to this complex process and keep it legit and growing?

This is because nodes are rewarded for verifying the transactions and mining a block. These rewards are typically in the form of coin associated with the application. But an application can decide the reward to be anything of value.

5.4. Node Types

A blockchain completely relies on its network to operate. In theory, the network is completely decentralized, and every node is equal. However, in practice, a network consists of multiple types of nodes.

While a full node has a complete list of transactions, a light node only has a partial list. Moreover, not all nodes participate in verification and validation.

5.5. Secure Communication

One of the hallmarks of blockchain technology is its openness and anonymity. But how does it provide security to transactions being carried within? This is based on cryptography and public key infrastructure.

The initiator of a transaction uses their private key to secure it and attach it to the public key of the recipient. Nodes can use the public keys of the participants to verify transactions.

6. Practical Applications of Blockchain

So, blockchain seems to be an exciting technology, but it also must prove useful. This technology has been around for some time now and – needless to say – it has proved to be disruptive in many domains.

Its application in many other areas is being actively pursued. Let's understand the most popular applications:

  • Currency: This is by far the oldest and most widely known use of blockchain, thanks to the success of Bitcoin. They provide secure and frictionless money to people across the globe without any central authority or government intervention.
  • Identity: Digital identity is fast becoming the norm in the present world. However, this is mired by security issues and tampering. Blockchain is inevitable in revolutionizing this area with completely secure and tamper-proof identities.
  • Healthcare: Healthcare industry is loaded with data, mostly handled by central authorities. This decreases transparency, security, and efficiency in handling such data. Blockchain technology can provide a system without any third party to provide much-needed trust.
  • Government: This is perhaps an area which is well open to disruption by the blockchain technology. Government is typically at the center of several citizen services which are often laden with inefficiencies and corruption. Blockchain can help establish much better government-citizen relations.

7. Tools of the Trade

While our basic implementation here is useful to elicit the concepts, it's not practical to develop a product on blockchain from scratch. Thankfully, this space has matured now, and we do have some quite useful tools to start from.

Let's go through some of the popular tools to work within this space:

  • Solidity: Solidity is a statically-typed and object-oriented programming language designed for writing smart contracts. It can be used to write smart contracts on various blockchain platforms like Ethereum.
  • Remix IDE: Remix is a powerful open-source tool to write smart contracts in Solidity. This enables the user to write smart contracts right from the browser.
  • Truffle Suite: Truffle provides a bunch of tools to get a developer up and started in developing distributed apps. This includes Truffle, Ganache, and Drizzle.
  • Ethlint/Solium: Solium allows developers to ensure that their smart contracts written on Solidity is free from style and security issues. Solium also helps in fixing these issues.
  • Parität: Parität hilft beim Einrichten der Entwicklungsumgebung für Smart Contract auf Etherium. Es bietet eine schnelle und sichere Möglichkeit, mit der Blockchain zu interagieren.

8. Fazit

Zusammenfassend haben wir in diesem Tutorial die Grundkonzepte der Blockchain-Technologie durchgearbeitet. Wir haben verstanden, wie ein Netzwerk abgebaut und einen neuen Block in die Blockchain eingefügt. Weiterhin haben wir die Grundkonzepte in Java implementiert. Wir haben auch einige der fortgeschrittenen Konzepte im Zusammenhang mit dieser Technologie diskutiert.

Schließlich haben wir einige praktische Anwendungen der Blockchain sowie verfügbare Tools abgeschlossen.

Wie immer ist der Code auf GitHub zu finden.