Wie berechne ich die Merkle-Wurzel für den Genesis-Block?

Ich wollte der Community helfen und eine reine C-Anwendung unabhängig vom Referenzclient erstellen, die mit einem Zeitstempel und einem öffentlichen Schlüssel eine Merkle-Root für die Erstellung eines Genesis-Blocks erzeugt.

Meine Kenntnisse in C++ sind sehr gering bis gar nicht vorhanden. Nach dem Betrachten des Quellcodes ist dies der relevante Code

    const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
    CTransaction txNew;
    txNew.vin.resize(1);
    txNew.vout.resize(1);
    txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
    txNew.vout[0].nValue = 50 * COIN;
    txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;

Was diesen Merkle-Hash produziert

 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b

Ich bin mir nicht sicher, ob CScript() << 486604799 << CBigNum(4) <<... all dies bitshifting oder es einfach in .scriptSig schreibt. Und ich gehe davon aus, dass CScript() der Konstruktor ist, der .scriptSig initialisiert.

Als ich mich in den Quellcode vertiefte und den Aufrufen von BuildMerkleTree folgte, landete ich darin

template<typename T>
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int     nVersion=PROTOCOL_VERSION)
{
    CHashWriter ss(nType, nVersion);
    ss << obj;
    return ss.GetHash();
}

Also fing ich an, ChashWriter zu folgen, und landete bei

template<typename T>
CHashWriter& operator<<(const T& obj) {
    // Serialize to this stream
    ::Serialize(*this, obj, nType, nVersion);
    return (*this);
}

Und ich habe mich dort verlaufen. Aber das, was mir am nächsten kam, war doppeltes SHA256-ing

04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73 5000000000 04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f OP_CHECKSIG after supposedly converting to a byte array.

Und ich habe mich offensichtlich geirrt, da das Ergebnis nicht korrekt war.

Anscheinend verwendet Bitcoin etwas, das als Serialisierung bekannt ist, um die Variablen des Objekts zu serialisieren, vielleicht zu verketten, aber leider konnte ich aufgrund meiner Unerfahrenheit mit C++ nicht verstehen, welche Variablen in welcher Reihenfolge und so weiter. Im Grunde war der Bitcoin-Quellcode komplexer, als ich es mir vorgestellt hatte.

Meine Frage ist also, wie ich einen Merkle-Hash für einen Genesis-Block erzeugen kann, ohne Serialisierung und in C zu verwenden?

Antworten (1)

Anstatt den Quellcode zu betrachten, werfen Sie einen Blick auf die entsprechende Wiki-Seite .

Wie der Blockexplorer zeigen wird, ist die Merkle-Wurzel des Genesis-Blocks gleich dem Hash der darin enthaltenen Transaktion . Dies liegt daran, dass das Erstellen eines Hash-Baums einer Transaktion einfach zu dieser einen Transaktion führt und der Hash dieses Baums derselbe ist wie der Hash dieser einen Transaktion.

Wenn Sie sich mit mehr Transaktionen befassen, legen Sie sie einfach in einen Baum und hashen Sie sie von unten nach oben, wie auf der Wiki-Seite erwähnt.

Aber ich verstehe nicht, in welcher Reihenfolge sie angeordnet sind. Wie die Reihenfolge der Verkettung und welche Daten genau. Da im Quellcode die Serialisierung von Objekten verwendet wird und ich mit diesem Konzept nicht vertraut bin, weiß ich nicht, in welcher Reihenfolge, welche Variablen usw.
Die unterste Ebene des Baums sollte nach Hash sortiert werden, aufsteigend von links nach rechts. Der Rest ist (hoffentlich) selbstverständlich. Vergiss die Serialisierung, das ist völlig irrelevant.
Da ich nicht vorhabe, mit etwas anderem als einem Genesis-Block zu arbeiten, glaube ich, dass ich dafür keine Bäume brauche.
Richtig. Wenn Sie nur mit dem Genesis-Block arbeiten, nehmen Sie einfach den SHA256 (SHA256 (tx)).
Nun, während ich daran arbeite, eine Struktur zu konstruieren, die die Transaktion des Genesis-Blocks enthält, wie würde ich später alles mit SHA256 versehen? Die Serialisierung in Bitcoin in C++ wird durchgeführt, um einige Variablen unabhängig von ihrem Datentyp in eine Folge von Bytes zu konvertieren, in C muss ich noch einen Standardweg dafür finden.
Ich würde sagen, werfen Sie einen Blick auf mein eigenes Bitcoin-Relay , das zufällig in C geschrieben ist. Der Hash wird von der gesamten Transaktion genommen, wie sie über das Netzwerk über den txBefehl gesendet wird. Der txBefehl ist hier beschrieben . Dort ist eine Beispieltransaktion enthalten.