Beispiel für Daten, die im Merkle-Baum für eine Transaktion gehasht werden

Also lese ich dies (ausgezeichnete Ressource) im Bitcoin-Merkle-Baum für eine Transaktion.

Der Merkle-Baum ist von unten nach oben aufgebaut. Im folgenden Beispiel beginnen wir mit vier Transaktionen, A, B, C und D, die die Blätter des Merkle-Baums bilden, wie in Berechnen der Knoten in einem Merkle-Baum gezeigt. Die Transaktionen werden nicht im Merkle-Baum gespeichert; Stattdessen werden ihre Daten gehasht und der resultierende Hash wird in jedem Blattknoten als HA, HB, HC und HD gespeichert:

HA = SHA256(SHA256(Transaction A))

Aufeinanderfolgende Paare von Blattknoten werden dann in einem übergeordneten Knoten zusammengefasst, indem die beiden Hashes verkettet und zusammengehasht werden. Um beispielsweise den Elternknoten HAB zu konstruieren, werden die zwei 32-Byte-Hashes der Kinder verkettet, um eine 64-Byte-Zeichenfolge zu erzeugen. Diese Zeichenfolge wird dann doppelt gehasht, um den Hash des übergeordneten Knotens zu erzeugen:

HAB = SHA256(SHA256(HA + HB))

Der Prozess wird fortgesetzt, bis es nur noch einen Knoten an der Spitze gibt, den Knoten, der als Merkle-Wurzel bekannt ist. Dieser 32-Byte-Hash wird im Block-Header gespeichert und fasst alle Daten in allen vier Transaktionen zusammen.

Das macht Sinn, aber ich habe ein paar Fragen. Erstens, wie die Transaktion wie Transaktion A gehasht wird und was in der Praxis in einer Transaktion enthalten ist. Zum Beispiel, wenn es sich um ein stringifiziertes JSON-Objekt oder ein byteArray in JavaScript handelt oder wenn Daten in einem bestimmten Format vorliegen müssen usw. Ich würde zum Beispiel gerne sehen, wie ein Datensatz gehasht würde, so oder so ähnlich { a: 'foo', b: 'bar', c: 123, ... }.

Zweitens, wenn hier die Idee des Patricia Merkle Tree (oder vielleicht sogar Merkle DAG, den ich irgendwo gesehen habe) ins Spiel kommt, um die Menge an Zeug zu verkürzen, die Sie im Speicher speichern müssen, da sich die Hashes nicht vollständig überlappen und hätte daher viele leere Baumknoten.

Schließlich, wie ein Beispielsatz von Transaktionen in einem einzelnen Block aussehen würde, in dem sie sagen, dass sie im Durchschnitt 1900 Transaktionen haben. Dies wäre ein ziemlich tiefer Merkle-Baum, und ich würde gerne sehen, wie die Transaktionen tatsächlich heißen, und weitere Informationen zu ihrer Datenstruktur. Zum Beispiel, wenn sie bis hinunter zu den ISA-Operationen (Instruction Set Architecture) gehen, oder wenn sie auf viel höherem Niveau sind. Das ist im Grunde alles, was ich wissen möchte. Das habe ich in dem oben verlinkten Buch noch nicht gesehen, werde aber mal genauer hinschauen .

Antworten (2)

Die Blätter im Merkle-Baum sind die Transaktions-IDs ( txid) der Transaktion, die wiederum der doppelte SHA256 der vollständig serialisierten Transaktion in ihrer binären (Little-Endian) Form ist, die das gleiche Format hat, in dem sie über das Netzwerk empfangen wird .

Ch06 desselben Buches beschreibt die Serialisierung der txinund txout-Strukturen. Ich bin mir nicht sicher, warum das Transaktionsformat selbst im Buch zu fehlen scheint. Eine Transaktion ist eine Serialisierung der Abfolge von txinund txoutStrukturen mit einer zusätzlichen Version und einer Sperrzeit.

tx {
    version : int32
    txin_count : VarInt
    txins : txin[]
    txout_count : VarInt
    txouts : txout[]
    nLockTime : uint32
}

Das VarIntist das gleiche, das im Buch verwendet wird. Im Bitcoin-Core-Quellcode heißt es CompactSize.

Es gibt ein alternatives Format für Witness-Transaktionen, die von Clients verwendet werden, die das Format unterstützen, das einen Trick verwendet, der txin_countnormalerweise verwendet werden muss >= 1, da alle Transaktionen eine vorhandene Eingabe ausgeben müssen (außer Coinbase tx). Wenn also das txin_countoben erwartete Byte den Wert hat 0, zeigt dies das Vorhandensein einer Witness-Transaktion an, bei der es einige zusätzliche Felder gibt.

witness_tx {
    version : int32
    witness_marker : byte //always 0
    witness_flag : byte
    txin_count : VarInt
    txins : txin[]
    txout_count : VarInt
    txouts : txout[]
    witnesses : witness[] //list always has the same length of txin_count
    nLockTime : uint32
}

Selbst wenn eine Transaktion eine Witness-Transaktion ist, txwird das Format verwendet, um das txidfür diese Transaktion zu generieren, die bei der Berechnung der Merkle-Wurzel verwendet wird. Damit soll sichergestellt werden, dass Witness-Transaktionen abwärtskompatibel mit dem älteren Transaktionsformat sind. Ein Client, der SegWit unterstützt, der mit einem Client kommuniziert, der es nicht unterstützt, sendet das txFormat an seinen Peer für Witness-Transaktionen und nicht das witness_txFormat.

enthalten Nicht-Segwit-TXIDs nicht den Zeugen [] als [0x00] und verwenden jetzt dasselbe Format? Tolle Erklärung.
Nein. Das 0x00-Flag wird dort verwendet, wo das txin_countnormalerweise im Legacy-TX-Format erscheint, und zeigt einfach an, dass die Transaktion eine Witness-Transaktion ist, sodass die verbleibenden Bytes mit dem zweiten Witness-Format geparst werden.

1) Transaktionen enthalten keine Merkle-Hashes. Die Hashes der Pre-SegWit-Transaktionen werden berechnet, indem die Transaktion serialisiert wird (Sie können nach „dem Hex-Format“ suchen) und dann das Byte-Array gehasht wird. Nach SegWit werden Signaturen von Transaktions-Hashes ausgeschlossen.

2) (Ich kann nicht verstehen, wonach du fragst)

3) 1900 Transaktionen sind nicht so tief. Die Höhe kann mit berechnet werden ceil(log_2(number_of_tx))+1. Stecken Sie 1900 ein, und die Höhe beträgt 12. Wenn Sie erfahren möchten, wie Merkle-Bäume für ISA verwendet werden können, würde ich vorschlagen, nach MAST zu suchen . Es ermöglicht das Ausblenden der nicht ausgeführten Teile des Skripts.