Was ist die Merkle-Wurzel?

Der Bitcoin-Wiki - Vokabularartikel erklärt, warum die Merkle-Wurzel existiert:

Jeder Transaktion ist ein Hash zugeordnet. In einem Block werden alle Transaktions-Hashes im Block selbst gehasht (manchmal mehrmals – der genaue Prozess ist komplex), und das Ergebnis ist die Merkle-Wurzel. Mit anderen Worten, die Merkle-Root ist der Hash aller Hashes aller Transaktionen im Block. Die Merkle-Wurzel ist im Block-Header enthalten. Mit diesem Schema ist es möglich, sicher zu verifizieren, dass eine Transaktion vom Netzwerk akzeptiert wurde (und die Anzahl der Bestätigungen zu erhalten), indem nur die winzigen Blockheader und der Merkle-Baum heruntergeladen werden – das Herunterladen der gesamten Blockkette ist nicht erforderlich. Diese Funktion wird derzeit in Bitcoin nicht verwendet, wird aber in Zukunft verwendet.

Wie können Sie überprüfen, ob eine Transaktion nur mit Merkle-Roots verifiziert wurde? Wie funktioniert dieser Mechanismus?

Während ich die Definition von Merkle Tree und Root sofort verstehen konnte, kämpfte ich, wie viele Posts in diesem Thread, damit, den größeren Kontext und ihre Verwendung herauszufinden, bis ich ein bisschen mehr recherchierte. Ich versuche hier ein Szenario zu erklären .

Antworten (6)

Die Idee (so wie ich es verstehe) ist, dass der Merkle-Baum es Ihnen ermöglicht, Transaktionen nach Bedarf zu überprüfen und nicht den Hauptteil jeder Transaktion in den Block-Header aufzunehmen, während er dennoch eine Möglichkeit bietet, die gesamte Blockchain zu überprüfen (und damit einen Arbeitsnachweis). ) bei jeder Transaktion.

Um dies zu verstehen, müssen Sie zuerst das Konzept eines Baums verstehen. Betrachten Sie einen 8-Transaktionsblock. Stellen Sie sich jede dieser 8 Transaktionen an der Basis einer Pyramide vor: Diese werden Blätter genannt. Legen Sie vier "Zweige" auf die zweite Ebene der Pyramide und ziehen Sie zwei Linien von jedem von ihnen zu den Blättern, sodass an jedem Zweig zwei Blätter befestigt sind. Verbinden Sie nun diese vier Zweige mit zwei Zweigen auf Pyramidenebene 3 und bis zu einem Zweig (der als Wurzel des Baums bezeichnet wird) auf der Spitze der Pyramide. (Unser Baum wächst in diesem Beispiel auf dem Kopf.)

Jetzt können wir beginnen, den Hash-Prozess zu verstehen. Hashen Sie die Hashes der „Blätter“ und schließen Sie diese als Teil der Zweige der 2. Ebene ein, an denen diese Blätter angehängt sind (diese werden als untergeordnete Knoten und übergeordnete Knoten bezeichnet). Hashen Sie nun die Hashes dieser Hashes und schließen Sie diese als Teil der Zweige der dritten Ebene ein. Usw. (Und wenn Sie mehr als 8 Transaktionen hatten, brauchen Sie nur mehr Ebenen in der Pyramide.)

Jetzt haben Sie also einen Root-Knoten, der effektiv über einen Hash verfügt, der die Integrität aller Transaktionen überprüft. Wenn eine Transaktion hinzugefügt/entfernt oder geändert wird, ändert sie den Hash ihres Elternteils. Dadurch wird der Hash des übergeordneten Knotens usw. geändert, was dazu führt, dass sich auch der Hash des Wurzelknotens (der Merkle-Wurzel) ändert.

Wie hilft uns das also, möglicherweise nicht die gesamte Blockchain haben zu müssen? Weil wir die Transaktionen nach Bedarf verifizieren könnten. Wenn wir eine Transaktion haben, die angeblich aus Block #234133 stammt, können wir die Transaktionen für diesen Block abrufen, den Merkle-Baum überprüfen und wissen, dass die Transaktion gültig ist. Wir können das tun, ohne unbedingt alle Transaktionen von #234132 oder #234134 zu kennen, weil wir wissen, dass die Blöcke manipulationssicher sind.

