Grundsätzlich funktioniert unser JavaCryptoCoin schon, aber wir wollen noch etwas näher an den realen „Bitcoin“ heran. Dort (und bei anderen Crypto-Währungen auch) wird der Schürfer („miner“) für seine Suche nach einem passenden Hashwert belohnt, in dem er einen Coin für seine Tätigkeit erhält.
Der Quellcode wird dafür im Hauptprogramm erweitert, alle übrigen Quellcodes sind unverändert. Daher zeige ich auf dieser Seite nur den Quellcode des Hauptprogramms und die Konsolenausgabe, die übrigen Sourcen sind im Unterartikel I09b Der JavaCryptoCoin komplett zu finden.
Schaut Euch in der Hauptklasse JavaCryptoCoin die Programmzeilen 287 bis 301 an – hier wird die Belohnung für den Miner realisiert:
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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
package net.bplaced.javacrypto.blockchain.step9; /* * 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): 15.06.2019 * Projekt/Project: Blockchain / JavaCryptoCoin * Funktion: Schritt 8: die neue Krypto-Währung - JavaCryptoCoin * Function: Step 8: the new crypto currency - JavaCryptoCoin * * 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 * https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce * Die Belohnung des Miners wird hier ergänzt / The reward for the miner is added here: * https://github.com/hansoctantan/NoobWalletUpdated */ import java.security.PublicKey; import java.util.ArrayList; import java.util.HashMap; import java.io.IOException; public class JavaCryptoCoin { public static ArrayList<Block> blockchain = new ArrayList<Block>(); public static HashMap<String, TransactionOutput> UTXOs = new HashMap<String, TransactionOutput>(); public static int difficulty = 4; // kann ganz vorsichtig erhöht werden public static float minimumTransaction = 0.1f; public static Wallet coinbase; public static Wallet walletA; public static Wallet walletB; public static Wallet miner; public static Transaction genesisTransaction; public static void main(String[] args) throws IOException { System.out.println("I09 BlockChain für Anfänger Stufe 09 JavaCryptoCoin komplett"); // unsere variablen für das programm String filenameBlockchain = "i09_blockchain.txt"; String filenameBlockchainJson = "i09_blockchain.json"; String filenameWalletA = "i09_walleta.txt"; String filenameWalletAJson = "i09_walleta.json"; String filenameWalletB = "i09_walletb.txt"; String filenameMiner = "i09_miner.txt"; // generierung der wallets coinbase = new Wallet(); walletA = new Wallet(); walletB = new Wallet(); miner = new Wallet(); float totalCoins = 0; // erzeuge die genesis transaktion und sende 100 javacryptocoins an walletA // ("initial coin offering") genesisTransaction = new Transaction(coinbase.publicKey, walletA.publicKey, 100f, null); genesisTransaction.generateSignature(coinbase.privateKey); // manuelle signatur der genesis transaktion genesisTransaction.transactionId = "0"; // manuelles setzen der transaktion id genesisTransaction.outputs.add(new TransactionOutput(genesisTransaction.recipient, genesisTransaction.value, genesisTransaction.transactionId)); // manuelles hinzufügen der transaktion zu den Transactions Output // es ist wichtig die erste transaktion in der UTXOs liste zu speichern UTXOs.put(genesisTransaction.outputs.get(0).id, genesisTransaction.outputs.get(0)); // der erste block wird in die blockchain geschrieben und gemined System.out.println("\nErzeuge und mine den Genesis block"); Block genesis = new Block("0"); genesis.addTransaction(genesisTransaction); addBlock(genesis); System.out.println("\nGuthaben der Wallets:"); System.out.println("Guthaben von coinbase: " + coinbase.getBalance()); System.out.println("Guthaben von walletA : " + walletA.getBalance()); System.out.println("Guthaben von walletB : " + walletB.getBalance()); System.out.println("Guthaben von miner : " + miner.getBalance()); // speicherung der blockchain und der wallets System.out.println("\nSpeicherung der Blockchain und der Wallets"); FileUtil.saveObject(filenameBlockchain, blockchain); FileUtil.saveObject(filenameWalletA, walletA); FileUtil.saveObject(filenameWalletB, walletB); FileUtil.saveObject(filenameMiner, miner); // der public key ist die empfänger-adresse, daher sichern wir diese daten System.out.println("\nEmpfänger-Adressen von walletA und walletB"); PublicKey publicKeyA = walletA.publicKey; PublicKey publicKeyB = walletB.publicKey; String publicKeyAString = StringUtil.getStringFromKey(publicKeyA); String publicKeyBString = StringUtil.getStringFromKey(publicKeyB); System.out.println("publicKeyAString:" + publicKeyAString); System.out.println("publicKeyBString:" + publicKeyBString); // eine überweisung von walletA an walletB System.out.println("\nÜberweisung 40 JCC von walletA an walletB"); Block blockNewA = new Block(blockchain.get(blockchain.size() - 1).hash); blockNewA.addTransaction(walletA.sendFunds(publicKeyB, 40f)); // ergänze die blockchain um den neuen block und lasse ihn minen addBlock(blockNewA); System.out.println("\nGuthaben der Wallets:"); System.out.println("Guthaben von walletA : " + walletA.getBalance()); System.out.println("Guthaben von walletB : " + walletB.getBalance()); // zwei überweisungen von walletB an walletA System.out.println("\n2 Überweisungen je 25 JCC von walletB an walletA"); Block blockNewB = new Block(blockchain.get(blockchain.size() - 1).hash); blockNewB.addTransaction(walletB.sendFunds(publicKeyA, 25f)); blockNewB.addTransaction(walletB.sendFunds(publicKeyA, 25f)); // ergänze die blockchain um den neuen block und lasse ihn minen addBlock(blockNewB); System.out.println("\nGuthaben der Wallets:"); System.out.println("Guthaben von walletA : " + walletA.getBalance()); System.out.println("Guthaben von walletB : " + walletB.getBalance()); // System.out.println(StringUtil.getJson(blockchain)); // speicherung der blockchain und der wallets System.out.println("\nSpeicherung der Blockchain und der Wallets"); FileUtil.saveObject(filenameBlockchain, blockchain); FileUtil.saveObject(filenameWalletA, walletA); FileUtil.saveObject(filenameWalletB, walletB); FileUtil.saveObject(filenameMiner, miner); // die blockchain funktioniert ohne online wallets, daher löschen wir walletB System.out.println("\nObjekt walletB gelöscht"); walletB = null; // mehrere transaktionen kommen in einen block Block block1 = new Block(blockchain.get(blockchain.size() - 1).hash); block1.addTransaction(walletA.sendFunds(publicKeyB, 40f)); block1.addTransaction(walletA.sendFunds(publicKeyB, 10.3f)); addBlock(block1); block1 = new Block(blockchain.get(blockchain.size() - 1).hash); block1.addTransaction(walletA.sendFunds(publicKeyB, 20f)); block1.addTransaction(walletA.sendFunds(publicKeyB, 1.1f)); addBlock(block1); block1 = new Block(blockchain.get(blockchain.size() - 1).hash); block1.addTransaction(walletA.sendFunds(publicKeyB, 60f)); addBlock(block1); System.out.println("\nGuthaben nach mehreren Transaktionen"); System.out.println("Guthaben von miner : " + miner.getBalance()); System.out.println("Guthaben von walletA : " + walletA.getBalance()); // walletB laden System.out.println("\nobjekt walletB geladen"); walletB = (Wallet) FileUtil.loadObject(filenameWalletB); System.out.println("Guthaben von walletB : " + walletB.getBalance()); System.out.println("\nSende Coins an walletA"); Block blockB1 = new Block(blockchain.get(blockchain.size() - 1).hash); blockB1.addTransaction(walletB.sendFunds(walletA.publicKey, 11.123f)); addBlock(blockB1); System.out.println("Guthaben von walletA : " + walletA.getBalance()); System.out.println("Guthaben von walletB : " + walletB.getBalance()); System.out.println("_miner's balance is : " + miner.getBalance()); System.out.println("\nSende Coins vom miner an walletA"); Block blockMiner = new Block(blockchain.get(blockchain.size() - 1).hash); blockMiner.addTransaction(miner.sendFunds(walletA.publicKey, 4.5f)); addBlock(blockMiner); System.out.println("Guthaben von walletA : " + walletA.getBalance()); System.out.println("Guthaben von walletB : " + walletB.getBalance()); System.out.println("Guthaben von miner : " + miner.getBalance()); System.out.println("\nSende 1 Coin vom miner an walletA"); blockMiner = new Block(blockchain.get(blockchain.size() - 1).hash); blockMiner.addTransaction(miner.sendFunds(walletA.publicKey, 1.00f)); System.out.println(isChainValid()); System.out.println("Guthaben von walletA : " + walletA.getBalance()); System.out.println("Guthaben von walletB : " + walletB.getBalance()); System.out.println("Guthaben von miner : " + miner.getBalance()); blockMiner.addTransaction(walletA.sendFunds(publicKeyB, 44f)); blockMiner.addTransaction(walletB.sendFunds(walletA.publicKey, 1.00f)); // System.out.println("Transaction:\n" + StringUtil.getJson(blockMiner)); blockMiner.addTransaction(walletB.sendFunds(walletA.publicKey, 2.00f)); blockMiner.addTransaction(walletB.sendFunds(walletA.publicKey, 3.00f)); addBlock(blockMiner); System.out.println("Guthaben von walletA : " + walletA.getBalance()); System.out.println("Guthaben von walletB : " + walletB.getBalance()); System.out.println("Guthaben von miner : " + miner.getBalance()); System.out.println("Guthaben von coinbase: " + coinbase.getBalance()); totalCoins = walletA.getBalance() + walletB.getBalance() + miner.getBalance() + coinbase.getBalance(); System.out.println("Gesamtguthaben : " + totalCoins); // save blockchain FileUtil.saveObject(filenameBlockchain, blockchain); System.out.println("\nBlockchain gespeichert in Datei:" + filenameBlockchain); FileUtil.saveJsonFile(filenameBlockchainJson, StringUtil.getJson(blockchain)); System.out.println("\nBlockchain im JSON-Format gespeichert in Datei:" + filenameBlockchainJson); System.out.println("\nDie Blockchain ist gültig:" + isChainValid()); // save wallet FileUtil.saveObject(filenameWalletA, walletA); System.out.println("\nWalletA gespeichert in Datei:" + filenameWalletA); FileUtil.saveJsonFile(filenameWalletAJson, StringUtil.getJson(walletA)); System.out.println("\nWalletA im JSON-Format gespeichert in Datei:" + filenameWalletAJson); System.out.println("\nProgramm beendet"); } public static Boolean isChainValid() { Block currentBlock; Block previousBlock; HashMap<String, TransactionOutput> tempUTXOs = new HashMap<>(); tempUTXOs.put(genesisTransaction.outputs.get(0).id, genesisTransaction.outputs.get(0)); for (int i = 1; i < blockchain.size(); i++) { currentBlock = blockchain.get(i); previousBlock = blockchain.get(i - 1); if (!currentBlock.hash.equals(currentBlock.calculateHash())) { System.out.println("# Die Current Hashes sind nicht gleich"); return false; } if (!previousBlock.hash.equals(currentBlock.previousHash)) { System.out.println("# Die Previous Hashes sind nicht gleich"); return false; } if (!currentBlock.mined) { System.out.println("# Dieser Block wurde noch nicht mined"); return false; } TransactionOutput tempOutput; for (int t = 0; t < currentBlock.transactions.size(); t++) { Transaction currentTransaction = currentBlock.transactions.get(t); if (!currentTransaction.verifySignature()) { System.out.println("# Die Signatur der Transaction(" + t + ") ist ungültig"); return false; } if (!currentTransaction.asReward) { if (currentTransaction.getInputsValue() != currentTransaction.getOutputsValue()) { System.out.println("# Die Inputs sind nicht gleich den Outputs der Transaktion(" + t + ")"); return false; } for (TransactionInput input : currentTransaction.inputs) { tempOutput = tempUTXOs.get(input.transactionOutputId); if (tempOutput == null) { System.out.println("# Der referenzierte Input der Transaktion(" + t + ") fehlt"); return false; } if (input.UTXO.value != tempOutput.value) { System.out .println("# Der referenzierte Input der Transaktion(" + t + ") Wert ist ungültig"); return false; } tempUTXOs.remove(input.transactionOutputId); } } for (TransactionOutput output : currentTransaction.outputs) { tempUTXOs.put(output.id, output); } if (currentTransaction.outputs.get(0).recipient != currentTransaction.recipient) { System.out.println("# Transaktion(" + t + ") Der Output Empfänger ist nicht wer er sein sollte"); return false; } if (!currentTransaction.asReward) { if (currentTransaction.outputs.get(1).recipient != currentTransaction.sender) { System.out.println("# Transaktion(" + t + ") Der Output 'change' ist nicht der Sender"); return false; } } } } return true; } public static void addBlock(Block newBlock) { newBlock.mineBlock(difficulty); // add if (!newBlock.previousHash.equals("0")) { Transaction rewardTransaction = new Transaction(coinbase.publicKey, miner.publicKey, 1f, null); // hier wird // rewarded ! rewardTransaction.asReward = true; rewardTransaction.generateSignature(coinbase.privateKey); // manually sign the genesis transaction rewardTransaction.transactionId = rewardTransaction.calculateHash(); // manually set the transaction id rewardTransaction.outputs.add(new TransactionOutput(rewardTransaction.recipient, rewardTransaction.value, rewardTransaction.transactionId)); // manually add the Transactions Output UTXOs.put(rewardTransaction.outputs.get(0).id, rewardTransaction.outputs.get(0)); // its important to store // our first transaction // in the UTXOs list. newBlock.addTransaction(rewardTransaction); } // add blockchain.add(newBlock); } } |
Die Konsole gibt ähnliche Ergebnisse zu Beispiel 08 aus, allerdings steigt das Guthaben des Miners mit jeder Transaktion an, so dass das Gesamtguthaben im System auf insgesamt 108 Coins anwächst:
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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
I09 BlockChain für Anfänger Stufe 09 JavaCryptoCoin komplett Erzeuge und mine den Genesis block Die Transaktion wurde dem Block erfolgreich hinzugefügt Block Mined!!! 78 ms: 4854dabc05a79f8427a0844356a02a288fec8072516384994db2ad8414a4b401 Guthaben der Wallets: Guthaben von coinbase: 0.0 Guthaben von walletA : 100.0 Guthaben von walletB : 0.0 Guthaben von miner : 0.0 Speicherung der Blockchain und der Wallets Empfänger-Adressen von walletA und walletB publicKeyAString:MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEECy/oAzfxrfW3qLg8LBam+NEWQgPqt20bIGw/4fre8UafeJigwV/RlfbaRmm/ZQQykzmis1y1ilp8onLERJtVw== publicKeyBString:MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+LDYPc+SWS0B+nbEZTjrn9sOStCmp1329XcUG1BU1bmyyv8W3AC6niQj66vnOPy0j6bHlGWOkSzyXLsAnrnuZA== Überweisung 40 JCC von walletA an walletB Die Transaktion wurde dem Block erfolgreich hinzugefügt Block Mined!!! 187 ms: 1222fe86e2d0893f45c792244bd1e148ca87fe0ae9074bec70f67c2fdd7379d4 Die Transaktion wurde dem Block erfolgreich hinzugefügt Guthaben der Wallets: Guthaben von walletA : 60.0 Guthaben von walletB : 40.0 2 Überweisungen je 25 JCC von walletB an walletA Die Transaktion wurde dem Block erfolgreich hinzugefügt # Das Guthaben ist zu gering um die Transaktion auszuführen, die Transaktion wurde abgebrochen. # Diese Transaktion scheitert: Empfänger:Sun EC public key, 256 bits public x coord: 7316069396682018573064932218930762862664507702966000958066707334222630845381 public y coord: 11982552396809543799043634966798505214582576478332975619926727101789815074135 parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7) Überweisungsbetrag:25.0 Block Mined!!! 16 ms: 48786c8a41487a3fbc964c644590df7fcd29d6c90451bb18026cfeae468f4335 Die Transaktion wurde dem Block erfolgreich hinzugefügt Guthaben der Wallets: Guthaben von walletA : 85.0 Guthaben von walletB : 15.0 Speicherung der Blockchain und der Wallets Objekt walletB gelöscht Die Transaktion wurde dem Block erfolgreich hinzugefügt Die Transaktion wurde dem Block erfolgreich hinzugefügt Block Mined!!! 79 ms: 08245fd2073eef1b8a80f393de8fe93cd2f1ed098a62f3a533e1442983a7e3a2 Die Transaktion wurde dem Block erfolgreich hinzugefügt Die Transaktion wurde dem Block erfolgreich hinzugefügt Die Transaktion wurde dem Block erfolgreich hinzugefügt Block Mined!!! 125 ms: 8996ac49579e5bc813adff7fc806e762cea894b3b622fd7454eedbefb5ed47ac Die Transaktion wurde dem Block erfolgreich hinzugefügt # Das Guthaben ist zu gering um die Transaktion auszuführen, die Transaktion wurde abgebrochen. # Diese Transaktion scheitert: Empfänger:Sun EC public key, 256 bits public x coord: 112486043975678562008295753886347724829541499274513166731902404545989058024889 public y coord: 80870350716512913086334443331961096255282863231261886194574728265388256783972 parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7) Überweisungsbetrag:60.0 Block Mined!!! 0 ms: 485446e65268ff8507e2e1745a850c1691de6764afcaab9e533532fe91dbb96f Die Transaktion wurde dem Block erfolgreich hinzugefügt Guthaben nach mehreren Transaktionen Guthaben von miner : 5.0 Guthaben von walletA : 13.6 objekt walletB geladen Guthaben von walletB : 86.399994 Sende Coins an walletA Die Transaktion wurde dem Block erfolgreich hinzugefügt Block Mined!!! 234 ms: 29093a832ce656765c14b161d1efe63e95f42f0cb5eed31b99f75f01d13818f7 Die Transaktion wurde dem Block erfolgreich hinzugefügt Guthaben von walletA : 24.723 Guthaben von walletB : 75.277 _miner's balance is : 6.0 Sende Coins vom miner an walletA Die Transaktion wurde dem Block erfolgreich hinzugefügt Block Mined!!! 78 ms: 51034e70063f51a615b06c3eccf669bc6b67bc68de107c33be84811fa185539d Die Transaktion wurde dem Block erfolgreich hinzugefügt Guthaben von walletA : 29.223 Guthaben von walletB : 75.277 Guthaben von miner : 2.5 Sende 1 Coin vom miner an walletA Die Transaktion wurde dem Block erfolgreich hinzugefügt true Guthaben von walletA : 30.223 Guthaben von walletB : 75.277 Guthaben von miner : 1.5 # Das Guthaben ist zu gering um die Transaktion auszuführen, die Transaktion wurde abgebrochen. # Diese Transaktion scheitert: Empfänger:Sun EC public key, 256 bits public x coord: 112486043975678562008295753886347724829541499274513166731902404545989058024889 public y coord: 80870350716512913086334443331961096255282863231261886194574728265388256783972 parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7) Überweisungsbetrag:44.0 Die Transaktion wurde dem Block erfolgreich hinzugefügt Die Transaktion wurde dem Block erfolgreich hinzugefügt Die Transaktion wurde dem Block erfolgreich hinzugefügt Block Mined!!! 203 ms: 6142b8b72fd22994f132e59144a9e169ced47cfe2310c1e47835dd945ec46961 Die Transaktion wurde dem Block erfolgreich hinzugefügt Guthaben von walletA : 36.223 Guthaben von walletB : 69.277 Guthaben von miner : 2.5 Guthaben von coinbase: 0.0 Gesamtguthaben : 108.0 Blockchain gespeichert in Datei:i09_blockchain.txt Blockchain im JSON-Format gespeichert in Datei:i09_blockchain.json Die Blockchain ist gültig:true WalletA gespeichert in Datei:i09_walleta.txt WalletA im JSON-Format gespeichert in Datei:i09_walleta.json Programm beendet |
Eine Funktionalität fehlt in unserem Beispiel und dass ist die Verteilfunktion der Blockchain. Ein wichtiges Wesensmerkmal der Blockchain ist es, dass sie nicht an einem Ort oder von einer Institution verwaltet und verwahrt wird, sondern das jeder Teilnehmer („client“) eine Kopie der Blockchain auf seinem Rechner hat. Dadurch ist sichergestellt, dass niemand die Blockchain verändern kann. In der Realität verbinden sich die Clients mit bekannten „Nodes“ und aktualisieren ihre eigene Blockchain, während sich die Nodes ihrerseits mit Nachbar-Nodes synchronisieren.
Damit kommt meine kleine Reihe zur Blockchain und dem JavaCryptoCoin zu ihrem Abschluß.
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: 15.06.2019