Förderjahr 2017 / Project Call #12 / ProjektID: 2200 / Projekt: BlockNinjas
Wie schon oft haben viele über Bitcoin gelesen und wissen mitterweile, was Bitcoin ist bzw. wie die Technologie Blockchain aufgebaut ist. Wenige aber wissen, wie die Datenstrukturen, die in der Blockchain abgespeichert werden, tatsächlich aussehen. S
Bitcoins Datenstrukturen
Wie schon oft haben viele über Bitcoin gelesen und wissen mitterweile, was Bitcoin ist bzw. wie die Technologie Blockchain aufgebaut ist. Wenige aber wissen, wie die Datenstrukturen, die in der Blockchain abgespeichert werden, tatsächlich aussehen. So ist zum Beispiel die Bitcoin Adresse oder der Hash bzw. die ID der Transaktion auch nicht Teil der Blockchain. In diesem Artikel möchten wir darauf näher eingeben.
Zu allererst betrachten wir alle Datenstrukturen, die in der Bitcoin Blockchain vorhanden sind. Es sei hier erwähnt, dass die Strukturen von Blockchain zu Blockchain unterschiedlich ausfallen. Den gemeinsamen Nenner haben alle in der Abspeicherung des Blockhashes vom vorangegangenen Block. Die Bitcoin Blockchain besteht aus „nur“ 4 Datentypen:
-
Block
-
Transaktion
-
Input
-
Output
Wobei ein Block ein oder mehrere Transaktionen, eine Transaktion ein oder mehreren Inputs und ein oder mehrere Outputs beinhalten.
Block
Betrachten wir einen Block besteht die Datenstruktur dahinter aus folgenden Feldern:
Magic-Number
Die Magic-Number ist vielen bekannt, da sie normalerweise am Beginn jeder Datei steht und die Datei dadurch, außer der Dateierweiterung, eigentlich noch genauer identifiziert. Die Blockchain von Bitcoin-Core wird so abgespeichert, dass in der .blk-Datei mehrere Blöcke zusammegefasst sind und jeder Block am Anfang die Magic-Number „f9beb4d9“ beinhaltet.
Blocksize
Diese Zahl gibt an, wieviel Byte der gesamte Block benötig, wenn man alle Daten, die darin vorhanden sind, zusammen zählt.
Previous Hash
Hier wird in den aktuellen Block der Hash des vorangegangenen Blocks hinein genommen. Denkt man an den Anfang von Bitcoin stellt sich die Frage, welcher Hash für den ersten, s.g. Genesis Block, abgespeichert wird. Bei genauerer Betrachung stellt man fest, dass es „0000000000000000000000000000000000000000000000000000000000000000“ ist.
Merkle Hash
Der Merkel Hash ist etwas komplizierter zu erklären. Aber im groben kann man ihn dadruch erklären, dass dieser Hash die Transaktionen des aktuellen Blocks identifiziert. Man kann folgende Rechenschritte heranziehen, um zu verstehen, was der Merkel Hash ist:
TX-Hash1 = hash(Transaktion1 in Block)
TX-Hash2 = hash(Transaktion2 in Block)
...
TX-Hashn = hash(Transaktionn in Block)
Merkel-Hash von Block = hash(TX-Hash1 + TX-Hash2 ... TX-Hashn)
Creation Time
Dieser Zeitpunkt definiert, wann der Block vom Blockchain Netzwerk als neuer Block angenommen wird. Wichtig zu wissen ist, dass alle Transaktionen in diesem Block genau diesen Timestamp besitzen und keine unterschiedlichen haben. Eine Transaktion kann somit nie genau einem Zeitpunkt zugeordnet werden sondern lediglich gesagt werden, dass die in diesem Block beinhaltete Transaktion in diesem Zeitraum erstellt wurde und aufgenommen wurde.
Hierbei ergeben sich sehr eigenartige Konstruktionen, denn es sei erwähnt, dass Transaktionen oft Stunden in der Blockchain verbringen, ohne in einen Block aufgenommen zu werden, da es einfach zu viele sind. Wie viele vielleicht bemerkt haben, ist bei einer Transaktion immer eine „Fee“ fällig, Diese bekommt der Miner des aktuellen Blocks. Nun ist der Miner natürlich auch dazu aufgefordert, Transaktionen aufzunehmen. Hierbei kann er sich allerdings aussuchen, welche er von den aktuell Anstehenden nimmt. Natürlich wird sich der Miner diese nehmen, wo die meiste Fee anfällt. Dies ist der Grund, warum eine höhere Fee die Wahrscheinlichkeit erhöht, in die Blockchain aufgenommen zu werden. Des Weiteren kann es auch passieren, dass eine Transaktion vom Netzwerk als gültig angenommen wird und der transferierte Betrag auf den neuen Konten in einer weiteren Transaktion verwendet wird. Dabei ist es Möglich, dass die neuer Transaktion eine höhere Fee enthält und dies vor der Alten in die Blockchain gespeichert wird. Dies bedeutet wiederum, dass eine Transaktion B „jünger“ sein kann als Transaktion A jedoch zeitlich nach A passiert ist.
Nonce
Dieser Wert ist jener, der sagt, mit welcher Lösung der aktuelle Block gemined wurde. Ein neuer Block wird ja bekanntlich durch die Lösung eines mathematischen Problems generiert. In diesem Feld ist die Lösung gespeichert.
Number of Transactions
Dieser Wert sollte selbsterklärend sein und definiert lediglich die Anzahl an Transaktionen in diesen Block.
Transaktionshash (nicht in der Blockchain enhalten)
Wie oben ersichtlich ist, ist der eigentliche Transaktionshash nicht in der Blockchain vorhanden. Das Grund hierfür liegt darin, dass dieser berechnet werden kann und zwar durch das Hashen der gesamten Blockdaten.
Transaktion
Folgend gehen wir auf die Felder des Datentyps der Transaktion ein.
Version
Hier wird festgehalten, welcher Bitcoin Transaktions Version diese Transaktion angehört. Waren es bisher nur Version 1 Transaktionen, ist es seit April 2017 möglich, Version 2 Transaktionen zu erstellen. Technisch bedeutet es, dass BIP68 (https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki) vom Client unterstützt wurde (Anm.: Im Skript wird OP_CHECKSEQUENCEVERIFY unterstützt).
Input-Count
Dieser Wert ist selbsterklärend, er beinhaltet lediglich die Anzahl an Inputs in der Transaktion.
Output-Count
Dieser Wert ist selbsterklärend, er beinhaltet lediglich die Anzahl an Outputs in der Transaktion.
Locktime
Dieses Feld gibt an, ab welcher Blockheight die Transaktion in die Blockchain aufgenommen hätte werden könnte. Hier ein Beispiel (https://blockchain.info/tx/a3188741187b00d8a80965fc04408e3b2686a57084d1…) bei dem die Lock Time den Block 413784 anzeigt, die Transaktion aber erst im nächsten Block in die Blockchain gespeichert wurde. Dieser Offset von 1 Block wurde in der Blockchain festgehalten.
Output
Im Folgenden wird beschrieben, wie ein Output abgespeichert wird.
Value
Die Anzahl an Bitcoin, die auf das Konto überwiesen werden. Abgespeichert wird meist eine sehr größe Zahl, wie z.B. 50.000.000.000. Dies ist Satoshi, was nichts anderes ist wie 100.000.000stel Bitcoin. D.h. die vorige Zahl sind 50 Bitcoin.
Script Length
Hier wird abgespeichert, wie lange das Script ist, welches in diesem Output vorhanden ist.
Script Signature
Dieses Feld speichert das Output Script. Dieses identifiziert den Public Key des Empfängers. Die Entwickler von Bitcoin haben sich hierfür ein interessantes System ausgedacht. Sieht man sich ein Beispiel eines Scripts an: 4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac stellt man fest, dass hier zur Zahlen und Buchstaben vorhanden sind. In Wirklichkeit steckt dahinter ein Programm, welches duch die Bitcoin Script Programmiersprache definiert ist (genaue Spezifikation siehe https://en.bitcoin.it/wiki/Script). Dieses Programm wird ausgeführt und bestimmte Daten in einen Speicher geschrieben. Darin wird auch definiert, was mit diesen Daten passiert. Nimmt man z.B. die letzten 2 Zeichen des obigen Scripts „AC“ ist damit die Operation (OP-Code) OP_CHECKSIG definiert, welche folgendes durchführt: „The entire transaction's outputs, inputs, and script (from the most recently-executed OP_CODESEPARATOR to the end) are hashed. The signature used by OP_CHECKSIG must be a valid signature for this hash and public key. If it is, 1 is returned, 0 otherwise.“ Wie man hier sieht, werden die Daten im Speicher gehasht. Dieser Hash kann dann Base58 encodiert werden und man erhält die Bitcoin Adresse. D.h. aber das die eigentliche Bitcoin Adresse NICHT in der Blockchain abgespeichert wird, sondern erst berechnet werden muss.
Input
Hier wird beschrieben wie die Inputs aufgebaut sind bzw. wie Bitcoin mit dem Double Spending Problem (siehe https://en.wikipedia.org/wiki/Double-spending) um geht.
Previous Hash
Ein Input einer Transaktion beinhaltet keine Anzahl an Bitcoin die von diesem Konto wegüberwiesen werden. Der Grund hierfür liegt darin, dass das Netzwerk dezentral veranlagt ist und es keine zentrale Stelle gibt, die überprüft ob „1 Bitcoin verwendet wird“ oder nicht oder „der Kontostand gemanaged“ wird. D.h. es muss gewährleistet sein, dass aus den vorhanden Bitcoin nicht plötzlich mehr Bitcoin werden. Dieses Problem gibt es in der Realwirtschaft bzw. dem e-Banking bereits und nennt sich Double-Spending Problem. In diesem Feld „Previous Hash“ wird also KEINE Bitcoin Adresse oder kein Wert, der transferiert wird, abgespeichert, sondern eine Referenz zu einer anderen Transaktion, von welcher ein Output nun als Input „verwendet“ wird. Welche Output dies ist, wird in dem weiteren Feld „OutID“ definiert.
Script Length
Auch ein Input hat ein Script und die Länge wird hier abgespeichert.
Script Signature
Hier wird das Bitcoin Script für einen Input abgespeichert. Beim Output Script wurde bereits erwähnt, dass es sich hierbei um den Public Key des Emfpängers handelt und das Netzwerk somit weiß, an wen die Bitcoin überwiesen werden. Das Input Script hat den Sinn, dass das Netzwerk überprüfen kann, ob der Sender die Bitcoin die er überweisen will auch besitzt. D.h. dieses Script muss eine Art „Beweis“ beinhalten, dass der Sender, dessen Public Key allgemein bekannt ist, auch den Private Key zum Public Key besitzt.
OutID
Wie bereits im Feld Previous Hash erwähnt, wird bei einem Input lediglich ein Output einer anderen Transaktion referenziert. Welcher Output das ist, wird mit diesem OutID Feld definiert. Dieser ist aber 0-basierend. D.h. der Wert „0“ würde auf das erste Output-Element in der Transaktion, referenziert durch „Previous Hash“, zeigen.
SeqNo
Diese Feld wird im aktuellen Netzwerk nicht verwendet. Es ist dafür gedacht, um im Zukunft Transaktionen in das Netzwerk zu senden, welche aber noch nicht durchgeführt werden und auf eine „Vervollständigung“ warten.
Fallbeispiel
Nun möchten wir Beispieldaten von 2 Transaktionen geben, damit die obigen Datentypen auch veranschaulicht werden.
Transaktion 1
Hier werden die Daten vom einem Block (Hash 0000000000038ef9c1acf53e61e6058cef69180f81a1b29428cbe3ec1e07eca0) veranschaulicht:
Magic-Number
f9beb4d9
Blocksize
1853
Previous Hash
10da45d0596cd488248c53b5af6d69961b5876603b4f89f20a20040000000000
Merkle Hash
c02412cb6c79deae82c13ee8f6734020f60f2ac14088ef5c2b4d0f3f0db1cf59
Creation Time
1293994126
Nonce
3737486936
Number of Transactions
4
Hier wird nun die 1. Transaktion (728758890cc7e0c64bb0f2df23f056e469c4967258c1374723fba46d8c4910d4), welche im ersten Block ist dargestellt:
Version
1
Input Count
1
Output Count
2
Locktime
0
Und nun der Input der Transaktion:
Previous Hash
279336ef5441c498b43b93ba5ce50bafed186c2928ed20e7ae900dcadc8b03cc
Script Length
140
Script Signature
493046022100ad09d2497baafc1745d11741c83077fd010781590b1813467e92557e03152a80022100f66c5ce41d1d32ade42ea85638f3b68b9934463fa78456c163b61a9dcfd44a9201410491c32b4413e08b660258442dfc1c82c83bcf8f6afd8773195bfb297e18f7180e8b9e2c33e4a3b869f59d6047bd93994010f6a6988d5b918b5ba6e43adeb852ca
OutID
00000000
SeqNo
ffffffff
Und hier werden die Outputs der Transaktion dargestellt.
Output 1:
Value
5000000
Script Length
25
Script Signature
76a914cbb5a201be8de01ce17add3efca6172a65eefe0c88ac
Output 2:
Value
338000000000
Script Length
25
Script Signature
76a914780bf5ab9bb69945a92af845d4d5df16f7e9567688ac
Transaktion 2
Hier wird nun eine weitere Transaktion (4396af309db0bf812fdb463b5c06952de9c91e81734cdb2f8cde809c6e0736ec) angeführt, welche einen Output der obigen Transaktion verwendet.
Block der Transaktion:
Magic-Number
f9beb4d9
Blocksize
1731
Previous Hash
fa2fa55bc27d75b05ff4ac1b3ee73184476896abc22ca421ef81020000000000
Merkle Hash
5d3eb7050478c62c25ed1d785a4b205dabb273fb0eff0ebebb01a996d274c975
Creation Time
1293997193
Nonce
518201913
Number of Transactions
5
Transaktion:
Version
1
Input Count
1
Output Count
2
Locktime
0
Und nun der Input der Transaktion:
Previous Hash
728758890cc7e0c64bb0f2df23f056e469c4967258c1374723fba46d8c4910d4
Script Length
139
Script Signature
4830450221008d119a90d7fad1911a1ee83cc3314b3e4dc59c6cf0274c535481785c0a79d71802206dc2f11e00dcd42dbff4a6f47875257645851db3e579e6348c95bbda30fb9aaa01410444dd507d47542c7339a73731422490cca3b07aea65c22cc1c57efd3959f0ffc20f45bcf157f322b3e632a6f0783530fa5dd1e01a1b8fbd0b9b71a0d253f35ec0
OutID
00000001
SeqNo
ffffffff
In den obigen Daten sieht man sehr gut, dass der Previoush Hash jener ist, der die Transaktion 1, die hier in diesem Artikel angeführt ist, refereziert. Um genau zu sein wird der zweite Output herangezogen!
Hier sind auch schon die Outputs der Transaktion gelistet.
Output 1:
Value
33795000000
Script Length
25
Script Signature
76a914fbc04efbc08955d14da3aea57714edeb290a885088ac
Output 2:
Value
5000000
Script Length
25
Script Signature
76a914674300eb2c15b7224a1af227eb9f7c2b904b589f88ac
Conclusio
Durch obiges Beispiel hat man sehr gut gesehen, wie die Architektur der Datenstrukturen hinter Bitcoin aufgebaut sind. Des Weiteren bekommt man ein Gefühl für so manche nicht ganz klar ersichtlichen Gegebenheiten, wie die Auswahl der Beträge im Bitcoin Netzwerk bei einer Überweisung bzw. wie das Double Spending Problem gelöst wurde, nämlich durch Verweise bei den Inputs.