¿Cómo calculo la raíz de Merkle para el bloque de génesis?

Quería ayudar a la comunidad y crear una aplicación C pura independiente del cliente de referencia, que, dada una marca de tiempo y una clave pública, produzca una raíz Merkle para la creación de un bloque de génesis.

Mi conocimiento de C++ es muy poco o nada. Después de mirar el código fuente, este es el código relevante

    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;

Que produce este merkle hash

 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b

No estoy seguro de si CScript() << 486604799 << CBigNum(4) <<... está cambiando todo esto, o simplemente escribiéndolo en .scriptSig. Y voy a suponer que CScript() es el constructor que inicializa .scriptSig.

Mientras profundizaba en el código fuente y siguiendo las llamadas de BuildMerkleTree, terminé en

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();
}

Así que comencé a seguir a ChashWriter y terminé en

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

Y me perdí allí. Pero lo más cerca que estuve fue duplicar SHA256 en esto

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

Y obviamente me equivoqué al respecto, ya que el resultado no fue correcto.

Aparentemente, Bitcoin usa algo conocido como Serialización para serializar las variables del objeto, tal vez concatenarlas, pero desafortunadamente debido a mi inexperiencia con C++ no pude entender qué variables, en qué orden, etc. Básicamente, el código fuente de Bitcoin era más complejo de lo que había imaginado.

Entonces, mi pregunta es cómo puedo producir un hash Merkle para un bloque de génesis, sin usar serialización y en C.

Respuestas (1)

En lugar de mirar el código fuente, eche un vistazo a la página wiki correspondiente .

Como revelará blockexplorer , la raíz merkle del bloque de génesis es igual al hash de la transacción en él . Esto se debe a que construir un árbol hash de una transacción simplemente dará como resultado esa transacción, y el hash de ese árbol será el mismo que el hash de esa transacción.

Cuando se trate de más transacciones, simplemente colóquelas en un árbol y córtelas de abajo hacia arriba, como se menciona en la página wiki.

Pero no entiendo en qué orden están colocados. Como el orden de concatenación y de qué datos exactamente. Porque en el código fuente se utiliza la serialización de objetos, y no estoy familiarizado con ese concepto, así que no sé en qué orden, qué variables, etc.
El nivel inferior del árbol debe ordenarse por hash, ascendiendo de izquierda a derecha. El resto es (con suerte) obvio. Olvídate de la serialización, eso es completamente irrelevante.
Dado que no planeo trabajar con nada más que un bloque de génesis, creo que no necesito ningún árbol para esto.
Correcto. Cuando solo trabaje con el bloque de génesis, simplemente tome el SHA256 (SHA256 (tx)).
Bueno, mientras estoy trabajando en la construcción de una estructura para contener la transacción del bloque de génesis, ¿cómo podría después SHA256 todo? La serialización en Bitcoin en C ++ se realiza para convertir algunas variables, independientemente de su tipo de datos, en una secuencia de bytes, en C todavía tengo que encontrar una forma estándar de hacerlo.
Diría que eche un vistazo a mi propio relé de bitcoin , que está escrito en C. El hash se toma de toda la transacción tal como se envía a través de la red a través del txcomando. El txcomando se describe aquí . Allí se incluye una transacción de ejemplo.