Noch besser, wenn wir wissen, wo es sich im Merkle-Baum befindet, und wir die Hashes der Zweige kennen, brauchen wir nicht einmal alle Transaktionen aus #234132. (In diesem Block waren 868.) Wir beginnen nur mit unserer Transaktion und ihrem Geschwister (falls vorhanden) und berechnen den Hash dieser beiden und überprüfen, ob er mit dem erwarteten Wert übereinstimmt. Daraus können wir nach dem Geschwisterzweig davon fragen und den Hash davon berechnen und verifizieren. Und fahren Sie mit diesem Prozess fort, den Baum hinauf. Was nur zehn Überprüfungen für 868 Transaktionen erfordert. (Das ist eines der großartigen Dinge an Bäumen, sie können viele Werte mit nur einer relativ kleinen Anzahl von Schichten enthalten.)

Woher wissen wir, dass die Quelle dieser Daten uns nicht über die Hash-Werte belügt? Da eine Hash-Funktion unidirektional ist, gibt es keine Möglichkeit, dass eine betrügerische Partei einen Wert erraten könnte, der mit unserem vorletzten Wert gehasht würde, um die Merkle-Wurzel zu erstellen. (Was wir aus unserer verifizierten Blockchain kennen.) Diese Argumentation gilt weiter unten im Baum: Es gibt keine Möglichkeit, einen gefälschten Wert zu erstellen, der unseren erwarteten Wert ergibt. Eine andere Möglichkeit, darüber nachzudenken, ist, dass selbst eine einzige Änderung einer Transaktion an der Basis des Baums zu einer wellenförmigen Änderung aller Hash-Werte von Knoten in seinem Zweig bis hinauf zum Hash-Wert der Wurzel führen würde.

Kurz gesagt, der Merkle-Baum erstellt einen einzigen Wert, der die Integrität aller Transaktionen unter ihm beweist. Satoshi hätte einfach den Hash einer großen Liste aller Transaktionen in den Bitcoin-Header aufnehmen können. Aber wenn er das getan hätte, hätten Sie die gesamte Liste der Transaktionen hashen müssen, um ihre Integrität zu überprüfen. Selbst wenn es eine extrem große Anzahl von Transaktionen gibt, müssen Sie auf diese Weise nur log(O) arbeiten (und die Anzahl der Hashes, die Sie anfordern/herunterladen müssen), um die Integrität zu überprüfen.

[Wie immer können Sie dies gerne bearbeiten. Dies ist in erster Linie nur eine Schlussfolgerung meinerseits aus dem Blick auf die Spezifikation.]

Ein Block-Header enthält nicht die Transaktions-IDs der Transaktionen im Block, oder? Im Grunde funktioniert die Idee des letzten Teils des Zitats also nur, wenn txids in den Blockheadern enthalten sind.
Es lautet "Blockheader und Merkle-Baum". Das macht mehr Sinn. Erlaubt das ursprüngliche Protokoll das Anfordern von Merkle-Bäumen und/oder Headern, die diese enthalten?
Was ist, wenn wir die Blocknummer der Transaktion nicht kennen? Müssen wir in diesem Fall alle Blöcke in der Blockchain durchlaufen? @DavidOgren
Vielleicht ist das eine schlechte Frage, aber was ist, wenn ich zwei bestimmte Transaktionen mit gleichen Hashes mit Geburtstagsangriff finde und eine dieser Transaktionen durchführe und später behaupte, dass ich die andere durchgeführt habe? Wie kann ich mich irren?
Es ist zu lang, Ihre Frage hier zu beantworten @tgwtdt. Kurz gesagt, Sie können keinen Geburtstagsangriff ausführen, da Sie keine willkürliche Kontrolle über Eingaben haben. Zweitens ist selbst ein Geburtstagsangriff auf SHA-256 nicht realistisch möglich. Aber im Allgemeinen ja, wenn Sie einen Weg finden, SHA-256 auszunutzen, können Sie alle möglichen unangenehmen Dinge innerhalb von Bitcoin tun: Die Schwierigkeit, den Hash-Algorithmus umzukehren, ist ein Grundprinzip. Andererseits ist die Sicherheit von Hash-Algorithmen ein sehr gut erforschtes Gebiet.

