Nach der Erzeugung und Erweiterung eines Timestamps kommen wir nun zur wichtigsten Funktion, nämlich der Überprüfung („Verifizierung“) des Timestamps. Da diese Überprüfung in der Regel von einem Dritten durchgeführt werden soll, braucht Ihr dem Prüfer lediglich die Originaldatei, die erweiterte Timestamp-Datei und dieses Programm geben – das eigene Wallet wird NICHT an den Dritten gegeben.
Das Programm baut im Wege der Überprüfung eine direkte Verbindung zum Bitcoin (Test-)Netzwerk auf und bittet einen Node, ihm die Daten eines speziellen Blocks im Rohformat zur Verfügung zu stellen. Anschließend geht das Programm durch alle Transaktionen dieses Blocks durch und sucht „unsere“ Transaktion, in der sich der Hashwert befindet. Sobald der Hashwert gefunden ist und mit dem aktuellen Hashwert der Originaldatei übereinstimmt wird „grünes“ Licht gegeben.
Hier nun die einfach zu bedienende Oberfläche – zuerst wählen wir eine Datei aus deren Timestamp wir verifizieren wollen (die erweiterte Timestamp-Datei muss „neben“ der Originaldatei liegen:
Das Programm verbindet sich nun mit dem Netzwerk und fragt nach den Daten des gewünschten Blockes – etwas warten ist angesagt:
Manchmal kann es sein, das der Node nicht schnell genug antwortet – bitte startet dann den Prüfvorgang erneut:
Sollte die Überprüfung positiv ausfallen erscheint eine grün unterlegte Information:
Sollte die erweiterte Timestamp-Datei nicht vorhanden sein bricht das Programm mit einer Fehlermeldung ab:
Sollte die Überprüfung fehlschlagen werden wir auch darüber informiert:
Mit diesem Artikel könnte unsere kleine Artikelreihe über den Timestamp enden aber ich habe noch eine weitere Möglichkeit der Überprüfung eines Timestamps gefunden, und zwar die Nutzung von externen Online-Programmschnittstellen; mehr dazu im Artikel BitcoinJ Überprüfe einen Timestamp API.
Die Sourcecodes findet Ihr am Ende des Artikels.
Alle Quellcodes zu BitcoinJ Timestamps & OP_RETURN findet Ihr zum Download in meinem GitHub-Repository BitcoinJTimestamp, welches Ihr über diesen Link erreicht: https://github.com/java-crypto/BitcoinJTimestamp. Alle Programme sind unter Java 11 lauffähig (vermutlich auch unter Java 8) und wurden mit intelliJ IDEA entwickelt, welches für dieses Programm aber nicht notwendig ist.
Zur Nutzung der Programme benötigt Ihr diverse Bibliotheken – ladet Euch diese aus dem separaten GitHub-Archiv (https://github.com/java-crypto/BitcoinJ_Libraries) herunter und bindet Sie über Eure Entwicklungsumgebung ein.
Noch ein Wort zum Thema „Lizenz“: Das Programm steht unter unterschiedlichen Lizenzen, die Ihr bitte beachten solltet. Die von mir erstellten Beispiele selber stehen unter der „Unlicense“-Lizenz, allerdings werden zur Laufzeit diverse Bibliotheken eingebunden, welche zum Teil ganz eigene Lizenzen mitbringen. Darauf kann ich in meinen Lizenzhinweisen nicht hinweisen.
Letzte Bearbeitung: 22.03.2020
Hier der Sourcecode des Programms und der Form; den Quellcode der Klasse RedirectedFrame.java findet Ihr in meinem GitHub-Repository:
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 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
/* * Herkunft/Origin: http://javacrypto.bplaced.net/ * Programmierer/Programmer: Michael Fehr * Copyright/Copyright: Michael Fehr * Lizenttext/Licence: verschiedene Lizenzen / several licenses * getestet mit/tested with: Java Runtime Environment 11.0.5 x64 * verwendete IDE/used IDE: intelliJ IDEA 2019.3.1 * Datum/Date (dd.mm.jjjj): 21.03.2020 * Funktion: Ueberprueft die Timestamp-Datei in der Bitcoin Blockchain * Function: verifies the timestamp-file in Bitcoin blockchain * * 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 ! * * Sie benötigen diverse Bibliotheken (alle im Github-Archiv im Unterordner "libs") * You need a lot of libraries (see my Github-repository in subfolder "libs") * verwendete BitcoinJ-Bibliothek / used BitcoinJ Library: bitcoinj-core-0.15.6.jar * my Github-Repository: https://github.com/java-crypto/BitcoinJ * libs in my Github-Repo: https://github.com/java-crypto/BitcoinJ_Libraries * */ import org.bitcoinj.core.*; import org.bitcoinj.net.discovery.DnsDiscovery; import org.bitcoinj.params.MainNetParams; import org.bitcoinj.params.RegTestParams; import org.bitcoinj.params.TestNet3Params; import org.bitcoinj.script.Script; import org.bitcoinj.script.ScriptChunk; import org.bitcoinj.store.BlockStore; import org.bitcoinj.store.BlockStoreException; import org.bitcoinj.store.MemoryBlockStore; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class BitcoinJVerifyATimestamp { PeerGroup peerGroup; public NetworkParameters netParams; private LocalDateTime localDateTimeStart; private LocalDateTime localDateTimeEnd; private String filenameTimestamp; private String filenameTimestampExtendedAppend = ".timestamp_extended.txt"; private int searchTimeout = 20; // seconds for searching private Sha256Hash sha256Hash; private Color colorStatus; public BitcoinJVerifyATimestamp() throws IOException, InterruptedException { // choose network type (MAIN, TEST or REG) //String networkType = "MAIN"; String networkType = "TEST"; //String networkType = "REG"; switch (networkType) { case "MAIN": { netParams = MainNetParams.get(); break; } case "TEST": { netParams = TestNet3Params.get(); break; } case "REG": { netParams = RegTestParams.get(); break; } default: { System.out.println("Es ist kein networkType angegeben, das Programm wird in 10 Sekunden beendet"); tfStatus.setText("Kein networkType angegeben, Programm endet in 10 Sekunden"); tfStatus.setBackground(Color.RED); TimeUnit.SECONDS.sleep(10); System.exit(0); } } System.out.println("Das Programm arbeitet im Netzwerk: " + netParams.getId()); System.out.println("Guten Tag, zum Start bitte den Button 'waehlen Sie die Datei um den Zeitstempel zu verifizieren' druecken"); localDateTimeStart = LocalDateTime.now(); colorStatus = tfStatus.getBackground(); progressBarWait.setVisible(false); progressBarWait.setIndeterminate(false); btnFileChooser.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { tfFile.setText(""); tfHash.setText(""); tfBlockHeight.setText(""); tfBlockHash.setText(""); tfProofFile.setText(""); tfTxId.setText(""); tfStatus.setText(""); filenameTimestamp = ""; sha256Hash = null; tfStatus.setBackground(colorStatus); File file = chooseFile(); try { tfFile.setText(file.toString()); } catch (NullPointerException e) { } if (tfFile.getText() != "") { filenameTimestamp = tfFile.getText(); System.out.println("Datei dessen Timestamp ueberprueft werden soll: " + filenameTimestamp); try { sha256Hash = Sha256Hash.of(file); } catch (IOException e) { e.printStackTrace(); } tfHash.setText(String.valueOf(sha256Hash)); // perform the next steps System.out.println("\nInformationen im OP_RETURN-Bereich der Transaktion werden verifiziert:"); // wir prüfen ob die proof-datei existiert String filenameExtendedTimestamp = tfFile.getText() + filenameTimestampExtendedAppend; tfProofFile.setText(filenameExtendedTimestamp); File fileTimestamp = new File(filenameExtendedTimestamp); System.out.println("Die erweiterte Timestampdatei " + filenameExtendedTimestamp + " ist vorhanden: " + fileTimestamp.exists()); if (!fileTimestamp.exists()) { System.out.println("Die erweiterte Timestampdatei ist nicht vorhanden und kann nicht verifiziert werden"); return; } if (!fileTimestamp.canRead() || !fileTimestamp.isFile()) { //System.exit(0); return; } tfStatus.setText("warten auf die Antwort eines Nodes (maximal " + searchTimeout + " Sekunden)"); tfStatus.setBackground(Color.YELLOW); BufferedReader in = null; String zeile = ""; try { in = new BufferedReader(new FileReader(filenameExtendedTimestamp)); zeile = null; // nur drei zeilen werden gelesen // erste zeile transaction hash tfTxId.setText(in.readLine().toUpperCase()); // zweite zeile block hash tfBlockHash.setText(in.readLine()); // dritte zeile block height tfBlockHeight.setText(in.readLine()); } catch (IOException e) { e.printStackTrace(); } finally { if (in != null) try { in.close(); } catch (IOException e) { } } try { in.close(); } catch (IOException e) { e.printStackTrace(); } System.out.println(("TxId in der Datei: " + tfTxId.getText())); Sha256Hash blockHash = Sha256Hash.wrap(tfBlockHash.getText()); byte[] hashToFind = hexStringToByteArray(tfHash.getText()); btnFileChooser.setEnabled(false); progressBarWait.setString("Der Node wird kontaktiert, bitte warten ..."); progressBarWait.setStringPainted(true); progressBarWait.setVisible(true); progressBarWait.setIndeterminate(true); Thread thread = new Thread() { public void run() { System.out.println("btn chooseFile Thread Running"); // ab hier wird verifiziert BlockStore blockStore = new MemoryBlockStore(netParams); BlockChain chain = null; try { chain = new BlockChain(netParams, blockStore); } catch (BlockStoreException e) { e.printStackTrace(); } peerGroup = new PeerGroup(netParams, chain); peerGroup.setUserAgent("Sample App", "1.0"); // ausführung nicht im REG / RegressionNetwork if (netParams != RegTestParams.get()) { peerGroup.addPeerDiscovery(new DnsDiscovery(netParams)); } PeerAddress addr = null; try { addr = new PeerAddress(netParams, InetAddress.getLocalHost()); } catch (UnknownHostException e) { e.printStackTrace(); } peerGroup.addAddress(addr); peerGroup.start(); try { peerGroup.waitForPeers(1).get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } Peer peer = peerGroup.getConnectedPeers().get(0); // System.out.println("Vor: Future<Block> future = peer.getBlock(blockHash);"); Future<Block> future = peer.getBlock(blockHash); System.out.println("Warten auf die Antwort eines Nodes mit dem gesuchten Block: " + blockHash); Block block = null; try { //block = future.get(); block = future.get(searchTimeout, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { //} catch (InterruptedException | ExecutionException e) { e.printStackTrace(); System.out.println("Der Node hat kein Ergebnis innerhalb von " + searchTimeout + " Sekunden abgeliefert, die Suche endet jetzt"); tfStatus.setText("Suche ergebnislos beendet (Timeout von " + searchTimeout + " Sekunden)"); tfStatus.setBackground(Color.ORANGE); btnFileChooser.setEnabled(true); progressBarWait.setVisible(false); progressBarWait.setIndeterminate(false); future.cancel(true); //this method will stop the running underlying task return; } //System.out.println("Hier das Ergebnis des Node Blocks:\n" + block); System.out.println("Gesuchte Transaktion: " + tfTxId.getText()); System.out.println("Gesuchter Hash : " + tfHash.getText()); boolean txOpReturnFound = findTx(block, tfTxId.getText(), tfHash.getText()); if (txOpReturnFound == true) { System.out.println("Timestamp BESTAETIGT - der Hash wurde in der Transaktion gefunden"); tfStatus.setText("Timestamp BESTAETIGT - der Hash wurde in der Transaktion gefunden"); tfStatus.setBackground(Color.GREEN); } else { tfStatus.setText("Timestamp NICHT BESTAEIGT - der Hash wurde NICHT in der Transaktion gefunden"); System.out.println("Timestamp NICHT BESTAETIGT - der Hash wurde NICHT in der Transaktion gefunden"); tfStatus.setBackground(Color.RED); } progressBarWait.setString("Verbindung zum Node wird beendet, bitte warten ..."); peerGroup.stopAsync(); btnFileChooser.setEnabled(true); progressBarWait.setVisible(false); progressBarWait.setIndeterminate(false); } }; thread.start(); } // do nothing } }); btnClose.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { localDateTimeEnd = LocalDateTime.now(); tfStatus.setText("Das Programm wird beendet, bitte warten ..."); System.out.println("Date & Time at Start: " + localDateTimeStart.toString()); System.out.println("Date & Time at End: " + localDateTimeEnd.toString()); System.exit(0); } }); } public boolean findTx(Block block, String tfTxId, String tfHash) { boolean txFound = false; int txIdFound = 0; boolean txOpReturnFound = false; // get transactions List<Transaction> transactions = block.getTransactions(); int transactionsSize = transactions.size(); //System.out.println("There are " + transactionsSize + " transactions in block"); for (int i = 0; i < transactionsSize; i++) { Transaction tx = transactions.get(i); String txId = tx.getTxId().toString().toUpperCase(); //System.out.println("txId: " + txId); //System.out.println("txId " + i + " ist " + txId); if (txId.equals(tfTxId)) { //System.out.println(" * Transaktion " + tfTxId + " gefunden in Nr " + i); txFound = true; txIdFound = i; break; } } if (txFound == true) { Transaction txWorks = transactions.get(txIdFound); List<TransactionOutput> txOutputs = txWorks.getOutputs(); int txOutputsSize = txOutputs.size(); //System.out.println(" There are " + txOutputsSize + " Outputs in the transaction"); for (int i = 0; i < txOutputsSize; i++) { TransactionOutput txOutput = txOutputs.get(i); //System.out.println(" Output Nr " + i + " ist " + txOutput.toString()); Script txOutputScriptPubKey = txOutput.getScriptPubKey(); //System.out.println("Script PubKey: " + txOutputScriptPubKey); Script.ScriptType txOutputScryptType = txOutputScriptPubKey.getScriptType(); //System.out.println("ScriptType: " + txOutputScryptType); List<ScriptChunk> txOutputScriptPubKeyChunks = txOutputScriptPubKey.getChunks(); int txOutputScriptPubKeyChunksSize = txOutputScriptPubKeyChunks.size(); //System.out.println("Chunks: " + txOutputScriptPubKeyChunksSize); for (int j = 0; j < txOutputScriptPubKeyChunksSize; j++) { ScriptChunk chunk = txOutputScriptPubKeyChunks.get(j); //System.out.println("Chunk " + j + " ist " + chunk); //System.out.println("chunk opcode " + chunk.opcode); byte[] chunkData = null; //System.out.println("Suche nun chunkData"); try { chunkData = chunk.data; //System.out.println("chunkData : " + bytesToHex(chunkData)); byte[] hashToFind = hexStringToByteArray(tfHash); //System.out.println("hashToFind: " + bytesToHex(hashToFind)); if (Arrays.equals(chunkData, hashToFind)) { //System.out.println(" *** Hash gefunden***"); txOpReturnFound = true; } } catch (NullPointerException e) { //System.out.println("NPE keine chunkData gefunden"); } } } } return txOpReturnFound; } private File chooseFile() { JFileChooser chooser = new JFileChooser(); if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { return chooser.getSelectedFile(); } else { return null; } } private static String bytesToHex(byte[] bytes) { StringBuffer result = new StringBuffer(); for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1)); return result.toString(); } public static byte[] hexStringToByteArray(String s) { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); } return data; } private static String getActualDateReverse() { // provides the actual date and time in this format yyyy-MM-dd_HH-mm-ss e.g. 2020-03-16_10-27-15 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss"); LocalDateTime today = LocalDateTime.now(); return formatter.format(today); } public static void main(String[] args) throws IOException, InterruptedException { JFrame frame = new JFrame("Ueberpruefe einen Timestamp"); // umleitung der konsole in 2 fenster RedirectedFrame outputFrameErrors = new RedirectedFrame("Log Frame", true, false, true, "BitcoinJ_VerifyTimestamp_Logfile_" + getActualDateReverse() + ".txt", 750, 650, JFrame.DO_NOTHING_ON_CLOSE); RedirectedFrame outputFrameOutput = new RedirectedFrame("Output Frame", false, true, true, "BitcoinJ_VerifyTimestamp_Output_" + getActualDateReverse() + ".txt", 700, 600, JFrame.DO_NOTHING_ON_CLOSE); frame.setContentPane(new BitcoinJVerifyATimestamp().mainPanel); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.pack(); frame.setSize(700, 450); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } private JPanel mainPanel; private JButton btnFileChooser; private JTextField tfFile; private JTextField tfHash; private JTextField tfBlockHeight; private JTextField tfProofFile; private JTextField tfTxId; private JTextField tfStatus; private JButton btnClose; private JTextField tfBlockHash; private JProgressBar progressBarWait; } |
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 |
<?xml version="1.0" encoding="UTF-8"?> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="BitcoinJVerifyATimestamp"> <grid id="27dc6" binding="mainPanel" layout-manager="GridLayoutManager" row-count="18" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="10" left="10" bottom="10" right="10"/> <constraints> <xy x="20" y="20" width="528" height="509"/> </constraints> <properties/> <border type="none"/> <children> <component id="6a45a" class="javax.swing.JButton" binding="btnFileChooser"> <constraints> <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/> </constraints> <properties> <enabled value="true"/> <text value="waehlen Sie die Datei um den Zeitstempel zu verifizieren"/> </properties> </component> <component id="e0fd9" class="javax.swing.JSeparator"> <constraints> <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> </component> <component id="f1a03" class="javax.swing.JTextField" binding="tfFile"> <constraints> <grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> <preferred-size width="150" height="-1"/> </grid> </constraints> <properties> <editable value="false"/> </properties> </component> <component id="4d2b1" class="javax.swing.JLabel"> <constraints> <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="Datei:"/> </properties> </component> <component id="93929" class="javax.swing.JSeparator"> <constraints> <grid row="4" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> </component> <component id="6fa8" class="javax.swing.JTextField" binding="tfHash"> <constraints> <grid row="5" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> <preferred-size width="150" height="-1"/> </grid> </constraints> <properties> <editable value="false"/> </properties> </component> <component id="14985" class="javax.swing.JLabel"> <constraints> <grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="SHA256-Hash:"/> </properties> </component> <component id="287a2" class="javax.swing.JSeparator"> <constraints> <grid row="6" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> </component> <component id="3e91c" class="javax.swing.JTextField" binding="tfBlockHeight"> <constraints> <grid row="7" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> <preferred-size width="150" height="-1"/> </grid> </constraints> <properties> <editable value="false"/> </properties> </component> <component id="95cad" class="javax.swing.JLabel"> <constraints> <grid row="7" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="Block Height:"/> </properties> </component> <component id="75695" class="javax.swing.JSeparator"> <constraints> <grid row="8" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> </component> <component id="2fb3a" class="javax.swing.JTextField" binding="tfProofFile"> <constraints> <grid row="11" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> <preferred-size width="150" height="-1"/> </grid> </constraints> <properties> <editable value="false"/> </properties> </component> <component id="6b8af" class="javax.swing.JLabel"> <constraints> <grid row="11" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="Erweiterte Timestamp-Datei:"/> </properties> </component> <component id="c2ef" class="javax.swing.JSeparator"> <constraints> <grid row="12" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> </component> <component id="f9349" class="javax.swing.JTextField" binding="tfTxId"> <constraints> <grid row="13" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> <preferred-size width="150" height="-1"/> </grid> </constraints> <properties> <editable value="false"/> </properties> </component> <component id="d1077" class="javax.swing.JLabel"> <constraints> <grid row="13" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="TxId:"/> </properties> </component> <component id="49fa" class="javax.swing.JSeparator"> <constraints> <grid row="14" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> </component> <component id="e8ac2" class="javax.swing.JTextField" binding="tfStatus"> <constraints> <grid row="15" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> <preferred-size width="150" height="-1"/> </grid> </constraints> <properties> <editable value="false"/> </properties> </component> <component id="999d5" class="javax.swing.JLabel"> <constraints> <grid row="15" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="Status:"/> </properties> </component> <component id="82258" class="javax.swing.JButton" binding="btnClose"> <constraints> <grid row="17" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="Ende des Programms"/> </properties> </component> <component id="4b3fc" class="javax.swing.JTextField" binding="tfBlockHash"> <constraints> <grid row="9" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> <preferred-size width="150" height="-1"/> </grid> </constraints> <properties> <editable value="false"/> </properties> </component> <component id="7be3c" class="javax.swing.JSeparator"> <constraints> <grid row="10" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> </component> <component id="7d86d" class="javax.swing.JLabel"> <constraints> <grid row="9" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> </constraints> <properties> <text value="Block Hash:"/> </properties> </component> <component id="4d21b" class="javax.swing.JSeparator"> <constraints> <grid row="16" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/> </constraints> <properties/> </component> <component id="fb506" class="javax.swing.JProgressBar" binding="progressBarWait"> <constraints> <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"> <minimum-size width="-1" height="20"/> </grid> </constraints> <properties/> </component> </children> </grid> </form> |