{"id":16696,"date":"2021-04-14T02:05:44","date_gmt":"2021-04-14T00:05:44","guid":{"rendered":"http:\/\/blog.wenzlaff.de\/?p=16696"},"modified":"2021-04-14T16:53:56","modified_gmt":"2021-04-14T14:53:56","slug":"blockchain","status":"publish","type":"post","link":"http:\/\/blog.wenzlaff.de\/?p=16696","title":{"rendered":"Blockchain in Java &#8211; Bitcoin heute Neues Allzeithoch &#8211; Nasdaq: B\u00f6rsengang von Coinbase"},"content":{"rendered":"<p>Wollte heute mal noch vor dem B\u00f6rsengang von Coinbase ein Blockchain in Java coden. Mit nur zwei Klassen sind die Grundlagen implementiert. D.h. ein Block verweist jeweils auf den n\u00e4chsten Block. Jeder Block hat einen Hash \u00fcber die Daten und kann so von jedem validiert werden. Ein Block kann alles enthalten, hier mal ein String Objekt, es muss ja nicht immer Bitcoin sein. Hier die Architektur:<\/p>\n<p><a href=\"http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2021\/04\/architektur.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2021\/04\/architektur.png\" alt=\"\" width=\"821\" height=\"604\" class=\"aligncenter size-full wp-image-16697\" srcset=\"http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2021\/04\/architektur.png 821w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2021\/04\/architektur-300x221.png 300w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2021\/04\/architektur-768x565.png 768w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/a><\/p>\n<p>Ein JUnit 5 Testklasse erzeugt eine g\u00fcltige Blockchain mit 5 Bl\u00f6cken und wird anschlie\u00dfend validiert. Bei Bitcoin werden alle 10 Minuten neue Bl\u00f6cke erzeugt. Die haben dann jeweils (urspr\u00fcnglich) eine Gr\u00f6\u00dfe von ca. max 1 MB an Daten.<\/p>\n<p>Dann im zweiten Testfall wird ein Block ver\u00e4ndert und in die Blockhain eingef\u00fcgt. Das Ergebnis der validierung muss dann einen Error ausgeben.<\/p>\n<p>Ein Block sieht so aus: <!--more--><\/p>\n<pre class=\"lang:java decode:true \" >package de.wenzlaff.blockchain.be;\r\n\r\nimport java.util.Arrays;\r\n\r\nimport org.apache.logging.log4j.LogManager;\r\nimport org.apache.logging.log4j.Logger;\r\n\r\n\/**\r\n * Der Block einer Blockchain.\r\n * \r\n * Ein einfaches POJO. Es k\u00f6nnen alle Daten enthalten sein. Hier mal als String.\r\n * \r\n * @author Thomas Wenzlaff\r\n *\/\r\npublic class Block {\r\n\r\n\tprivate static final Logger LOG = LogManager.getLogger(Block.class);\r\n\r\n\t\/**\r\n\t * Der Hash vom vorherigen Block.\r\n\t *\/\r\n\tprivate int previousHash;\r\n\t\/**\r\n\t * Die Daten. Es k\u00f6nnte alles sein.\r\n\t *\/\r\n\tprivate String data;\r\n\r\n\t\/**\r\n\t * Der Hash dieses Blockes.\r\n\t *\/\r\n\tprivate int hash;\r\n\r\n\tpublic Block(String data, int previousHash) {\r\n\t\tthis.data = data;\r\n\t\tthis.previousHash = previousHash;\r\n\r\n\t\t\/\/ eine Verbindung der gehashten Daten (mit Arrays.hashCode) mit den gehashten\r\n\t\t\/\/ Daten aus dem\r\n\t\t\/\/ vorhergehenden Block also das macht die Blockchain aus\r\n\t\tthis.hash = Arrays.hashCode(new Integer[] { data.hashCode(), previousHash });\r\n\t\tLOG.info(\"Neuen Block erzeugt mit Hash: \" + this.hash);\r\n\t}\r\n\r\n\tpublic int getPreviousHash() {\r\n\t\treturn previousHash;\r\n\t}\r\n\r\n\tpublic void setPreviousHash(int previousHash) {\r\n\t\tthis.previousHash = previousHash;\r\n\t}\r\n\r\n\tpublic String getData() {\r\n\t\treturn data;\r\n\t}\r\n\r\n\tpublic void setData(String data) {\r\n\t\tthis.data = data;\r\n\t}\r\n\r\n\tpublic int getHash() {\r\n\t\treturn hash;\r\n\t}\r\n\r\n\tpublic void setHash(int hash) {\r\n\t\tthis.hash = hash;\r\n\t}\r\n\r\n\t@Override\r\n\tpublic String toString() {\r\n\t\tStringBuilder builder = new StringBuilder();\r\n\t\tbuilder.append(\"Block [previousHash=\");\r\n\t\tbuilder.append(previousHash);\r\n\t\tbuilder.append(\", \");\r\n\t\tbuilder.append(\"hash=\");\r\n\t\tbuilder.append(hash);\r\n\t\tif (data != null) {\r\n\t\t\tbuilder.append(\", \");\r\n\t\t\tbuilder.append(\"data=\");\r\n\t\t\tbuilder.append(data);\r\n\t\t}\r\n\t\tbuilder.append(\"]\");\r\n\t\treturn builder.toString();\r\n\t}\r\n}\r\n<\/pre>\n<p>Die Blockchain:<\/p>\n<pre class=\"lang:java decode:true \" >package de.wenzlaff.blockchain;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\nimport org.apache.logging.log4j.LogManager;\r\nimport org.apache.logging.log4j.Logger;\r\n\r\nimport de.wenzlaff.blockchain.be.Block;\r\n\r\n\/**\r\n * Blockchain Test.\r\n * \r\n * @author Thomas Wenzlaff\r\n *\/\r\npublic class Blockchain {\r\n\r\n\tprivate static final Logger LOG = LogManager.getLogger(Blockchain.class);\r\n\r\n\t\/** Die Blockchain. *\/\r\n\tprivate List&lt;Block&gt; chain;\r\n\r\n\tpublic Blockchain() {\r\n\t\tchain = new ArrayList&lt;&gt;();\r\n\t}\r\n\r\n\tpublic boolean add(Block block) {\r\n\t\treturn chain.add(block);\r\n\t}\r\n\r\n\tpublic boolean checkBlockchain() {\r\n\t\tboolean ergebnis = validate();\r\n\t\tif (ergebnis) {\r\n\t\t\tLOG.info(\"Die Blockchain ist g\u00fcltig.\");\r\n\t\t} else {\r\n\t\t\tLOG.error(\"Die Blockchain ist gehackt worden und ung\u00fcltig.\");\r\n\t\t}\r\n\t\treturn ergebnis;\r\n\t}\r\n\r\n\tpublic void printBlockchain() {\r\n\t\tchain.forEach(b -&gt; LOG.info(b));\r\n\t}\r\n\r\n\tpublic int getPreviousHash() {\r\n\t\treturn chain.get(getAnzahlBlocks() - 1).getHash();\r\n\t}\r\n\r\n\tpublic Block get(int i) {\r\n\t\treturn chain.get(i);\r\n\t}\r\n\r\n\tpublic void remove(int i) {\r\n\t\tchain.remove(i);\r\n\t}\r\n\r\n\tpublic void add(int i, Block block) {\r\n\t\tchain.add(i, block);\r\n\t}\r\n\r\n\tpublic int getAnzahlBlocks() {\r\n\t\treturn chain.size();\r\n\t}\r\n\r\n\tpublic boolean validate() {\r\n\r\n\t\tboolean result = true;\r\n\r\n\t\tBlock lastBlock = null;\r\n\t\tfor (int i = getAnzahlBlocks() - 1; i &gt;= 0; i--) {\r\n\t\t\tif (lastBlock == null) {\r\n\t\t\t\tlastBlock = get(i);\r\n\t\t\t} else {\r\n\t\t\t\tBlock current = get(i);\r\n\t\t\t\tif (lastBlock.getPreviousHash() != current.getHash()) {\r\n\t\t\t\t\tresult = false;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\tlastBlock = current;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n}<\/pre>\n<p>Die Junit 5 Testklasse mit den beiden Testf\u00e4llen:<\/p>\n<pre class=\"lang:java decode:true \" >package de.wenzlaff.blockchain;\r\n\r\nimport static org.junit.jupiter.api.Assertions.assertFalse;\r\nimport static org.junit.jupiter.api.Assertions.assertTrue;\r\n\r\nimport org.apache.logging.log4j.LogManager;\r\nimport org.apache.logging.log4j.Logger;\r\nimport org.junit.jupiter.api.BeforeEach;\r\nimport org.junit.jupiter.api.Test;\r\n\r\nimport de.wenzlaff.blockchain.be.Block;\r\n\r\n\/**\r\n * Testet die Blockchain.\r\n * \r\n * @author Thomas Wenzlaff\r\n *\r\n *\/\r\nclass BlockchainTest {\r\n\r\n\tprivate static final Logger LOG = LogManager.getLogger(BlockchainTest.class);\r\n\r\n\t\/** Die zu testende Blockchain. *\/\r\n\tprivate Blockchain chain;\r\n\r\n\t@BeforeEach\r\n\tvoid iniBlockchain() {\r\n\t\tchain = new Blockchain();\r\n\r\n\t\tBlock genesisBlock = new Block(\"Erster Block (genesis) der Blockchain\", 0);\r\n\t\tchain.add(genesisBlock);\r\n\r\n\t\tBlock zweiterBlock = new Block(\"Zweiter Block\", chain.getPreviousHash());\r\n\t\tchain.add(zweiterBlock);\r\n\r\n\t\tBlock dritterBlock = new Block(\"Dritter Block mit Daten\", chain.getPreviousHash());\r\n\t\tchain.add(dritterBlock);\r\n\r\n\t\tBlock vierterBlock = new Block(\"Vierter Block auch mit super Daten.\", chain.getPreviousHash());\r\n\t\tchain.add(vierterBlock);\r\n\r\n\t\tBlock letzterBlock = new Block(\"5. und letzter Block\", chain.getPreviousHash());\r\n\t\tchain.add(letzterBlock);\r\n\r\n\t\tLOG.info(\"Blockchain mit \" + chain.getAnzahlBlocks() + \" Bl\u00f6cken f\u00fcr Test erzeugt.\");\r\n\t}\r\n\r\n\t\/**\r\n\t * Positiver Test.\r\n\t *\/\r\n\t@Test\r\n\tvoid testBlockchain() {\r\n\r\n\t\tchain.printBlockchain();\r\n\t\tassertTrue(chain.checkBlockchain());\r\n\t}\r\n\r\n\t\/**\r\n\t * Test wie eine ver\u00e4nderte Blockchain erkannt wird: ersetzen des zweiten Block\r\n\t * durch einen ver\u00e4nderten bzw. gehackten Block. Es passen die Hash nicht mehr\r\n\t *\/\r\n\t@Test\r\n\tvoid testBlockchainHack() {\r\n\r\n\t\tBlock gehackterBlock = new Block(\"Verf\u00e4lschte Daten\", chain.get(0).getHash());\r\n\t\tchain.remove(1);\r\n\t\tchain.add(1, gehackterBlock);\r\n\r\n\t\tchain.printBlockchain();\r\n\t\tassertFalse(chain.checkBlockchain());\r\n\t}\r\n}\r\n<\/pre>\n<p>Die Ausgabe des pos. Tests:<\/p>\n<pre class=\"lang:default decode:true \" >[INFO ] 2021-04-13 22:20:20,309 Block.&lt;init&gt;() - Neuen Block erzeugt mit Hash: -465238321\r\n[INFO ] 2021-04-13 22:20:20,312 Block.&lt;init&gt;() - Neuen Block erzeugt mit Hash: -870077405\r\n[INFO ] 2021-04-13 22:20:20,312 Block.&lt;init&gt;() - Neuen Block erzeugt mit Hash: 1814193111\r\n[INFO ] 2021-04-13 22:20:20,312 Block.&lt;init&gt;() - Neuen Block erzeugt mit Hash: 791461576\r\n[INFO ] 2021-04-13 22:20:20,312 Block.&lt;init&gt;() - Neuen Block erzeugt mit Hash: 1378020438\r\n[INFO ] 2021-04-13 22:20:20,312 BlockchainTest.iniBlockchain() - Blockchain mit 5 Bl\u00f6cken f\u00fcr Test erzeugt.\r\n[INFO ] 2021-04-13 22:20:20,315 Blockchain.lambda$printBlockchain$0() - Block [previousHash=0, hash=-465238321, data=Erster Block (genesis) der Blockchain]\r\n[INFO ] 2021-04-13 22:20:20,315 Blockchain.lambda$printBlockchain$0() - Block [previousHash=-465238321, hash=-870077405, data=Zweiter Block]\r\n[INFO ] 2021-04-13 22:20:20,315 Blockchain.lambda$printBlockchain$0() - Block [previousHash=-870077405, hash=1814193111, data=Dritter Block mit Daten]\r\n[INFO ] 2021-04-13 22:20:20,315 Blockchain.lambda$printBlockchain$0() - Block [previousHash=1814193111, hash=791461576, data=Vierter Block auch mit super Daten.]\r\n[INFO ] 2021-04-13 22:20:20,315 Blockchain.lambda$printBlockchain$0() - Block [previousHash=791461576, hash=1378020438, data=5. und letzter Block]\r\n[INFO ] 2021-04-13 22:20:20,316 Blockchain.checkBlockchain() - Die Blockchain ist g\u00fcltig.<\/pre>\n<p>Und der Test, wenn jemand versucht die Blockchain zu hacken:<\/p>\n<pre class=\"lang:default decode:true \" >[INFO ] 2021-04-13 22:21:31,821 Block.&lt;init&gt;() - Neuen Block erzeugt mit Hash: -465238321\r\n[INFO ] 2021-04-13 22:21:31,823 Block.&lt;init&gt;() - Neuen Block erzeugt mit Hash: -870077405\r\n[INFO ] 2021-04-13 22:21:31,824 Block.&lt;init&gt;() - Neuen Block erzeugt mit Hash: 1814193111\r\n[INFO ] 2021-04-13 22:21:31,824 Block.&lt;init&gt;() - Neuen Block erzeugt mit Hash: 791461576\r\n[INFO ] 2021-04-13 22:21:31,824 Block.&lt;init&gt;() - Neuen Block erzeugt mit Hash: 1378020438\r\n[INFO ] 2021-04-13 22:21:31,824 BlockchainTest.iniBlockchain() - Blockchain mit 5 Bl\u00f6cken f\u00fcr Test erzeugt.\r\n[INFO ] 2021-04-13 22:21:31,826 Block.&lt;init&gt;() - Neuen Block erzeugt mit Hash: 1371965362\r\n[INFO ] 2021-04-13 22:21:31,827 Blockchain.lambda$printBlockchain$0() - Block [previousHash=0, hash=-465238321, data=Erster Block (genesis) der Blockchain]\r\n[INFO ] 2021-04-13 22:21:31,827 Blockchain.lambda$printBlockchain$0() - Block [previousHash=-465238321, hash=1371965362, data=Verf\u00e4lschte Daten]\r\n[INFO ] 2021-04-13 22:21:31,827 Blockchain.lambda$printBlockchain$0() - Block [previousHash=-870077405, hash=1814193111, data=Dritter Block mit Daten]\r\n[INFO ] 2021-04-13 22:21:31,827 Blockchain.lambda$printBlockchain$0() - Block [previousHash=1814193111, hash=791461576, data=Vierter Block auch mit super Daten.]\r\n[INFO ] 2021-04-13 22:21:31,827 Blockchain.lambda$printBlockchain$0() - Block [previousHash=791461576, hash=1378020438, data=5. und letzter Block]\r\n[ERROR] 2021-04-13 22:21:31,828 Blockchain.checkBlockchain() - Die Blockchain ist gehackt worden und ung\u00fcltig.<\/pre>\n<p>Das ganze Projekt kann <a href=\"https:\/\/gitlab.com\/IT-Berater\/twblockchain\/-\/tree\/v0.0.1\" rel=\"noopener\" target=\"_blank\">hier als Maven Beispielprojekt (branch 0.0.1)<\/a> von GitLab geladen werden.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wollte heute mal noch vor dem B\u00f6rsengang von Coinbase ein Blockchain in Java coden. Mit nur zwei Klassen sind die Grundlagen implementiert. D.h. ein Block verweist jeweils auf den n\u00e4chsten Block. Jeder Block hat einen Hash \u00fcber die Daten und kann so von jedem validiert werden. Ein Block kann alles enthalten, hier mal ein String &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/blog.wenzlaff.de\/?p=16696\" class=\"more-link\"><span class=\"screen-reader-text\">\u201eBlockchain in Java &#8211; Bitcoin heute Neues Allzeithoch &#8211; Nasdaq: B\u00f6rsengang von Coinbase\u201c <\/span>weiterlesen<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[220,4606,4,5,3163,1319],"tags":[4839,1183,4837,4841,4611,4842,4838,4840],"class_list":["post-16696","post","type-post","status-publish","format-standard","hentry","category-anleitung","category-crypto","category-eclipse","category-java","category-maven","category-sicherheit-2","tag-allzeithoch","tag-bitcoin","tag-blockchain-in-java","tag-boersengang","tag-btc","tag-coinbase","tag-heute","tag-nasdaq"],"_links":{"self":[{"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/posts\/16696","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=16696"}],"version-history":[{"count":0,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/posts\/16696\/revisions"}],"wp:attachment":[{"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=16696"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=16696"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=16696"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}