„Abbildung 7-2. Berechnung der Knoten in einem Merkle-Baum“ aus Mastering Bitcoin zeigt die Merkle-Wurzel (H ABCD ) einer Liste von vier Transaktionen: Tx A, Tx B, Tx C und Tx D:Abbildung 7-2.  Berechnen der Knoten in einem Merkle-Baum


Um zu verifizieren, dass eine Transaktion – zum Beispiel die mit Hash H K – eine gültige Transaktion ist (dh Teil einer Liste von in diesem Beispiel 16 Transaktionen mit Hashes H A , H B , … H P ), braucht man nur führt höchstens 2*log 2 (N) < N Hashes aus, die hier im Merkle-Pfad gezeigt werden:

Abbildung 7-5.  Ein Merkle-Pfad, der verwendet wird, um die Einbeziehung eines Datenelements zu beweisen

Wenn H K zur richtigen Merkle-Wurzel führt, dann war T K in der Transaktionsliste.

Und der Merkle-Pfad , der benötigt wird, um zu überprüfen, ob H k mit der Merkle-Wurzel übereinstimmt, enthält im obigen Beispiel nur 4 Hashes. Der Merkle-Pfad nimmt viel weniger Platz ein als das Speichern aller Transaktionen in einem Block. (Im obigen Beispiel: 4 Hashes nehmen viel weniger Platz ein als 16.) Aus diesem Grund ist SPV leichter.

In diesem Fall ist N = 16 und 2*log 2 (16) = 5,55 … ist tatsächlich kleiner als 16.

Um eine Transaktion zu überprüfen: Woher kennen wir die genaue Position von Hk auf dem Merkle-Baum? @Geremia
@Avatar Um Merkle-Pfade von Grund auf neu zu erstellen, müssen alle Transaktionen bekannt sein. Außerdem wäre es noch schwieriger, einen gefälschten Merkle-Pfad zu schmieden, der einer bestimmten Merkle-Wurzel entspricht, als SHA256 zu knacken.
Wenn wir zum Beispiel von root folgen: right left right left, gelangen wir zu Hk, was wir überprüfen möchten. Aber wie konnten wir wissen, dass wir diesem Weg folgen sollten? @Geremia
@Avator Die Überprüfung eines Merkle-Pfades erfolgt vom Blattknoten bis zur Merkle-Wurzel.
Habe es jetzt viel klarer. Aber noch einmal, woher sollte der Algorithmus wissen, von welchem ​​​​Blatt aus er beginnen soll? In Ihrem Beispiel gibt es 16 Blätter. Wie können wir also den Startpunkt des Hk auf den Blättern des Baums erkennen? @Geremia
@Avatar Entschuldigung, ich wollte sagen, dass man einfach in der "Liste der Transaktionen" nach der Transaktion suchen muss.
Soweit ich weiß, kennen wir den Index aller Transaktionen, an welchem ​​Blatt sie sich befinden. @Geremia
Der Diskussionslink scheint tot zu sein ... habe die Erklärung immer noch nicht gefunden: Wenn sie in der "Liste der Transaktionen" gesucht wird, wenn die Position gegründet wurde, bedeutet dies nicht, dass diese Transaktion eine gültige Transaktion ist?
@limboy Ein SPV-Server sendet den Merkle-Pfad einer Transaktion an den Lightweight-Client. dies reicht dem Lightweight-Client aus, um zu überprüfen, ob die Transaktion gültig ist, ohne dass der Lightweight-Client eine Liste aller Transaktionen haben muss.
Das 2. Diagramm ist das einzige, was Sie brauchen, um alles zu verstehen. Der „grüne“ Hash H_K ist der /claim/, der dem ZAHLUNGSEMPFÄNGER gegeben wird (der auch die Merkle-Wurzel hat). Der VERIFIER (Full Node) sendet die "blauen" Hashes als /proof/, da sie verwendet werden können, um alle "blau gestrichelten" Hashes bis hin zur Merkle-Wurzel zu berechnen. Wenn die berechnete Merkle-Wurzel mit der bekannten Merkle-Wurzel übereinstimmt, ist H_K im Block. Offensichtlich sind die „blauen“ Hashes eine kleine Teilmenge ALLER Hashes, dh 2*log_2(N) ist kleiner als die gesamte Menge N für N > 4. Stellen Sie es selbst auf desmos.com grafisch dar, mit y=2log(N)/log(2)vs y=N.

