Die Blockchain in 9 Schritten – Teil 4: Hash-Schwierigkeitsstufe erhöhen
Da die Errechnung eines SHA256-Hashwertes innerhalb von Millisekunden erledigt ist, hat der Erfinder des Blockchain-Konzeptes einen veränderlichen Schwierigkeitsgrad eingebaut, der eine nachträgliche Änderung innerhalb der Blockchain über mehrere Datenblöcke hinweg derart verlangsamt, dass die notwendigen Berechnungen immer der Original-Blockchain hinterherlaufen.
In welcher Form wird nun die Schwierigkeit berechnet bzw. erhöht? Die Antwort ist recht einfach – in dem solange ein Hashwert gesucht wird, bei dem die ersten Stellen mit einer Null beginnen. So kann ein gültiger SHA256-Hashwert mit Schwierigkeitsgrad 4 (bedeutet 4 Nullen am Anfang) so aussehen: „0000ed35a36da547ca146f1be973bbe700c5a21bccd5fee27502e43f8736408a“.
Ich höre schon die Rufe – „ein Hashwert ist eindeutig für einen Datensatz“ und das stimmt auch, nur ist ab sofort der Block-Datensatz um ein Feld reicher: „nonce“. Ebenso ist in der Block-Klasse nun eine zusätzliche Methode namens „mineBlock“, welche für die Generierung eines Hashwertes mit passender Schwierigkeit („difficulty“) sorgt. Das Programm zählt den Wert im feld „nonce“ laufend hoch und errechnet den Hashwert unter Einbezug des „nonce“-Feldes bis die Schwierigkeit erreicht ist.
In der Hauptklasse wird die Schwierigkeit fest mit dem Wert 4 belegt und Ihr solltet diesen Wert sehr langsam auf 5, 6 oder 7 erhöhen. Mit jeder Erhöhung verlangsamt sich die Hashwertberechnung für die Datenblöcke deutlich bis hin zur Unbenutzbarkeit. Ich habe Euch eine Version von Stufe 4 erstellt, in der mehr Datensätze erstellt werden, damit ist der Verlangsamungseffekt besser zu bemerken. Schaut Euch den Unterartikel I04B Hash-Schwierigkeitsstufe erhöhen an.
In der Praxis wird bei „echtem“ Krypto-Geld die Schwierigkeit automatisch an die verfügbare Rechengeschwindigkeit angepasst, so dass nur etwa alle 10 Minuten ein neuer Datenblock für die Bitcoin-Währung gefunden wird. Werden die Rechner schneller, erhöht sich auch der Schwierigkeitsgrad und die Berechnung dauert wieder 10 Minuten.
Fangen wir mit Quellcode der Klasse „Block“ an, gefolgt von den Klassen „StringUtil“ und „BlockChain“:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package net.bplaced.javacrypto.blockchain.step4; /* * Diese Klasse gehört zu BlockChain.java * This class belongs to BlockChain.java */ import java.util.Date; public class Block { public String hash; public String previousHash; private long timeStamp; // as number of milliseconds since 1/1/1970. private String data; private int nonce; public Block(String previousHash, String data) { this.previousHash = previousHash; this.data = data; this.timeStamp = new Date().getTime(); this.hash = calculateHash(); } public String calculateHash() { String calculatedhash = StringUtil .generateSha256(previousHash + Long.toString(timeStamp) + Integer.toString(nonce) + data); return calculatedhash; } public void mineBlock(int difficulty) { String target = StringUtil.getDifficultyString(difficulty); // Create a string with difficulty * "0" while (!hash.substring(0, difficulty).equals(target)) { nonce++; hash = calculateHash(); } System.out.println("Block Mined, Hash: " + hash); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
package net.bplaced.javacrypto.blockchain.step4; /* * Diese Klasse gehört zu BlockChain.java * This class belongs to BlockChain.java */ import java.security.MessageDigest; import com.google.gson.GsonBuilder; public class StringUtil { public static String generateSha256(String input) { try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] hash = digest.digest(input.getBytes("UTF-8")); StringBuffer hexString = new StringBuffer(); for (int i = 0; i < hash.length; i++) { String hex = Integer.toHexString(0xff & hash[i]); if (hex.length() == 1) hexString.append('0'); hexString.append(hex); } return hexString.toString(); } catch (Exception e) { throw new RuntimeException(e); } } public static String getJson(Object o) { return new GsonBuilder().setPrettyPrinting().create().toJson(o); } public static String getDifficultyString(int difficulty) { return new String(new char[difficulty]).replace('\0', '0'); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
package net.bplaced.javacrypto.blockchain.step4; /* * Herkunft/Origin: http://javacrypto.bplaced.net/ * Programmierer/Programmer: Michael Fehr * Copyright/Copyright: frei verwendbares Programm (Public Domain) * Copyright: This is free and unencumbered software released into the public domain. * Lizenztext/Licence: <http://unlicense.org> * getestet mit/tested with: Java Runtime Environment 8 Update 191 x64 * getestet mit/tested with: Java Runtime Environment 11.0.1 x64 * Datum/Date (dd.mm.jjjj): 28.05.2019 * Projekt/Project: Blockchain * Funktion: Schritt 4: Mining eines Blockes * Function: Step 4: mining of a block * * Sicherheitshinweis/Security notice * Die Programmroutinen dienen nur der Darstellung und haben keinen Anspruch auf eine korrekte Funktion, * insbesondere mit Blick auf die Sicherheit ! * Prüfen Sie die Sicherheit bevor das Programm in der echten Welt eingesetzt wird. * The program routines just show the function but please be aware of the security part - * check yourself before using in the real world ! * * Das Programm benötigt die nachfolgende Bibliothek: * The programm uses this external library: * jar-Datei: https://mvnrepository.com/artifact/com.google.code.gson/gson * * Das Projekt basiert auf dem nachfolgenden Artikel: * The project is based on this article: * https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa */ import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; public class BlockChain { public static ArrayList<Block> blockchain = new ArrayList<Block>(); public static int difficulty = 4; // vorsichtig auf 5 oder 6 erhöhen public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException { System.out.println("I04 BlockChain für Anfänger Stufe 04"); int blockNumber; System.out.println("\nAnzahl Einträge in der blockchain:" + blockchain.size()); // datensatz 1 blockNumber = 1; System.out.println("\nErgänze Block " + blockNumber); addBlock(new Block("0", "Data " + blockNumber)); // genesis block // daten der blockchain System.out.println("Anzahl Einträge in der blockchain:" + blockchain.size()); System.out.println("Inhalt der BlockChain:\n" + StringUtil.getJson(blockchain)); System.out.println("Ist die blockchain gültig:" + blockchainIsValid()); // datensatz 2 blockNumber = 2; System.out.println("\nErgänze Block " + blockNumber); addBlock(new Block(blockchain.get(blockchain.size() - 1).hash, "Data " + blockNumber)); // daten der blockchain System.out.println("Anzahl Einträge in der blockchain:" + blockchain.size()); System.out.println("Inhalt der BlockChain:\n" + StringUtil.getJson(blockchain)); System.out.println("Ist die blockchain gültig:" + blockchainIsValid()); } public static void addBlock(Block newBlock) { newBlock.mineBlock(difficulty); blockchain.add(newBlock); } public static Boolean blockchainIsValid() { Block currentBlock; Block previousBlock; for (int i = 1; i < blockchain.size(); i++) { currentBlock = blockchain.get(i); previousBlock = blockchain.get(i - 1); if (!currentBlock.hash.equals(currentBlock.calculateHash())) { return false; } if (!previousBlock.hash.equals(currentBlock.previousHash)) { return false; } } return true; } } |
Die Konsole gibt dieses Ergebnis aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
I04 BlockChain für Anfänger Stufe 04 Anzahl Einträge in der blockchain:0 Ergänze Block 1 Block Mined, Hash: 0000ed35a36da547ca146f1be973bbe700c5a21bccd5fee27502e43f8736408a Anzahl Einträge in der blockchain:1 Inhalt der BlockChain: [ { "hash": "0000ed35a36da547ca146f1be973bbe700c5a21bccd5fee27502e43f8736408a", "previousHash": "0", "timeStamp": 1559057037783, "data": "Data 1", "nonce": 95385 } ] Ist die blockchain gültig:true Ergänze Block 2 Block Mined, Hash: 0000675299eb730c37c524025645d8923d0c214f0fd1ff5a73254f71b6b616df Anzahl Einträge in der blockchain:2 Inhalt der BlockChain: [ { "hash": "0000ed35a36da547ca146f1be973bbe700c5a21bccd5fee27502e43f8736408a", "previousHash": "0", "timeStamp": 1559057037783, "data": "Data 1", "nonce": 95385 }, { "hash": "0000675299eb730c37c524025645d8923d0c214f0fd1ff5a73254f71b6b616df", "previousHash": "0000ed35a36da547ca146f1be973bbe700c5a21bccd5fee27502e43f8736408a", "timeStamp": 1559057038158, "data": "Data 2", "nonce": 217906 } ] Ist die blockchain gültig:true |
Weiter geht es mit Teil 5: I05 Erstellung eines Wallets.
Alle Quellcodes zur Blockchain findet Ihr zum Download in meinem Github-Repository, welches Ihr über diesen Link erreicht: https://github.com/java-crypto/I-Blockchain. Alle Programme sind sowohl unter Java 8 als auch unter Java 11 lauffähig.
Die Lizenz zum obigen Beispiel findet Ihr auf der eigenen Lizenz-Seite.
Letzte Aktualisierung: 28.05.2019