Es ist nicht wahr, dass Sie nur die Merkle-Wurzel verwenden (das sagt der Artikel auch nicht). Stattdessen verwenden Sie nur die Teile des Merkle -Baums , die sich auf Ihre Transaktion beziehen. Dazu gehört die Wurzel.

Dies kann eine gute Einführung sein. Ripple verwendet möglicherweise den Merkle-Baum, aber ich bin mir nicht sicher: http://en.m.wikipedia.org/wiki/Hash_tree Überprüfen Sie auch dies: https://stackoverflow.com/questions/5486304/explain-merkle-trees-for -Use-in-eventual-consistency

Die Merkle Root ist, wie ich es verstehe, im Grunde ein Hash aus vielen Hashes (gutes Beispiel hier ) - um eine Merkle Root zu erstellen, müssen Sie damit beginnen, einen doppelten SHA-256-Hash der Byteströme der Transaktionen im Block zu nehmen. Was diese Daten sind (die Bytestreams), wie sie aussehen und woher sie kommen, bleibt mir jedoch ein Rätsel.

SEI VORSICHTIG! Die Merkle-Wurzel ist wichtig für den Bergbau. Da die Merkle-Root der Hash-Wert ALLER Transaktions-Hashes aus dem Block ist, wird der Wert der Merkle-Root im Voraus genommen, wenn Miner ihre Arbeit erledigen. Siehe: https://en.bitcoin.it/wiki/Block_hashing_algorithm . Vorheriger Hash:

81cd02ab7e569e8bcd9317e2fe99f2de44d49ab2b8851ba4a308000000000000

Hier ein Auszug des dortigen Algorithmus:

>>> import hashlib
>>> header_hex = ("01000000" +
 "81cd02ab7e569e8bcd9317e2fe99f2de44d49ab2b8851ba4a308000000000000" +
 "e320b6c2fffc8d750423db8b1eb942ae710e951ed797f7affc8892b0f1fc122b" +
 "c7f5d74d" +
 "f2b9441a" +
 "42a14695")
>>> header_bin = header_hex.decode('hex')
>>> hash = hashlib.sha256(hashlib.sha256(header_bin).digest()).digest()
>>> hash.encode('hex_codec')
'1dbd981fe6985776b644b173a4d0385ddc1aa2a829688d1e0000000000000000'
>>> hash[::-1].encode('hex_codec')
'00000000000000001e8d6829a8a21adc5d38d0a473b144b6765798e61f98bd1d'

Zunächst einmal sind alle Werte hier in Little-Endian-Notation, Sie müssen also Byte für Byte von rechts nach links bereitstellen (denken Sie daran, dass ein Byte ZWEI Zeichen sind). Der erste Wert ist also der vorherige Block-Hash, dann THE MERKLE ROOT, dann die Erstellungszeit und dann die Bits. Um die Werte zu vergleichen, schaut einfach auf: https://blockexplorer.com/block/00000000000000001e8d6829a8a21adc5d38d0a473b144b6765798e61f98bd1d

Fazit: Die Merkle-Wurzel wird implizit von der Bitcoin-Blockchain verwendet! Es spielt eine wichtige Rolle, wenn es ums Mining geht!

Der Wert im Wiki ist korrekt, da jeder dies überprüfen kann, indem er sich den Hash des Headers des vorherigen Blocks ansieht oder Ihren Code ausführt, der nicht die von Ihnen behaupteten Werte erzeugt.
Ah ja, ich habe die Bytes falsch gelesen.